pass2.c revision 6d96b00d57d236e2746f8245df6c8ea64abc64c1
13839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
23839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * pass2.c --- check directory structure
33839e65723771b85975f4263102dd3ceec4523cTheodore 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%
103839e65723771b85975f4263102dd3ceec4523cTheodore 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)
193839e65723771b85975f4263102dd3ceec4523cTheodore 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() */
4548e6e81362f264aee4f3945c14928efaf71a06c9Theodore Ts'o#include <string.h>
4648e6e81362f264aee4f3945c14928efaf71a06c9Theodore Ts'o
473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include "e2fsck.h"
4821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o#include "problem.h"
490926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o#include "dict.h"
503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
51aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o#ifdef NO_INLINE_FUNCS
52aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o#define _INLINE_
53aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o#else
54aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o#define _INLINE_ inline
55aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o#endif
56aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o
57ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o/* #define DX_DEBUG */
588fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o
593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Keeps track of how many times an inode is referenced.
613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
624035f40bc4550ce7520724cc837992a700794e00Theodore Ts'ostatic void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf);
633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic int check_dir_block(ext2_filsys fs,
6421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			   struct ext2_db_entry *dir_blocks_info,
6554dc7ca2869897ae8cb81a9ab9880ebff11680bcTheodore Ts'o			   void *priv_data);
661b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'ostatic int allocate_dir_block(e2fsck_t ctx,
6721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			      struct ext2_db_entry *dir_blocks_info,
6821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			      char *buf, struct problem_context *pctx);
6950e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'ostatic int update_dir_block(ext2_filsys fs,
7050e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o			    blk_t	*block_nr,
71133a56dc9da52054bc27b4c1a23f03e3405003dbTheodore Ts'o			    e2_blkcnt_t blockcnt,
724035f40bc4550ce7520724cc837992a700794e00Theodore Ts'o			    blk_t	ref_block,
734035f40bc4550ce7520724cc837992a700794e00Theodore Ts'o			    int		ref_offset,
744035f40bc4550ce7520724cc837992a700794e00Theodore Ts'o			    void	*priv_data);
758fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'ostatic void clear_htree(e2fsck_t ctx, ext2_ino_t ino);
76ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'ostatic int htree_depth(struct dx_dir_info *dx_dir,
77ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		       struct dx_dirblock_info *dx_db);
78ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'ostatic EXT2_QSORT_TYPE special_dir_block_cmp(const void *a, const void *b);
793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
8021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'ostruct check_dir_struct {
8121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	char *buf;
8221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	struct problem_context	pctx;
83f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o	int	count, max;
841b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	e2fsck_t ctx;
8521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o};
8621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o
8708b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'ovoid e2fsck_pass2(e2fsck_t ctx)
883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
89a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o	struct ext2_super_block *sb = ctx->fs->super;
90a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o	struct problem_context	pctx;
91a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o	ext2_filsys 		fs = ctx->fs;
92a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o	char			*buf;
938bf191e8660939687ef35c013066d2082cb16722Theodore Ts'o#ifdef RESOURCE_TRACK
943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct resource_track	rtrack;
958bf191e8660939687ef35c013066d2082cb16722Theodore Ts'o#endif
9621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	struct check_dir_struct cd;
978fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	struct dx_dir_info	*dx_dir;
988fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	struct dx_dirblock_info	*dx_db, *dx_parent;
99544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	int			b;
100ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	int			i, depth;
1018fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	problem_t		code;
1028fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	int			bad_dir;
1038fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o
1048bf191e8660939687ef35c013066d2082cb16722Theodore Ts'o#ifdef RESOURCE_TRACK
1056d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	init_resource_track(&rtrack, ctx->fs->io);
1068bf191e8660939687ef35c013066d2082cb16722Theodore Ts'o#endif
1073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1081b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	clear_problem_context(&cd.pctx);
1091b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o
1103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#ifdef MTRACE
1113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	mtrace_print("Pass 2");
1123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#endif
1133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1141b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (!(ctx->options & E2F_OPT_PREEN))
1151b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_2_PASS_HEADER, &cd.pctx);
1161b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o
11734b9f7963933daeb1c3fb3f21a70a1673d098154Theodore Ts'o	e2fsck_setup_tdb_icount(ctx, EXT2_ICOUNT_OPT_INCREMENT,
11834b9f7963933daeb1c3fb3f21a70a1673d098154Theodore Ts'o				&ctx->inode_count);
11934b9f7963933daeb1c3fb3f21a70a1673d098154Theodore Ts'o	if (ctx->inode_count)
12034b9f7963933daeb1c3fb3f21a70a1673d098154Theodore Ts'o		cd.pctx.errcode = 0;
12134b9f7963933daeb1c3fb3f21a70a1673d098154Theodore Ts'o	else
12234b9f7963933daeb1c3fb3f21a70a1673d098154Theodore Ts'o		cd.pctx.errcode = ext2fs_create_icount2(fs,
12334b9f7963933daeb1c3fb3f21a70a1673d098154Theodore Ts'o						EXT2_ICOUNT_OPT_INCREMENT,
1241b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o						0, ctx->inode_link_info,
1251b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o						&ctx->inode_count);
1261b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (cd.pctx.errcode) {
1271b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_2_ALLOCATE_ICOUNT, &cd.pctx);
12808b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		ctx->flags |= E2F_FLAG_ABORT;
12908b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		return;
13021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	}
131bcf9c5d4016975c3c2afdb4a4b358569bd3c8681Theodore Ts'o	buf = (char *) e2fsck_allocate_memory(ctx, 2*fs->blocksize,
13254dc7ca2869897ae8cb81a9ab9880ebff11680bcTheodore Ts'o					      "directory scan buffer");
1333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
13421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	/*
13521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	 * Set up the parent pointer for the root directory, if
13621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	 * present.  (If the root directory is not present, we will
13721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	 * create it in pass 3.)
13821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	 */
13928db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o	(void) e2fsck_dir_info_set_parent(ctx, EXT2_ROOT_INO, EXT2_ROOT_INO);
14021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o
14121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	cd.buf = buf;
1421b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	cd.ctx = ctx;
143f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	cd.count = 1;
144f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o	cd.max = ext2fs_dblist_count(fs->dblist);
145f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o
146f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	if (ctx->progress)
147f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o		(void) (ctx->progress)(ctx, 2, 0, cd.max);
148ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o
149ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o	if (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX)
150ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o		ext2fs_dblist_sort(fs->dblist, special_dir_block_cmp);
15121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o
1521b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	cd.pctx.errcode = ext2fs_dblist_iterate(fs->dblist, check_dir_block,
1531b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o						&cd);
154a02ce9df5ff5db2982462aec7162f7142dc18131Theodore Ts'o	if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
15508b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		return;
1561b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (cd.pctx.errcode) {
1571b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_2_DBLIST_ITERATE, &cd.pctx);
15808b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		ctx->flags |= E2F_FLAG_ABORT;
15908b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		return;
1607ac02a5ebddcc6187c893eedc80d92777b399575Theodore Ts'o	}
1618fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o
1628fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#ifdef ENABLE_HTREE
1638fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	for (i=0; (dx_dir = e2fsck_dx_dir_info_iter(ctx, &i)) != 0;) {
1644cae04529eda0e482ceaa86b48e532f9c8d35f24Theodore Ts'o		if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
1654cae04529eda0e482ceaa86b48e532f9c8d35f24Theodore Ts'o			return;
16662acaa1de132a808949d71264731bba7fe095705Theodore Ts'o		if (dx_dir->numblocks == 0)
1678fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			continue;
1688fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		clear_problem_context(&pctx);
1698fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		bad_dir = 0;
1708fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		pctx.dir = dx_dir->ino;
1718fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		dx_db = dx_dir->dx_block;
1728fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		if (dx_db->flags & DX_FLAG_REFERENCED)
1738fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			dx_db->flags |= DX_FLAG_DUP_REF;
1748fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		else
1758fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			dx_db->flags |= DX_FLAG_REFERENCED;
1768fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		/*
1778fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		 * Find all of the first and last leaf blocks, and
1788fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		 * update their parent's min and max hash values
1798fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		 */
1808fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		for (b=0, dx_db = dx_dir->dx_block;
1818fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		     b < dx_dir->numblocks;
1828fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		     b++, dx_db++) {
1838fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			if ((dx_db->type != DX_DIRBLOCK_LEAF) ||
1848fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			    !(dx_db->flags & (DX_FLAG_FIRST | DX_FLAG_LAST)))
1858fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				continue;
1868fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			dx_parent = &dx_dir->dx_block[dx_db->parent];
1878fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			/*
1888fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			 * XXX Make sure dx_parent->min_hash > dx_db->min_hash
1898fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			 */
1908fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			if (dx_db->flags & DX_FLAG_FIRST)
1918fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				dx_parent->min_hash = dx_db->min_hash;
1928fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			/*
1938fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			 * XXX Make sure dx_parent->max_hash < dx_db->max_hash
1948fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			 */
1958fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			if (dx_db->flags & DX_FLAG_LAST)
1968fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				dx_parent->max_hash = dx_db->max_hash;
1978fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		}
1988fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o
1998fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		for (b=0, dx_db = dx_dir->dx_block;
2008fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		     b < dx_dir->numblocks;
2018fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		     b++, dx_db++) {
2028fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			pctx.blkcount = b;
2038fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			pctx.group = dx_db->parent;
2048fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			code = 0;
2058fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			if (!(dx_db->flags & DX_FLAG_FIRST) &&
2068fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			    (dx_db->min_hash < dx_db->node_min_hash)) {
2078fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				pctx.blk = dx_db->min_hash;
2088fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				pctx.blk2 = dx_db->node_min_hash;
2098fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				code = PR_2_HTREE_MIN_HASH;
2108fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				fix_problem(ctx, code, &pctx);
2118fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				bad_dir++;
2128fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			}
213ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o			if (dx_db->type == DX_DIRBLOCK_LEAF) {
214ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o				depth = htree_depth(dx_dir, dx_db);
215ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o				if (depth != dx_dir->depth) {
216ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o					code = PR_2_HTREE_BAD_DEPTH;
217ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o					fix_problem(ctx, code, &pctx);
218ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o					bad_dir++;
219ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o				}
220ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o			}
2218fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			/*
2228fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			 * This test doesn't apply for the root block
2238fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			 * at block #0
2248fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			 */
2258fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			if (b &&
2268fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			    (dx_db->max_hash > dx_db->node_max_hash)) {
2278fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				pctx.blk = dx_db->max_hash;
2288fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				pctx.blk2 = dx_db->node_max_hash;
2298fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				code = PR_2_HTREE_MAX_HASH;
2308fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				fix_problem(ctx, code, &pctx);
231503f9e7f6eb331c5b75d7f1ad126f71bcdcfb4e3Theodore Ts'o				bad_dir++;
2328fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			}
2338fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			if (!(dx_db->flags & DX_FLAG_REFERENCED)) {
2348fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				code = PR_2_HTREE_NOTREF;
2358fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				fix_problem(ctx, code, &pctx);
2368fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				bad_dir++;
2378fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			} else if (dx_db->flags & DX_FLAG_DUP_REF) {
2388fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				code = PR_2_HTREE_DUPREF;
2398fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				fix_problem(ctx, code, &pctx);
2408fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				bad_dir++;
2418fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			}
2428fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			if (code == 0)
2438fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				continue;
2448fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		}
2458fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		if (bad_dir && fix_problem(ctx, PR_2_HTREE_CLEAR, &pctx)) {
2468fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			clear_htree(ctx, dx_dir->ino);
24762acaa1de132a808949d71264731bba7fe095705Theodore Ts'o			dx_dir->numblocks = 0;
2488fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		}
2498fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	}
2508fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#endif
251c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	ext2fs_free_mem(&buf);
25221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	ext2fs_free_dblist(fs->dblist);
25321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o
2541b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (ctx->inode_bad_map) {
2551b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		ext2fs_free_inode_bitmap(ctx->inode_bad_map);
2561b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		ctx->inode_bad_map = 0;
2573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
258aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o	if (ctx->inode_reg_map) {
259aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o		ext2fs_free_inode_bitmap(ctx->inode_reg_map);
260aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o		ctx->inode_reg_map = 0;
261aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o	}
262a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o
263a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o	clear_problem_context(&pctx);
264a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o	if (ctx->large_files) {
265a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o		if (!(sb->s_feature_ro_compat &
266a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o		      EXT2_FEATURE_RO_COMPAT_LARGE_FILE) &&
267a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o		    fix_problem(ctx, PR_2_FEATURE_LARGE_FILES, &pctx)) {
268a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o			sb->s_feature_ro_compat |=
269a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o				EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
270a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o			ext2fs_mark_super_dirty(fs);
271a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o		}
272a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o		if (sb->s_rev_level == EXT2_GOOD_OLD_REV &&
273a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o		    fix_problem(ctx, PR_1_FS_REV_LEVEL, &pctx)) {
274a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o			ext2fs_update_dynamic_rev(fs);
275a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o			ext2fs_mark_super_dirty(fs);
276a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o		}
277a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o	} else if (!ctx->large_files &&
278a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o	    (sb->s_feature_ro_compat &
279a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o	      EXT2_FEATURE_RO_COMPAT_LARGE_FILE)) {
280a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o		if (fs->flags & EXT2_FLAG_RW) {
281a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o			sb->s_feature_ro_compat &=
282a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o				~EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
283a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o			ext2fs_mark_super_dirty(fs);
284a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o		}
285a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o	}
286a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o
2878bf191e8660939687ef35c013066d2082cb16722Theodore Ts'o#ifdef RESOURCE_TRACK
2885596defa1e212242c1bf1b028139143fbb7777a0Theodore Ts'o	if (ctx->options & E2F_OPT_TIME2) {
2895596defa1e212242c1bf1b028139143fbb7777a0Theodore Ts'o		e2fsck_clear_progbar(ctx);
2906d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o		print_resource_track(_("Pass 2"), &rtrack, fs->io);
2915596defa1e212242c1bf1b028139143fbb7777a0Theodore Ts'o	}
2928bf191e8660939687ef35c013066d2082cb16722Theodore Ts'o#endif
2933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
2943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
295ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o#define MAX_DEPTH 32000
296ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'ostatic int htree_depth(struct dx_dir_info *dx_dir,
297ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		       struct dx_dirblock_info *dx_db)
298ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o{
299ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	int	depth = 0;
300ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o
301ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	while (dx_db->type != DX_DIRBLOCK_ROOT && depth < MAX_DEPTH) {
302ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		dx_db = &dx_dir->dx_block[dx_db->parent];
303ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		depth++;
304ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	}
305ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	return depth;
306ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o}
307ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o
3080926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'ostatic int dict_de_cmp(const void *a, const void *b)
3090926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o{
310520ead378ec5ddef828a8d206434cc3a444b2e9eTheodore Ts'o	const struct ext2_dir_entry *de_a, *de_b;
3110926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o	int	a_len, b_len;
3120926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o
313520ead378ec5ddef828a8d206434cc3a444b2e9eTheodore Ts'o	de_a = (const struct ext2_dir_entry *) a;
3140926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o	a_len = de_a->name_len & 0xFF;
315520ead378ec5ddef828a8d206434cc3a444b2e9eTheodore Ts'o	de_b = (const struct ext2_dir_entry *) b;
3160926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o	b_len = de_b->name_len & 0xFF;
3170926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o
3180926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o	if (a_len != b_len)
3190926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o		return (a_len - b_len);
3200926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o
3210926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o	return strncmp(de_a->name, de_b->name, a_len);
3220926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o}
323ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o
3243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
325ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o * This is special sort function that makes sure that directory blocks
326ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o * with a dirblock of zero are sorted to the beginning of the list.
327ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o * This guarantees that the root node of the htree directories are
328ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o * processed first, so we know what hash version to use.
329ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o */
330ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'ostatic EXT2_QSORT_TYPE special_dir_block_cmp(const void *a, const void *b)
331ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o{
332ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o	const struct ext2_db_entry *db_a =
333ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o		(const struct ext2_db_entry *) a;
334ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o	const struct ext2_db_entry *db_b =
335ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o		(const struct ext2_db_entry *) b;
336ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o
337ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o	if (db_a->blockcnt && !db_b->blockcnt)
338ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o		return 1;
339ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o
340ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o	if (!db_a->blockcnt && db_b->blockcnt)
341ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o		return -1;
342ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o
343ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o	if (db_a->blk != db_b->blk)
344ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o		return (int) (db_a->blk - db_b->blk);
345ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o
346ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o	if (db_a->ino != db_b->ino)
347ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o		return (int) (db_a->ino - db_b->ino);
348ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o
349ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o	return (int) (db_a->blockcnt - db_b->blockcnt);
350ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o}
351ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o
352ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o
353ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o/*
3543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Make sure the first entry in the directory is '.', and that the
3553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * directory entry is sane.
3563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
3571b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'ostatic int check_dot(e2fsck_t ctx,
3583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		     struct ext2_dir_entry *dirent,
35986c627ec1136446409a0170d439e60c148e6eb48Theodore Ts'o		     ext2_ino_t ino, struct problem_context *pctx)
3603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
3613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct ext2_dir_entry *nextdir;
3623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int	status = 0;
3633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int	created = 0;
3643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int	new_len;
36521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	int	problem = 0;
3663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
36721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	if (!dirent->inode)
36821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		problem = PR_2_MISSING_DOT;
369b6f7983197fe217cf20862c93d72620be3b0fcecTheodore Ts'o	else if (((dirent->name_len & 0xFF) != 1) ||
37021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		 (dirent->name[0] != '.'))
37121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		problem = PR_2_1ST_NOT_DOT;
37221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	else if (dirent->name[1] != '\0')
37321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		problem = PR_2_DOT_NULL_TERM;
37421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o
37521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	if (problem) {
3761b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		if (fix_problem(ctx, problem, pctx)) {
37721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			if (dirent->rec_len < 12)
37821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o				dirent->rec_len = 12;
3793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			dirent->inode = ino;
3803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			dirent->name_len = 1;
3813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			dirent->name[0] = '.';
38221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			dirent->name[1] = '\0';
3833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			status = 1;
3843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			created = 1;
3853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
3863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
3873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (dirent->inode != ino) {
3881b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		if (fix_problem(ctx, PR_2_BAD_INODE_DOT, pctx)) {
3893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			dirent->inode = ino;
3903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			status = 1;
39121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		}
3923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
3933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (dirent->rec_len > 12) {
3943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		new_len = dirent->rec_len - 12;
3953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (new_len > 12) {
3963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			if (created ||
397f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o			    fix_problem(ctx, PR_2_SPLIT_DOT, pctx)) {
3983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				nextdir = (struct ext2_dir_entry *)
3993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o					((char *) dirent + 12);
4003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				dirent->rec_len = 12;
4013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				nextdir->rec_len = new_len;
4023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				nextdir->inode = 0;
4033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				nextdir->name_len = 0;
4043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				status = 1;
4053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			}
4063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
4073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
4083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return status;
4093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
4103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
4123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Make sure the second entry in the directory is '..', and that the
4133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * directory entry is sane.  We do not check the inode number of '..'
4143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * here; this gets done in pass 3.
4153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
4161b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'ostatic int check_dotdot(e2fsck_t ctx,
4173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			struct ext2_dir_entry *dirent,
41828db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o			ext2_ino_t ino, struct problem_context *pctx)
4193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
42028db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o	int			problem = 0;
4213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
42221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	if (!dirent->inode)
42321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		problem = PR_2_MISSING_DOT_DOT;
424b6f7983197fe217cf20862c93d72620be3b0fcecTheodore Ts'o	else if (((dirent->name_len & 0xFF) != 2) ||
42521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		 (dirent->name[0] != '.') ||
42621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		 (dirent->name[1] != '.'))
42721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		problem = PR_2_2ND_NOT_DOT_DOT;
42821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	else if (dirent->name[2] != '\0')
42921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		problem = PR_2_DOT_DOT_NULL_TERM;
43021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o
43121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	if (problem) {
4321b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		if (fix_problem(ctx, problem, pctx)) {
43321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			if (dirent->rec_len < 12)
43421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o				dirent->rec_len = 12;
4353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			/*
4363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			 * Note: we don't have the parent inode just
4373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			 * yet, so we will fill it in with the root
4383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			 * inode.  This will get fixed in pass 3.
4393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			 */
4403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			dirent->inode = EXT2_ROOT_INO;
4413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			dirent->name_len = 2;
4423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			dirent->name[0] = '.';
4433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			dirent->name[1] = '.';
44421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			dirent->name[2] = '\0';
4453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			return 1;
44621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		}
4473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
4483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
44928db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o	if (e2fsck_dir_info_set_dotdot(ctx, ino, dirent->inode)) {
45028db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o		fix_problem(ctx, PR_2_NO_DIRINFO, pctx);
45128db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o		return -1;
45228db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o	}
4533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
4543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
4553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
4573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Check to make sure a directory entry doesn't contain any illegal
4583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * characters.
4593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
4601b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'ostatic int check_name(e2fsck_t ctx,
4613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		      struct ext2_dir_entry *dirent,
462544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		      ext2_ino_t dir_ino EXT2FS_ATTR((unused)),
463544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		      struct problem_context *pctx)
4643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
4653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int	i;
4663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int	fixup = -1;
4673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int	ret = 0;
4683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
469b6f7983197fe217cf20862c93d72620be3b0fcecTheodore Ts'o	for ( i = 0; i < (dirent->name_len & 0xFF); i++) {
4703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (dirent->name[i] == '/' || dirent->name[i] == '\0') {
4713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			if (fixup < 0) {
4721b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o				fixup = fix_problem(ctx, PR_2_BAD_NAME, pctx);
4733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			}
4743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			if (fixup) {
4753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				dirent->name[i] = '.';
4763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				ret = 1;
47721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			}
4783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
4793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
4803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return ret;
4813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
4823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
483aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o/*
484aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o * Check the directory filetype (if present)
485aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o */
486aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'ostatic _INLINE_ int check_filetype(e2fsck_t ctx,
487544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o				   struct ext2_dir_entry *dirent,
488544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o				   ext2_ino_t dir_ino EXT2FS_ATTR((unused)),
489544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o				   struct problem_context *pctx)
490aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o{
491aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o	int	filetype = dirent->name_len >> 8;
492aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o	int	should_be = EXT2_FT_UNKNOWN;
493aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o	struct ext2_inode	inode;
494aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o
495aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o	if (!(ctx->fs->super->s_feature_incompat &
4967847c1d4fff9195c16b6d74194d104200b3f6c67Theodore Ts'o	      EXT2_FEATURE_INCOMPAT_FILETYPE)) {
4977847c1d4fff9195c16b6d74194d104200b3f6c67Theodore Ts'o		if (filetype == 0 ||
4987847c1d4fff9195c16b6d74194d104200b3f6c67Theodore Ts'o		    !fix_problem(ctx, PR_2_CLEAR_FILETYPE, pctx))
4997847c1d4fff9195c16b6d74194d104200b3f6c67Theodore Ts'o			return 0;
5007847c1d4fff9195c16b6d74194d104200b3f6c67Theodore Ts'o		dirent->name_len = dirent->name_len & 0xFF;
5017847c1d4fff9195c16b6d74194d104200b3f6c67Theodore Ts'o		return 1;
5027847c1d4fff9195c16b6d74194d104200b3f6c67Theodore Ts'o	}
503aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o
504aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o	if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, dirent->inode)) {
505aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o		should_be = EXT2_FT_DIR;
506aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o	} else if (ext2fs_test_inode_bitmap(ctx->inode_reg_map,
507aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o					    dirent->inode)) {
508aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o		should_be = EXT2_FT_REG_FILE;
509aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o	} else if (ctx->inode_bad_map &&
510aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o		   ext2fs_test_inode_bitmap(ctx->inode_bad_map,
511aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o					    dirent->inode))
512aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o		should_be = 0;
513aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o	else {
514aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o		e2fsck_read_inode(ctx, dirent->inode, &inode,
515aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o				  "check_filetype");
5166fdc7a325c8bff67fc3a0489d0858bc7c48dc1a3Theodore Ts'o		should_be = ext2_file_type(inode.i_mode);
517aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o	}
518aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o	if (filetype == should_be)
519aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o		return 0;
520aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o	pctx->num = should_be;
521aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o
522aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o	if (fix_problem(ctx, filetype ? PR_2_BAD_FILETYPE : PR_2_SET_FILETYPE,
523aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o			pctx) == 0)
524aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o		return 0;
525aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o
526aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o	dirent->name_len = (dirent->name_len & 0xFF) | should_be << 8;
527aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o	return 1;
528aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o}
529aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o
5308fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#ifdef ENABLE_HTREE
5318fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'ostatic void parse_int_node(ext2_filsys fs,
5328fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			   struct ext2_db_entry *db,
5338fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			   struct check_dir_struct *cd,
5348fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			   struct dx_dir_info	*dx_dir,
5358fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			   char *block_buf)
5368fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o{
5378fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	struct 		ext2_dx_root_info  *root;
5388fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	struct 		ext2_dx_entry *ent;
5398fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	struct		ext2_dx_countlimit *limit;
5408fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	struct dx_dirblock_info	*dx_db;
541ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	int		i, expect_limit, count;
5428fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	blk_t		blk;
5438fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	ext2_dirhash_t	min_hash = 0xffffffff;
5448fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	ext2_dirhash_t	max_hash = 0;
545ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	ext2_dirhash_t	hash = 0, prev_hash;
5468fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o
5478fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	if (db->blockcnt == 0) {
5488fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		root = (struct ext2_dx_root_info *) (block_buf + 24);
5498fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o
5508fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#ifdef DX_DEBUG
5518fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		printf("Root node dump:\n");
5528deb80a5d1078cbe43eaffcdeebf0a1a549d6a54Takashi Sato		printf("\t Reserved zero: %u\n", root->reserved_zero);
5538fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		printf("\t Hash Version: %d\n", root->hash_version);
5548fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		printf("\t Info length: %d\n", root->info_length);
5558fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		printf("\t Indirect levels: %d\n", root->indirect_levels);
5568fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		printf("\t Flags: %d\n", root->unused_flags);
5578fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#endif
5588fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o
5598fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		ent = (struct ext2_dx_entry *) (block_buf + 24 + root->info_length);
5608fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	} else {
5618fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		ent = (struct ext2_dx_entry *) (block_buf+8);
5628fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	}
5638fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	limit = (struct ext2_dx_countlimit *) ent;
5648fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o
5658fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#ifdef DX_DEBUG
5668132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o	printf("Number of entries (count): %d\n",
5678132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o	       ext2fs_le16_to_cpu(limit->count));
5688132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o	printf("Number of entries (limit): %d\n",
5698132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o	       ext2fs_le16_to_cpu(limit->limit));
5708fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#endif
5718fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o
5728132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o	count = ext2fs_le16_to_cpu(limit->count);
573ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	expect_limit = (fs->blocksize - ((char *) ent - block_buf)) /
574ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		sizeof(struct ext2_dx_entry);
5758132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o	if (ext2fs_le16_to_cpu(limit->limit) != expect_limit) {
5768132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o		cd->pctx.num = ext2fs_le16_to_cpu(limit->limit);
577ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		if (fix_problem(cd->ctx, PR_2_HTREE_BAD_LIMIT, &cd->pctx))
578ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o			goto clear_and_exit;
579ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	}
5808132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o	if (count > expect_limit) {
5818132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o		cd->pctx.num = count;
582ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		if (fix_problem(cd->ctx, PR_2_HTREE_BAD_COUNT, &cd->pctx))
583ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o			goto clear_and_exit;
584ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		count = expect_limit;
585ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	}
586ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o
587ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	for (i=0; i < count; i++) {
588ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		prev_hash = hash;
5898132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o		hash = i ? (ext2fs_le32_to_cpu(ent[i].hash) & ~1) : 0;
5908fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#ifdef DX_DEBUG
5918deb80a5d1078cbe43eaffcdeebf0a1a549d6a54Takashi Sato		printf("Entry #%d: Hash 0x%08x, block %u\n", i,
5928132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o		       hash, ext2fs_le32_to_cpu(ent[i].block));
5938fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#endif
5948132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o		blk = ext2fs_le32_to_cpu(ent[i].block) & 0x0ffffff;
5958fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		/* Check to make sure the block is valid */
596977ac8731bf3bd934421dd8107e77325ec7e6de7Theodore Ts'o		if (blk >= (blk_t) dx_dir->numblocks) {
597b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o			cd->pctx.blk = blk;
5988fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			if (fix_problem(cd->ctx, PR_2_HTREE_BADBLK,
599ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o					&cd->pctx))
600ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o				goto clear_and_exit;
601977ac8731bf3bd934421dd8107e77325ec7e6de7Theodore Ts'o			continue;
6028fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		}
603ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		if (hash < prev_hash &&
604ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		    fix_problem(cd->ctx, PR_2_HTREE_HASH_ORDER, &cd->pctx))
605ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o			goto clear_and_exit;
6068fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		dx_db = &dx_dir->dx_block[blk];
6078fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		if (dx_db->flags & DX_FLAG_REFERENCED) {
6088fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			dx_db->flags |= DX_FLAG_DUP_REF;
6098fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		} else {
6108fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			dx_db->flags |= DX_FLAG_REFERENCED;
6118fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			dx_db->parent = db->blockcnt;
6128fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		}
6138fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		if (hash < min_hash)
6148fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			min_hash = hash;
6158fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		if (hash > max_hash)
6168fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			max_hash = hash;
6178fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		dx_db->node_min_hash = hash;
6188132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o		if ((i+1) < count)
6198132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o			dx_db->node_max_hash =
6208132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o			  ext2fs_le32_to_cpu(ent[i+1].hash) & ~1;
6218fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		else {
6228fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			dx_db->node_max_hash = 0xfffffffe;
6238fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			dx_db->flags |= DX_FLAG_LAST;
6248fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		}
6258fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		if (i == 0)
6268fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			dx_db->flags |= DX_FLAG_FIRST;
6278fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	}
6288fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#ifdef DX_DEBUG
6298fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	printf("Blockcnt = %d, min hash 0x%08x, max hash 0x%08x\n",
6308fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	       db->blockcnt, min_hash, max_hash);
6318fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#endif
6328fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	dx_db = &dx_dir->dx_block[db->blockcnt];
6338fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	dx_db->min_hash = min_hash;
6348fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	dx_db->max_hash = max_hash;
635ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	return;
636ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o
637ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'oclear_and_exit:
638ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	clear_htree(cd->ctx, cd->pctx.ino);
639ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	dx_dir->numblocks = 0;
6408fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o}
6418fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#endif /* ENABLE_HTREE */
642aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o
643e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o/*
644e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o * Given a busted directory, try to salvage it somehow.
645e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o *
646e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o */
647ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'ostatic void salvage_directory(ext2_filsys fs,
648e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o			      struct ext2_dir_entry *dirent,
649e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o			      struct ext2_dir_entry *prev,
650544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			      unsigned int *offset)
651e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o{
652e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	char	*cp = (char *) dirent;
653ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	int left = fs->blocksize - *offset - dirent->rec_len;
654642935c082ca22e1186fc9926fe06e4207d5ab56Theodore Ts'o	unsigned int name_len = dirent->name_len & 0xFF;
655e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o
656e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	/*
657e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	 * Special case of directory entry of size 8: copy what's left
658e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	 * of the directory block up to cover up the invalid hole.
659e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	 */
660e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	if ((left >= 12) && (dirent->rec_len == 8)) {
661e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o		memmove(cp, cp+8, left);
662e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o		memset(cp + left, 0, 8);
663ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		return;
664ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	}
665ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	/*
666ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	 * If the directory entry overruns the end of the directory
667ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	 * block, and the name is small enough to fit, then adjust the
668ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	 * record length.
669ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	 */
670ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	if ((left < 0) &&
671642935c082ca22e1186fc9926fe06e4207d5ab56Theodore Ts'o	    (name_len + 8 <= dirent->rec_len + (unsigned) left) &&
672ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	    dirent->inode <= fs->super->s_inodes_count &&
673ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	    strnlen(dirent->name, name_len) == name_len) {
674ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		dirent->rec_len += left;
675ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		return;
676e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	}
677e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	/*
678575307cc63d24766ff789262a5cea7b4faf2fa13Kalpak Shah	 * If the record length of the directory entry is a multiple
679575307cc63d24766ff789262a5cea7b4faf2fa13Kalpak Shah	 * of four, and not too big, such that it is valid, let the
680575307cc63d24766ff789262a5cea7b4faf2fa13Kalpak Shah	 * previous directory entry absorb the invalid one.
681e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	 */
682575307cc63d24766ff789262a5cea7b4faf2fa13Kalpak Shah	if (prev && dirent->rec_len && (dirent->rec_len % 4) == 0 &&
683575307cc63d24766ff789262a5cea7b4faf2fa13Kalpak Shah	    (*offset + dirent->rec_len <= fs->blocksize)) {
684e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o		prev->rec_len += dirent->rec_len;
685ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		*offset += dirent->rec_len;
686ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		return;
687e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	}
688e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	/*
689e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	 * Default salvage method --- kill all of the directory
690e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	 * entries for the rest of the block.  We will either try to
691e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	 * absorb it into the previous directory entry, or create a
692e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	 * new empty directory entry the rest of the directory block.
693e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	 */
694e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	if (prev) {
695ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		prev->rec_len += fs->blocksize - *offset;
696ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		*offset = fs->blocksize;
697e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	} else {
698ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		dirent->rec_len = fs->blocksize - *offset;
699e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o		dirent->name_len = 0;
700e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o		dirent->inode = 0;
701e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	}
702e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o}
703e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o
7043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic int check_dir_block(ext2_filsys fs,
70521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			   struct ext2_db_entry *db,
70654dc7ca2869897ae8cb81a9ab9880ebff11680bcTheodore Ts'o			   void *priv_data)
7073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
7088fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o 	struct dx_dir_info	*dx_dir;
7098fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#ifdef ENABLE_HTREE
7108fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	struct dx_dirblock_info	*dx_db = 0;
7118fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#endif /* ENABLE_HTREE */
712e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	struct ext2_dir_entry 	*dirent, *prev;
7138fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	ext2_dirhash_t		hash;
714544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	unsigned int		offset = 0;
715e94bc631648299dca43a6015520b18f6232d50dfTheodore Ts'o	const char *		old_op;
7163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int			dir_modified = 0;
71721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	int			dot_state;
7183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	blk_t			block_nr = db->blk;
71986c627ec1136446409a0170d439e60c148e6eb48Theodore Ts'o	ext2_ino_t 		ino = db->ino;
72028db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o	ext2_ino_t 		subdir_parent;
72121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	__u16			links;
72254dc7ca2869897ae8cb81a9ab9880ebff11680bcTheodore Ts'o	struct check_dir_struct	*cd;
7231b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	char 			*buf;
7241b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	e2fsck_t		ctx;
7251b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	int			problem;
726ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o	struct ext2_dx_root_info *root;
727e8254bfd3b49cb325a1ff6b21ca86570a1008744Theodore Ts'o	struct ext2_dx_countlimit *limit;
7280926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o	static dict_t de_dict;
7290926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o	struct problem_context	pctx;
7300926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o	int	dups_found = 0;
73128db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o	int	ret;
7321b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o
73354dc7ca2869897ae8cb81a9ab9880ebff11680bcTheodore Ts'o	cd = (struct check_dir_struct *) priv_data;
7341b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	buf = cd->buf;
7351b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ctx = cd->ctx;
736f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o
7374cae04529eda0e482ceaa86b48e532f9c8d35f24Theodore Ts'o	if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
7384cae04529eda0e482ceaa86b48e532f9c8d35f24Theodore Ts'o		return DIRENT_ABORT;
7394cae04529eda0e482ceaa86b48e532f9c8d35f24Theodore Ts'o
7404cae04529eda0e482ceaa86b48e532f9c8d35f24Theodore Ts'o	if (ctx->progress && (ctx->progress)(ctx, 2, cd->count++, cd->max))
7414cae04529eda0e482ceaa86b48e532f9c8d35f24Theodore Ts'o		return DIRENT_ABORT;
74221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o
7433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
7443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Make sure the inode is still in use (could have been
7453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * deleted in the duplicate/bad blocks pass.
7463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
7471b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map, ino)))
7483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
74950e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o
75021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	cd->pctx.ino = ino;
75121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	cd->pctx.blk = block_nr;
75221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	cd->pctx.blkcount = db->blockcnt;
75321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	cd->pctx.ino2 = 0;
75421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	cd->pctx.dirent = 0;
75521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	cd->pctx.num = 0;
75621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o
75750e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	if (db->blk == 0) {
7581b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		if (allocate_dir_block(ctx, db, buf, &cd->pctx))
75950e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o			return 0;
76050e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o		block_nr = db->blk;
76150e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	}
7623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
7633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (db->blockcnt)
7643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		dot_state = 2;
7653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	else
7663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		dot_state = 0;
7673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
7680926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o	if (ctx->dirs_to_hash &&
7690926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o	    ext2fs_u32_list_test(ctx->dirs_to_hash, ino))
7700926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o		dups_found++;
7710926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o
7723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#if 0
773f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	printf("In process_dir_block block %lu, #%d, inode %lu\n", block_nr,
7743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	       db->blockcnt, ino);
7753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#endif
7763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
777e94bc631648299dca43a6015520b18f6232d50dfTheodore Ts'o	old_op = ehandler_operation(_("reading directory block"));
7781b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	cd->pctx.errcode = ext2fs_read_dir_block(fs, block_nr, buf);
779e94bc631648299dca43a6015520b18f6232d50dfTheodore Ts'o	ehandler_operation(0);
780b9852cd87b42f79d569db68c3fdefe4a8f48ede1Theodore Ts'o	if (cd->pctx.errcode == EXT2_ET_DIR_CORRUPTED)
781b9852cd87b42f79d569db68c3fdefe4a8f48ede1Theodore Ts'o		cd->pctx.errcode = 0; /* We'll handle this ourselves */
7821b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (cd->pctx.errcode) {
78308b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		if (!fix_problem(ctx, PR_2_READ_DIRBLOCK, &cd->pctx)) {
78408b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o			ctx->flags |= E2F_FLAG_ABORT;
78508b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o			return DIRENT_ABORT;
78608b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		}
7871b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		memset(buf, 0, fs->blocksize);
7883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
7898fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#ifdef ENABLE_HTREE
7908fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	dx_dir = e2fsck_get_dx_dir_info(ctx, ino);
79162acaa1de132a808949d71264731bba7fe095705Theodore Ts'o	if (dx_dir && dx_dir->numblocks) {
7928fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		if (db->blockcnt >= dx_dir->numblocks) {
7938fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			printf("XXX should never happen!!!\n");
7948fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			abort();
7958fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		}
7968fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		dx_db = &dx_dir->dx_block[db->blockcnt];
7978fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		dx_db->type = DX_DIRBLOCK_LEAF;
7988fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		dx_db->phys = block_nr;
7998fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		dx_db->min_hash = ~0;
8008fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		dx_db->max_hash = 0;
8018fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o
8028fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		dirent = (struct ext2_dir_entry *) buf;
803e8254bfd3b49cb325a1ff6b21ca86570a1008744Theodore Ts'o		limit = (struct ext2_dx_countlimit *) (buf+8);
8048fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		if (db->blockcnt == 0) {
805ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o			root = (struct ext2_dx_root_info *) (buf + 24);
8068fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			dx_db->type = DX_DIRBLOCK_ROOT;
8078fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			dx_db->flags |= DX_FLAG_FIRST | DX_FLAG_LAST;
808ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o			if ((root->reserved_zero ||
809ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o			     root->info_length < 8 ||
810ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o			     root->indirect_levels > 1) &&
811ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o			    fix_problem(ctx, PR_2_HTREE_BAD_ROOT, &cd->pctx)) {
812ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o				clear_htree(ctx, ino);
813ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o				dx_dir->numblocks = 0;
814ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o				dx_db = 0;
815f77704e416fca7dbe4cc91abba674d2ae3c14f6fTheodore Ts'o			}
816ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o			dx_dir->hashversion = root->hash_version;
817f77704e416fca7dbe4cc91abba674d2ae3c14f6fTheodore Ts'o			if ((dx_dir->hashversion <= EXT2_HASH_TEA) &&
818f77704e416fca7dbe4cc91abba674d2ae3c14f6fTheodore Ts'o			    (fs->super->s_flags & EXT2_FLAGS_UNSIGNED_HASH))
819f77704e416fca7dbe4cc91abba674d2ae3c14f6fTheodore Ts'o				dx_dir->hashversion += 3;
820ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o			dx_dir->depth = root->indirect_levels + 1;
8218fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		} else if ((dirent->inode == 0) &&
822e8254bfd3b49cb325a1ff6b21ca86570a1008744Theodore Ts'o			   (dirent->rec_len == fs->blocksize) &&
823e8254bfd3b49cb325a1ff6b21ca86570a1008744Theodore Ts'o			   (dirent->name_len == 0) &&
8248132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o			   (ext2fs_le16_to_cpu(limit->limit) ==
8258132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o			    ((fs->blocksize-8) /
8268132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o			     sizeof(struct ext2_dx_entry))))
8278fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			dx_db->type = DX_DIRBLOCK_NODE;
8288fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	}
8298fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#endif /* ENABLE_HTREE */
8303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
8310926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o	dict_init(&de_dict, DICTCOUNT_T_MAX, dict_de_cmp);
832e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	prev = 0;
8333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	do {
8341b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		problem = 0;
8353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		dirent = (struct ext2_dir_entry *) (buf + offset);
83621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		cd->pctx.dirent = dirent;
83721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		cd->pctx.num = offset;
8383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (((offset + dirent->rec_len) > fs->blocksize) ||
839c40db6d5717023bdd6bb4935161e7ce9678d6234Theodore Ts'o		    (dirent->rec_len < 12) ||
84021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		    ((dirent->rec_len % 4) != 0) ||
841b6f7983197fe217cf20862c93d72620be3b0fcecTheodore Ts'o		    (((dirent->name_len & 0xFF)+8) > dirent->rec_len)) {
8421b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			if (fix_problem(ctx, PR_2_DIR_CORRUPTED, &cd->pctx)) {
843ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o				salvage_directory(fs, dirent, prev, &offset);
8443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				dir_modified++;
845e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o				continue;
84621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			} else
8470926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o				goto abort_free_dict;
8483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
849b6f7983197fe217cf20862c93d72620be3b0fcecTheodore Ts'o		if ((dirent->name_len & 0xFF) > EXT2_NAME_LEN) {
8501b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			if (fix_problem(ctx, PR_2_FILENAME_LONG, &cd->pctx)) {
85150e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o				dirent->name_len = EXT2_NAME_LEN;
85250e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o				dir_modified++;
85350e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o			}
85450e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o		}
85550e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o
856e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o		if (dot_state == 0) {
8571b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			if (check_dot(ctx, dirent, ino, &cd->pctx))
8583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				dir_modified++;
859e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o		} else if (dot_state == 1) {
86028db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o			ret = check_dotdot(ctx, dirent, ino, &cd->pctx);
86128db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o			if (ret < 0)
8620926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o				goto abort_free_dict;
86328db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o			if (ret)
8643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				dir_modified++;
8653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		} else if (dirent->inode == ino) {
8661b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			problem = PR_2_LINK_DOT;
8671b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			if (fix_problem(ctx, PR_2_LINK_DOT, &cd->pctx)) {
8683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				dirent->inode = 0;
8693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				dir_modified++;
87021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o				goto next;
8713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			}
8723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
8733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (!dirent->inode)
8743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			goto next;
8753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
8763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		/*
8773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * Make sure the inode listed is a legal one.
8783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 */
8793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (((dirent->inode != EXT2_ROOT_INO) &&
8807f88b04341d88c5df0360d930832c38040303b61Theodore Ts'o		     (dirent->inode < EXT2_FIRST_INODE(fs->super))) ||
8813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		    (dirent->inode > fs->super->s_inodes_count)) {
8821b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			problem = PR_2_BAD_INO;
8831b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		} else if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map,
8843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o					       dirent->inode))) {
8851b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			/*
8861b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 * If the inode is unused, offer to clear it.
8871b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 */
8881b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			problem = PR_2_UNUSED_INODE;
8891b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		} else if (ctx->inode_bb_map &&
8901b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			   (ext2fs_test_inode_bitmap(ctx->inode_bb_map,
8911b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o						     dirent->inode))) {
8921b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			/*
8931b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 * If the inode is in a bad block, offer to
8941b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 * clear it.
8951b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 */
8961b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			problem = PR_2_BB_INODE;
897e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o		} else if ((dot_state > 1) &&
898b6f7983197fe217cf20862c93d72620be3b0fcecTheodore Ts'o			   ((dirent->name_len & 0xFF) == 1) &&
8991b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			   (dirent->name[0] == '.')) {
9001b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			/*
9011b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 * If there's a '.' entry in anything other
9021b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 * than the first directory entry, it's a
9031b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 * duplicate entry that should be removed.
9041b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 */
9051b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			problem = PR_2_DUP_DOT;
906e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o		} else if ((dot_state > 1) &&
907b6f7983197fe217cf20862c93d72620be3b0fcecTheodore Ts'o			   ((dirent->name_len & 0xFF) == 2) &&
9081b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			   (dirent->name[0] == '.') &&
9091b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			   (dirent->name[1] == '.')) {
9101b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			/*
9111b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 * If there's a '..' entry in anything other
9121b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 * than the second directory entry, it's a
9131b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 * duplicate entry that should be removed.
9141b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 */
9151b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			problem = PR_2_DUP_DOT_DOT;
916e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o		} else if ((dot_state > 1) &&
9171b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			   (dirent->inode == EXT2_ROOT_INO)) {
9181b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			/*
9191b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 * Don't allow links to the root directory.
9201b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 * We check this specially to make sure we
9211b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 * catch this error case even if the root
9221b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 * directory hasn't been created yet.
9231b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 */
9241b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			problem = PR_2_LINK_ROOT;
925e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o		} else if ((dot_state > 1) &&
926c40db6d5717023bdd6bb4935161e7ce9678d6234Theodore Ts'o			   (dirent->name_len & 0xFF) == 0) {
927c40db6d5717023bdd6bb4935161e7ce9678d6234Theodore Ts'o			/*
928c40db6d5717023bdd6bb4935161e7ce9678d6234Theodore Ts'o			 * Don't allow zero-length directory names.
929c40db6d5717023bdd6bb4935161e7ce9678d6234Theodore Ts'o			 */
930c40db6d5717023bdd6bb4935161e7ce9678d6234Theodore Ts'o			problem = PR_2_NULL_NAME;
93121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		}
93221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o
9331b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		if (problem) {
9341b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			if (fix_problem(ctx, problem, &cd->pctx)) {
93521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o				dirent->inode = 0;
93621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o				dir_modified++;
93721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o				goto next;
9381b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			} else {
9391b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o				ext2fs_unmark_valid(fs);
9401b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o				if (problem == PR_2_BAD_INO)
9411b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o					goto next;
94221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			}
9433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
9443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
9453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		/*
9463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * If the inode was marked as having bad fields in
9473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * pass1, process it and offer to fix/clear it.
9483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * (We wait until now so that we can display the
9493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * pathname to the user.)
9503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 */
9511b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		if (ctx->inode_bad_map &&
9521b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		    ext2fs_test_inode_bitmap(ctx->inode_bad_map,
9533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o					     dirent->inode)) {
954e72a9ba39471364ad2f9397f645ca547090e3485Theodore Ts'o			if (e2fsck_process_bad_inode(ctx, ino,
955bcf9c5d4016975c3c2afdb4a4b358569bd3c8681Theodore Ts'o						     dirent->inode,
956bcf9c5d4016975c3c2afdb4a4b358569bd3c8681Theodore Ts'o						     buf + fs->blocksize)) {
9573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				dirent->inode = 0;
9583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				dir_modified++;
9593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				goto next;
9603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			}
961a02ce9df5ff5db2982462aec7162f7142dc18131Theodore Ts'o			if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
96208b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o				return DIRENT_ABORT;
9633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
9643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
9651b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		if (check_name(ctx, dirent, ino, &cd->pctx))
9661b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			dir_modified++;
9671b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o
968aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o		if (check_filetype(ctx, dirent, ino, &cd->pctx))
969aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o			dir_modified++;
970aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o
9718fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#ifdef ENABLE_HTREE
9728fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		if (dx_db) {
9738fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			ext2fs_dirhash(dx_dir->hashversion, dirent->name,
974503f9e7f6eb331c5b75d7f1ad126f71bcdcfb4e3Theodore Ts'o				       (dirent->name_len & 0xFF),
975503f9e7f6eb331c5b75d7f1ad126f71bcdcfb4e3Theodore Ts'o				       fs->super->s_hash_seed, &hash, 0);
9768fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			if (hash < dx_db->min_hash)
9778fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				dx_db->min_hash = hash;
9788fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			if (hash > dx_db->max_hash)
9798fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				dx_db->max_hash = hash;
9808fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		}
9818fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#endif
9828fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o
98321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		/*
9843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * If this is a directory, then mark its parent in its
9853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * dir_info structure.  If the parent field is already
9863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * filled in, then this directory has more than one
9873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * hard link.  We assume the first link is correct,
9883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * and ask the user if he/she wants to clear this one.
9893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 */
990e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o		if ((dot_state > 1) &&
9911b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		    (ext2fs_test_inode_bitmap(ctx->inode_dir_map,
9923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o					      dirent->inode))) {
99328db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o			if (e2fsck_dir_info_get_parent(ctx, dirent->inode,
99428db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o						       &subdir_parent)) {
9951b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o				cd->pctx.ino = dirent->inode;
9961b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o				fix_problem(ctx, PR_2_NO_DIRINFO, &cd->pctx);
9970926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o				goto abort_free_dict;
9983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			}
99928db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o			if (subdir_parent) {
100028db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o				cd->pctx.ino2 = subdir_parent;
10011b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o				if (fix_problem(ctx, PR_2_LINK_DIR,
100221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o						&cd->pctx)) {
10033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o					dirent->inode = 0;
10043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o					dir_modified++;
10053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o					goto next;
100621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o				}
100721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o				cd->pctx.ino2 = 0;
100828db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o			} else {
100928db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o				(void) e2fsck_dir_info_set_parent(ctx,
101028db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o						  dirent->inode, ino);
101128db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o			}
10123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
10130926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o
10140926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o		if (dups_found) {
10150926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o			;
10160926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o		} else if (dict_lookup(&de_dict, dirent)) {
10170926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o			clear_problem_context(&pctx);
10180926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o			pctx.ino = ino;
10190926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o			pctx.dirent = dirent;
10200926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o			fix_problem(ctx, PR_2_REPORT_DUP_DIRENT, &pctx);
10210926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o			if (!ctx->dirs_to_hash)
10220926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o				ext2fs_u32_list_create(&ctx->dirs_to_hash, 50);
10230926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o			if (ctx->dirs_to_hash)
10240926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o				ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
10250926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o			dups_found++;
10260926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o		} else
10270926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o			dict_alloc_insert(&de_dict, dirent, dirent);
10283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
10291b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		ext2fs_icount_increment(ctx->inode_count, dirent->inode,
10301b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o					&links);
103121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		if (links > 1)
10321b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			ctx->fs_links_count++;
10331b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		ctx->fs_total_count++;
10343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	next:
1035e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o		prev = dirent;
10363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		offset += dirent->rec_len;
1037e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o		dot_state++;
10383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	} while (offset < fs->blocksize);
10393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#if 0
10403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	printf("\n");
10413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#endif
10428fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#ifdef ENABLE_HTREE
10438fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	if (dx_db) {
10448fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#ifdef DX_DEBUG
10458fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		printf("db_block %d, type %d, min_hash 0x%0x, max_hash 0x%0x\n",
10468fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		       db->blockcnt, dx_db->type,
10478fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		       dx_db->min_hash, dx_db->max_hash);
10488fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#endif
1049b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o		cd->pctx.dir = cd->pctx.ino;
10508fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		if ((dx_db->type == DX_DIRBLOCK_ROOT) ||
10518fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		    (dx_db->type == DX_DIRBLOCK_NODE))
10528fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			parse_int_node(fs, db, cd, dx_dir, buf);
10538fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	}
10548fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#endif /* ENABLE_HTREE */
10553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (offset != fs->blocksize) {
10561b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		cd->pctx.num = dirent->rec_len - fs->blocksize + offset;
10571b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		if (fix_problem(ctx, PR_2_FINAL_RECLEN, &cd->pctx)) {
10581b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			dirent->rec_len = cd->pctx.num;
10591b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			dir_modified++;
10601b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		}
10613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
10623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (dir_modified) {
10631b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		cd->pctx.errcode = ext2fs_write_dir_block(fs, block_nr, buf);
10641b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		if (cd->pctx.errcode) {
106508b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o			if (!fix_problem(ctx, PR_2_WRITE_DIRBLOCK,
10660926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o					 &cd->pctx))
10670926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o				goto abort_free_dict;
10683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
10693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		ext2fs_mark_changed(fs);
10703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
10710926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o	dict_free_nodes(&de_dict);
10723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
10730926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'oabort_free_dict:
10740926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o	dict_free_nodes(&de_dict);
10750926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o	ctx->flags |= E2F_FLAG_ABORT;
10760926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o	return DIRENT_ABORT;
10773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
10783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
10793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
10803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * This function is called to deallocate a block, and is an interator
10813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * functioned called by deallocate inode via ext2fs_iterate_block().
10823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
10833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic int deallocate_inode_block(ext2_filsys fs,
1084133a56dc9da52054bc27b4c1a23f03e3405003dbTheodore Ts'o				  blk_t	*block_nr,
1085544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o				  e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
1086544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o				  blk_t ref_block EXT2FS_ATTR((unused)),
1087544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o				  int ref_offset EXT2FS_ATTR((unused)),
1088133a56dc9da52054bc27b4c1a23f03e3405003dbTheodore Ts'o				  void *priv_data)
10893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
109054dc7ca2869897ae8cb81a9ab9880ebff11680bcTheodore Ts'o	e2fsck_t	ctx = (e2fsck_t) priv_data;
10911b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o
10921917875fcd16428d14eb5a86acf414472bc216f1Theodore Ts'o	if (HOLE_BLKADDR(*block_nr))
10933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
10941ba7a2f2b6a9b152828a06443955a7fb1d139930Theodore Ts'o	if ((*block_nr < fs->super->s_first_data_block) ||
10951ba7a2f2b6a9b152828a06443955a7fb1d139930Theodore Ts'o	    (*block_nr >= fs->super->s_blocks_count))
10961ba7a2f2b6a9b152828a06443955a7fb1d139930Theodore Ts'o		return 0;
10971b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ext2fs_unmark_block_bitmap(ctx->block_found_map, *block_nr);
10980684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o	ext2fs_block_alloc_stats(fs, *block_nr, -1);
10993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
11003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
11013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
11023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
11033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * This fuction deallocates an inode
11043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
11054035f40bc4550ce7520724cc837992a700794e00Theodore Ts'ostatic void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf)
11063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
11071b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ext2_filsys fs = ctx->fs;
11083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct ext2_inode	inode;
11091b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	struct problem_context	pctx;
11100684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o	__u32			count;
11111b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o
11121b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ext2fs_icount_store(ctx->inode_link_info, ino, 0);
111308b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o	e2fsck_read_inode(ctx, ino, &inode, "deallocate_inode");
11143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_links_count = 0;
11151f3ad14a5ad5df3ac4012d41ef5d76411cd8fff3Theodore Ts'o	inode.i_dtime = ctx->now;
111608b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o	e2fsck_write_inode(ctx, ino, &inode, "deallocate_inode");
11171b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	clear_problem_context(&pctx);
11181b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	pctx.ino = ino;
1119f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
11203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
11213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Fix up the bitmaps...
11223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
1123f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o	e2fsck_read_bitmaps(ctx);
11241b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
11251b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
11261b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (ctx->inode_bad_map)
11271b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
11280684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o	ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode));
11290684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o
11300684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o	if (inode.i_file_acl &&
11310684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o	    (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) {
11320684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o		pctx.errcode = ext2fs_adjust_ea_refcount(fs, inode.i_file_acl,
11330684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o						   block_buf, -1, &count);
11340684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o		if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) {
11350684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o			pctx.errcode = 0;
11360684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o			count = 1;
11370684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o		}
11380684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o		if (pctx.errcode) {
11390684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o			pctx.blk = inode.i_file_acl;
11400684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o			fix_problem(ctx, PR_2_ADJ_EA_REFCOUNT, &pctx);
11410684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o			ctx->flags |= E2F_FLAG_ABORT;
11420684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o			return;
11430684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o		}
11440684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o		if (count == 0) {
11450684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o			ext2fs_unmark_block_bitmap(ctx->block_found_map,
11460684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o						   inode.i_file_acl);
11470684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o			ext2fs_block_alloc_stats(fs, inode.i_file_acl, -1);
11480684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o		}
11490684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o		inode.i_file_acl = 0;
11500684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o	}
11513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
115221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	if (!ext2fs_inode_has_valid_blocks(&inode))
11533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return;
1154a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o
1155b94a052a25d0c524209782e408c31d8ff25a6fe1Andreas Dilger	if (LINUX_S_ISREG(inode.i_mode) &&
1156a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o	    (inode.i_size_high || inode.i_size & 0x80000000UL))
1157a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o		ctx->large_files--;
1158a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o
1159133a56dc9da52054bc27b4c1a23f03e3405003dbTheodore Ts'o	pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf,
11601b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o					    deallocate_inode_block, ctx);
11611b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (pctx.errcode) {
11621b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_2_DEALLOC_INODE, &pctx);
116308b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		ctx->flags |= E2F_FLAG_ABORT;
116408b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		return;
11651b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	}
11663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
11673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
11688fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o/*
11698fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o * This fuction clears the htree flag on an inode
11708fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o */
11718fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'ostatic void clear_htree(e2fsck_t ctx, ext2_ino_t ino)
11728fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o{
11738fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	struct ext2_inode	inode;
11748fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o
11758fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	e2fsck_read_inode(ctx, ino, &inode, "clear_htree");
11768fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	inode.i_flags = inode.i_flags & ~EXT2_INDEX_FL;
11778fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	e2fsck_write_inode(ctx, ino, &inode, "clear_htree");
1178b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o	if (ctx->dirs_to_hash)
1179b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o		ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
11808fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o}
11818fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o
11828fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o
118386c627ec1136446409a0170d439e60c148e6eb48Theodore Ts'oextern int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir,
1184bcf9c5d4016975c3c2afdb4a4b358569bd3c8681Theodore Ts'o				    ext2_ino_t ino, char *buf)
11853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
11861b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ext2_filsys fs = ctx->fs;
11873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct ext2_inode	inode;
11883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int			inode_modified = 0;
11896c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o	int			not_fixed = 0;
11901e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o	unsigned char		*frag, *fsize;
119121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	struct problem_context	pctx;
119208b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o	int	problem = 0;
11933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
119408b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o	e2fsck_read_inode(ctx, ino, &inode, "process_bad_inode");
119521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o
119621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	clear_problem_context(&pctx);
119721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	pctx.ino = ino;
119821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	pctx.dir = dir;
119921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	pctx.inode = &inode;
120021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o
12016c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o	if (inode.i_file_acl &&
1202f76344fb6f9439ecd5060943930e73cd3b3dd9feTheodore Ts'o	    !(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) {
1203f76344fb6f9439ecd5060943930e73cd3b3dd9feTheodore Ts'o		if (fix_problem(ctx, PR_2_FILE_ACL_ZERO, &pctx)) {
1204f76344fb6f9439ecd5060943930e73cd3b3dd9feTheodore Ts'o			inode.i_file_acl = 0;
1205f76344fb6f9439ecd5060943930e73cd3b3dd9feTheodore Ts'o			inode_modified++;
1206f76344fb6f9439ecd5060943930e73cd3b3dd9feTheodore Ts'o		} else
1207f76344fb6f9439ecd5060943930e73cd3b3dd9feTheodore Ts'o			not_fixed++;
1208f76344fb6f9439ecd5060943930e73cd3b3dd9feTheodore Ts'o	}
12096c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o
121050e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	if (!LINUX_S_ISDIR(inode.i_mode) && !LINUX_S_ISREG(inode.i_mode) &&
121150e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	    !LINUX_S_ISCHR(inode.i_mode) && !LINUX_S_ISBLK(inode.i_mode) &&
121250e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	    !LINUX_S_ISLNK(inode.i_mode) && !LINUX_S_ISFIFO(inode.i_mode) &&
121308b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o	    !(LINUX_S_ISSOCK(inode.i_mode)))
121408b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		problem = PR_2_BAD_MODE;
1215fdbdea09b87dbd8e39c23286f22653e7641599aeTheodore Ts'o	else if (LINUX_S_ISCHR(inode.i_mode)
12160684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o		 && !e2fsck_pass1_check_device_inode(fs, &inode))
121708b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		problem = PR_2_BAD_CHAR_DEV;
1218fdbdea09b87dbd8e39c23286f22653e7641599aeTheodore Ts'o	else if (LINUX_S_ISBLK(inode.i_mode)
12190684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o		 && !e2fsck_pass1_check_device_inode(fs, &inode))
122008b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		problem = PR_2_BAD_BLOCK_DEV;
1221fdbdea09b87dbd8e39c23286f22653e7641599aeTheodore Ts'o	else if (LINUX_S_ISFIFO(inode.i_mode)
12220684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o		 && !e2fsck_pass1_check_device_inode(fs, &inode))
12231dde43f0c1176f61dd0bf91aff265ce8cd1c5fd6Theodore Ts'o		problem = PR_2_BAD_FIFO;
1224fdbdea09b87dbd8e39c23286f22653e7641599aeTheodore Ts'o	else if (LINUX_S_ISSOCK(inode.i_mode)
12250684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o		 && !e2fsck_pass1_check_device_inode(fs, &inode))
12261dde43f0c1176f61dd0bf91aff265ce8cd1c5fd6Theodore Ts'o		problem = PR_2_BAD_SOCKET;
1227fdbdea09b87dbd8e39c23286f22653e7641599aeTheodore Ts'o	else if (LINUX_S_ISLNK(inode.i_mode)
1228bcf9c5d4016975c3c2afdb4a4b358569bd3c8681Theodore Ts'o		 && !e2fsck_pass1_check_symlink(fs, &inode, buf)) {
1229bcf9c5d4016975c3c2afdb4a4b358569bd3c8681Theodore Ts'o		problem = PR_2_INVALID_SYMLINK;
123067052a8aeeca8cd80d1dd33c2792f917573accc8Andreas Dilger	}
12311dde43f0c1176f61dd0bf91aff265ce8cd1c5fd6Theodore Ts'o
123208b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o	if (problem) {
123308b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		if (fix_problem(ctx, problem, &pctx)) {
12341b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			deallocate_inode(ctx, ino, 0);
1235a02ce9df5ff5db2982462aec7162f7142dc18131Theodore Ts'o			if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
123608b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o				return 0;
12377cf73dcd3d173d88ceab26d381f4abac362d8518Theodore Ts'o			return 1;
12386c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o		} else
12396c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o			not_fixed++;
124008b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		problem = 0;
12417cf73dcd3d173d88ceab26d381f4abac362d8518Theodore Ts'o	}
12427cf73dcd3d173d88ceab26d381f4abac362d8518Theodore Ts'o
12436c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o	if (inode.i_faddr) {
12446c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o		if (fix_problem(ctx, PR_2_FADDR_ZERO, &pctx)) {
12456c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o			inode.i_faddr = 0;
12466c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o			inode_modified++;
12476c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o		} else
12486c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o			not_fixed++;
12493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
12501e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o
12511e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o	switch (fs->super->s_creator_os) {
12521e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o	    case EXT2_OS_HURD:
12531e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o		frag = &inode.osd2.hurd2.h_i_frag;
12541e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o		fsize = &inode.osd2.hurd2.h_i_fsize;
12551e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o		break;
12561e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o	    case EXT2_OS_MASIX:
12571e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o		frag = &inode.osd2.masix2.m_i_frag;
12581e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o		fsize = &inode.osd2.masix2.m_i_fsize;
12591e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o		break;
12601e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o	    default:
12611e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o		frag = fsize = 0;
12621e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o	}
126321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	if (frag && *frag) {
126421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		pctx.num = *frag;
12651b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		if (fix_problem(ctx, PR_2_FRAG_ZERO, &pctx)) {
126621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			*frag = 0;
126721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			inode_modified++;
12687e0282c5f21add344b306876ca999aecd4d5fd0cTheodore Ts'o		} else
12697e0282c5f21add344b306876ca999aecd4d5fd0cTheodore Ts'o			not_fixed++;
127021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		pctx.num = 0;
127121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	}
127221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	if (fsize && *fsize) {
127321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		pctx.num = *fsize;
12741b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		if (fix_problem(ctx, PR_2_FSIZE_ZERO, &pctx)) {
127521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			*fsize = 0;
127621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			inode_modified++;
12776c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o		} else
12786c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o			not_fixed++;
127921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		pctx.num = 0;
128021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	}
128121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o
12825d17119d14fe1276936c85d7986695a4543b1aa1Theodore Ts'o	if ((fs->super->s_creator_os == EXT2_OS_LINUX) &&
12835d17119d14fe1276936c85d7986695a4543b1aa1Theodore Ts'o	    !(fs->super->s_feature_ro_compat &
12845d17119d14fe1276936c85d7986695a4543b1aa1Theodore Ts'o	      EXT4_FEATURE_RO_COMPAT_HUGE_FILE) &&
12855d17119d14fe1276936c85d7986695a4543b1aa1Theodore Ts'o	    (inode.osd2.linux2.l_i_blocks_hi != 0)) {
12865d17119d14fe1276936c85d7986695a4543b1aa1Theodore Ts'o		pctx.num = inode.osd2.linux2.l_i_blocks_hi;
12875d17119d14fe1276936c85d7986695a4543b1aa1Theodore Ts'o		if (fix_problem(ctx, PR_2_BLOCKS_HI_ZERO, &pctx)) {
12885d17119d14fe1276936c85d7986695a4543b1aa1Theodore Ts'o			inode.osd2.linux2.l_i_blocks_hi = 0;
12895d17119d14fe1276936c85d7986695a4543b1aa1Theodore Ts'o			inode_modified++;
12905d17119d14fe1276936c85d7986695a4543b1aa1Theodore Ts'o		}
12915d17119d14fe1276936c85d7986695a4543b1aa1Theodore Ts'o	}
12925d17119d14fe1276936c85d7986695a4543b1aa1Theodore Ts'o
129321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	if (inode.i_file_acl &&
1294342d847db355d81299218e07a1e58ece82080a04Theodore Ts'o	    ((inode.i_file_acl < fs->super->s_first_data_block) ||
12956c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o	     (inode.i_file_acl >= fs->super->s_blocks_count))) {
12966c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o		if (fix_problem(ctx, PR_2_FILE_ACL_BAD, &pctx)) {
12976c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o			inode.i_file_acl = 0;
12986c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o			inode_modified++;
12996c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o		} else
13006c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o			not_fixed++;
1301342d847db355d81299218e07a1e58ece82080a04Theodore Ts'o	}
130221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	if (inode.i_dir_acl &&
13036c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o	    LINUX_S_ISDIR(inode.i_mode)) {
13046c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o		if (fix_problem(ctx, PR_2_DIR_ACL_ZERO, &pctx)) {
13056c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o			inode.i_dir_acl = 0;
13066c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o			inode_modified++;
13076c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o		} else
13086c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o			not_fixed++;
130921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	}
13106c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o
1311f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	if (inode_modified)
131208b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		e2fsck_write_inode(ctx, ino, &inode, "process_bad_inode");
1313f76344fb6f9439ecd5060943930e73cd3b3dd9feTheodore Ts'o	if (!not_fixed && ctx->inode_bad_map)
13146c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o		ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
13153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
13163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
13173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
131850e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o
131950e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o/*
132050e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o * allocate_dir_block --- this function allocates a new directory
132150e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o * 	block for a particular inode; this is done if a directory has
132250e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o * 	a "hole" in it, or if a directory has a illegal block number
132350e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o * 	that was zeroed out and now needs to be replaced.
132450e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o */
13251b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'ostatic int allocate_dir_block(e2fsck_t ctx,
132621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			      struct ext2_db_entry *db,
1327544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			      char *buf EXT2FS_ATTR((unused)),
1328544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			      struct problem_context *pctx)
132950e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o{
13301b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ext2_filsys fs = ctx->fs;
133150e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	blk_t			blk;
133250e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	char			*block;
133350e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	struct ext2_inode	inode;
133450e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o
13351b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (fix_problem(ctx, PR_2_DIRECTORY_HOLE, pctx) == 0)
133650e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o		return 1;
133750e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o
133850e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	/*
133950e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	 * Read the inode and block bitmaps in; we'll be messing with
134050e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	 * them.
134150e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	 */
1342f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o	e2fsck_read_bitmaps(ctx);
134350e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o
134450e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	/*
134550e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	 * First, find a free block
134650e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	 */
13471b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	pctx->errcode = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk);
13481b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (pctx->errcode) {
13491b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx->str = "ext2fs_new_block";
13501b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
135150e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o		return 1;
135250e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	}
13531b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
135450e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	ext2fs_mark_block_bitmap(fs->block_map, blk);
135550e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	ext2fs_mark_bb_dirty(fs);
135650e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o
135750e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	/*
135850e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	 * Now let's create the actual data block for the inode
135950e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	 */
136050e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	if (db->blockcnt)
13611b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx->errcode = ext2fs_new_dir_block(fs, 0, 0, &block);
136250e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	else
13631b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx->errcode = ext2fs_new_dir_block(fs, db->ino,
13641b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o						     EXT2_ROOT_INO, &block);
136550e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o
13661b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (pctx->errcode) {
13671b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx->str = "ext2fs_new_dir_block";
13681b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
136950e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o		return 1;
137050e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	}
137150e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o
13721b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	pctx->errcode = ext2fs_write_dir_block(fs, blk, block);
1373c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	ext2fs_free_mem(&block);
13741b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (pctx->errcode) {
13751b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx->str = "ext2fs_write_dir_block";
13761b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
137750e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o		return 1;
137850e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	}
137950e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o
138050e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	/*
138150e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	 * Update the inode block count
138250e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	 */
138308b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o	e2fsck_read_inode(ctx, db->ino, &inode, "allocate_dir_block");
138450e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	inode.i_blocks += fs->blocksize / 512;
138550e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	if (inode.i_size < (db->blockcnt+1) * fs->blocksize)
138650e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o		inode.i_size = (db->blockcnt+1) * fs->blocksize;
138708b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o	e2fsck_write_inode(ctx, db->ino, &inode, "allocate_dir_block");
138850e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o
138950e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	/*
139050e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	 * Finally, update the block pointers for the inode
139150e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	 */
139250e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	db->blk = blk;
1393133a56dc9da52054bc27b4c1a23f03e3405003dbTheodore Ts'o	pctx->errcode = ext2fs_block_iterate2(fs, db->ino, BLOCK_FLAG_HOLE,
139450e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o				      0, update_dir_block, db);
13951b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (pctx->errcode) {
13961b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx->str = "ext2fs_block_iterate";
13971b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
139850e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o		return 1;
139950e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	}
140050e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o
140150e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	return 0;
140250e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o}
140350e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o
140450e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o/*
140550e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o * This is a helper function for allocate_dir_block().
140650e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o */
1407544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'ostatic int update_dir_block(ext2_filsys fs EXT2FS_ATTR((unused)),
140850e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o			    blk_t	*block_nr,
1409133a56dc9da52054bc27b4c1a23f03e3405003dbTheodore Ts'o			    e2_blkcnt_t blockcnt,
1410544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			    blk_t ref_block EXT2FS_ATTR((unused)),
1411544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			    int ref_offset EXT2FS_ATTR((unused)),
141254dc7ca2869897ae8cb81a9ab9880ebff11680bcTheodore Ts'o			    void *priv_data)
141350e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o{
141454dc7ca2869897ae8cb81a9ab9880ebff11680bcTheodore Ts'o	struct ext2_db_entry *db;
141550e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o
141654dc7ca2869897ae8cb81a9ab9880ebff11680bcTheodore Ts'o	db = (struct ext2_db_entry *) priv_data;
1417133a56dc9da52054bc27b4c1a23f03e3405003dbTheodore Ts'o	if (db->blockcnt == (int) blockcnt) {
141850e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o		*block_nr = db->blk;
141950e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o		return BLOCK_CHANGED;
142050e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	}
142150e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	return 0;
142250e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o}
1423