13839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
23839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * pass2.c --- check directory structure
3efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o *
421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o
521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o *
621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * %Begin-Header%
721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * This file may be redistributed under the terms of the GNU Public
821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * License.
921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * %End-Header%
10efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o *
113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Pass 2 of e2fsck iterates through all active directory inodes, and
123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * applies to following tests to each directory entry in the directory
133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * blocks in the inodes:
143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *
153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *	- The length of the directory entry (rec_len) should be at
163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 		least 8 bytes, and no more than the remaining space
173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 		left in the directory block.
183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 	- The length of the name in the directory entry (name_len)
19efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o * 		should be less than (rec_len - 8).
203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *	- The inode number in the directory entry should be within
213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 		legal bounds.
223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 	- The inode number should refer to a in-use inode.
233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *	- The first entry should be '.', and its inode should be
243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 		the inode of the directory.
253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 	- The second entry should be '..'.
263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *
273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * To minimize disk seek time, the directory blocks are processed in
283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * sorted order of block numbers.
293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *
303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Pass 2 also collects the following information:
313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 	- The inode numbers of the subdirectories for each directory.
323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *
333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Pass 2 relies on the following information from previous passes:
343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 	- The directory information collected in pass 1.
353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 	- The inode_used_map bitmap
363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 	- The inode_bad_map bitmap
373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 	- The inode_dir_map bitmap
383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *
393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Pass 2 frees the following data structures
403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 	- The inode_bad_map bitmap
41aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o * 	- The inode_reg_map bitmap
423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
44b969b1b8a5c13992cadb026114731958644540d8Matthias Andree#define _GNU_SOURCE 1 /* get strnlen() */
45d1154eb460efe588eaed3d439c1caaca149fa362Theodore Ts'o#include "config.h"
4648e6e81362f264aee4f3945c14928efaf71a06c9Theodore Ts'o#include <string.h>
4748e6e81362f264aee4f3945c14928efaf71a06c9Theodore Ts'o
483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include "e2fsck.h"
4921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o#include "problem.h"
503dca12fb62448f52663c859a089244d9cf37c5e3Theodore Ts'o#include "support/dict.h"
513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
52aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o#ifdef NO_INLINE_FUNCS
53aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o#define _INLINE_
54aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o#else
55aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o#define _INLINE_ inline
56aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o#endif
57aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o
58ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o/* #define DX_DEBUG */
598fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o
603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Keeps track of how many times an inode is referenced.
623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
634035f40bc4550ce7520724cc837992a700794e00Theodore Ts'ostatic void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf);
64a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wongstatic int check_dir_block2(ext2_filsys fs,
65a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong			   struct ext2_db_entry2 *dir_blocks_info,
66a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong			   void *priv_data);
673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic int check_dir_block(ext2_filsys fs,
686dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson			   struct ext2_db_entry2 *dir_blocks_info,
6954dc7ca2869897ae8cb81a9ab9880ebff11680bcTheodore Ts'o			   void *priv_data);
701b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'ostatic int allocate_dir_block(e2fsck_t ctx,
716dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson			      struct ext2_db_entry2 *dir_blocks_info,
7221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			      char *buf, struct problem_context *pctx);
738fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'ostatic void clear_htree(e2fsck_t ctx, ext2_ino_t ino);
74ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'ostatic int htree_depth(struct dx_dir_info *dx_dir,
75ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		       struct dx_dirblock_info *dx_db);
76ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'ostatic EXT2_QSORT_TYPE special_dir_block_cmp(const void *a, const void *b);
773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
7821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'ostruct check_dir_struct {
7921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	char *buf;
8021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	struct problem_context	pctx;
81f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o	int	count, max;
821b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	e2fsck_t ctx;
83a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong	unsigned long long list_offset;
84a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong	unsigned long long ra_entries;
85a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong	unsigned long long next_ra_off;
86efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o};
8721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o
8808b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'ovoid e2fsck_pass2(e2fsck_t ctx)
893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
90a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o	struct ext2_super_block *sb = ctx->fs->super;
91a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o	struct problem_context	pctx;
92a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o	ext2_filsys 		fs = ctx->fs;
93a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o	char			*buf;
948bf191e8660939687ef35c013066d2082cb16722Theodore Ts'o#ifdef RESOURCE_TRACK
953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct resource_track	rtrack;
968bf191e8660939687ef35c013066d2082cb16722Theodore Ts'o#endif
9721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	struct check_dir_struct cd;
988fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	struct dx_dir_info	*dx_dir;
998fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	struct dx_dirblock_info	*dx_db, *dx_parent;
100544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	int			b;
101ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	int			i, depth;
1028fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	problem_t		code;
1038fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	int			bad_dir;
104a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong	int (*check_dir_func)(ext2_filsys fs,
105a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong			      struct ext2_db_entry2 *dir_blocks_info,
106a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong			      void *priv_data);
1078fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o
1086d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	init_resource_track(&rtrack, ctx->fs->io);
1091b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	clear_problem_context(&cd.pctx);
1101b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o
1113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#ifdef MTRACE
1123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	mtrace_print("Pass 2");
1133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#endif
1143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1151b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (!(ctx->options & E2F_OPT_PREEN))
1161b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_2_PASS_HEADER, &cd.pctx);
1171b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o
118749f07121d9c98c317987a87f44c458745f39f15Theodore Ts'o	cd.pctx.errcode = e2fsck_setup_icount(ctx, "inode_count",
119749f07121d9c98c317987a87f44c458745f39f15Theodore Ts'o				EXT2_ICOUNT_OPT_INCREMENT,
120749f07121d9c98c317987a87f44c458745f39f15Theodore Ts'o				ctx->inode_link_info, &ctx->inode_count);
1211b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (cd.pctx.errcode) {
1221b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_2_ALLOCATE_ICOUNT, &cd.pctx);
12308b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		ctx->flags |= E2F_FLAG_ABORT;
12408b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		return;
12521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	}
126bcf9c5d4016975c3c2afdb4a4b358569bd3c8681Theodore Ts'o	buf = (char *) e2fsck_allocate_memory(ctx, 2*fs->blocksize,
12754dc7ca2869897ae8cb81a9ab9880ebff11680bcTheodore Ts'o					      "directory scan buffer");
1283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
12921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	/*
13021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	 * Set up the parent pointer for the root directory, if
13121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	 * present.  (If the root directory is not present, we will
13221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	 * create it in pass 3.)
13321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	 */
13428db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o	(void) e2fsck_dir_info_set_parent(ctx, EXT2_ROOT_INO, EXT2_ROOT_INO);
13521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o
13621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	cd.buf = buf;
1371b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	cd.ctx = ctx;
138f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	cd.count = 1;
1396dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson	cd.max = ext2fs_dblist_count2(fs->dblist);
140a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong	cd.list_offset = 0;
141a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong	cd.ra_entries = ctx->readahead_kb * 1024 / ctx->fs->blocksize;
142a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong	cd.next_ra_off = 0;
143f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o
144f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	if (ctx->progress)
145f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o		(void) (ctx->progress)(ctx, 2, 0, cd.max);
146ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o
14786f3b6cf98a72c6dad0738e3af2512ddcbd49be9Darrick J. Wong	if (ext2fs_has_feature_dir_index(fs->super))
1486dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson		ext2fs_dblist_sort2(fs->dblist, special_dir_block_cmp);
149efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
150a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong	check_dir_func = cd.ra_entries ? check_dir_block2 : check_dir_block;
151a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong	cd.pctx.errcode = ext2fs_dblist_iterate2(fs->dblist, check_dir_func,
1526dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson						 &cd);
1536267ee49be64035d8a9772c3bafed18a09874fa5Andreas Dilger	if (ctx->flags & E2F_FLAG_RESTART_LATER) {
1546267ee49be64035d8a9772c3bafed18a09874fa5Andreas Dilger		ctx->flags |= E2F_FLAG_RESTART;
155db3d8718be6ad3bdd252b242827fa54914b8ec2eAndreas Dilger		ctx->flags &= ~E2F_FLAG_RESTART_LATER;
1566267ee49be64035d8a9772c3bafed18a09874fa5Andreas Dilger	}
1576267ee49be64035d8a9772c3bafed18a09874fa5Andreas Dilger
158db3d8718be6ad3bdd252b242827fa54914b8ec2eAndreas Dilger	if (ctx->flags & E2F_FLAG_RUN_RETURN)
159db3d8718be6ad3bdd252b242827fa54914b8ec2eAndreas Dilger		return;
160db3d8718be6ad3bdd252b242827fa54914b8ec2eAndreas Dilger
1611b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (cd.pctx.errcode) {
1621b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_2_DBLIST_ITERATE, &cd.pctx);
16308b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		ctx->flags |= E2F_FLAG_ABORT;
16408b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		return;
1657ac02a5ebddcc6187c893eedc80d92777b399575Theodore Ts'o	}
1668fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o
1678fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	for (i=0; (dx_dir = e2fsck_dx_dir_info_iter(ctx, &i)) != 0;) {
1684cae04529eda0e482ceaa86b48e532f9c8d35f24Theodore Ts'o		if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
1694cae04529eda0e482ceaa86b48e532f9c8d35f24Theodore Ts'o			return;
170d02d019557d993c8dfe2f7d0fea841101f0d9e61Darrick J. Wong		if (e2fsck_dir_will_be_rehashed(ctx, dx_dir->ino) ||
171d02d019557d993c8dfe2f7d0fea841101f0d9e61Darrick J. Wong		    dx_dir->numblocks == 0)
1728fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			continue;
1738fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		clear_problem_context(&pctx);
1748fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		bad_dir = 0;
1758fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		pctx.dir = dx_dir->ino;
1768fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		dx_db = dx_dir->dx_block;
1778fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		if (dx_db->flags & DX_FLAG_REFERENCED)
1788fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			dx_db->flags |= DX_FLAG_DUP_REF;
1798fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		else
1808fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			dx_db->flags |= DX_FLAG_REFERENCED;
1818fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		/*
1828fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		 * Find all of the first and last leaf blocks, and
1838fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		 * update their parent's min and max hash values
1848fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		 */
1858fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		for (b=0, dx_db = dx_dir->dx_block;
1868fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		     b < dx_dir->numblocks;
1878fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		     b++, dx_db++) {
1888fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			if ((dx_db->type != DX_DIRBLOCK_LEAF) ||
1898fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			    !(dx_db->flags & (DX_FLAG_FIRST | DX_FLAG_LAST)))
1908fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				continue;
1918fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			dx_parent = &dx_dir->dx_block[dx_db->parent];
1928fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			/*
1938fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			 * XXX Make sure dx_parent->min_hash > dx_db->min_hash
1948fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			 */
1958fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			if (dx_db->flags & DX_FLAG_FIRST)
1968fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				dx_parent->min_hash = dx_db->min_hash;
1978fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			/*
1988fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			 * XXX Make sure dx_parent->max_hash < dx_db->max_hash
1998fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			 */
2008fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			if (dx_db->flags & DX_FLAG_LAST)
2018fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				dx_parent->max_hash = dx_db->max_hash;
2028fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		}
203efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
2048fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		for (b=0, dx_db = dx_dir->dx_block;
2058fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		     b < dx_dir->numblocks;
2068fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		     b++, dx_db++) {
2078fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			pctx.blkcount = b;
2088fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			pctx.group = dx_db->parent;
2098fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			code = 0;
2108fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			if (!(dx_db->flags & DX_FLAG_FIRST) &&
2118fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			    (dx_db->min_hash < dx_db->node_min_hash)) {
2128fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				pctx.blk = dx_db->min_hash;
2138fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				pctx.blk2 = dx_db->node_min_hash;
2148fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				code = PR_2_HTREE_MIN_HASH;
2158fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				fix_problem(ctx, code, &pctx);
2168fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				bad_dir++;
2178fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			}
218ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o			if (dx_db->type == DX_DIRBLOCK_LEAF) {
219ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o				depth = htree_depth(dx_dir, dx_db);
220ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o				if (depth != dx_dir->depth) {
221e5e12db959d3c18f6cf4ac938a14f68be0a89accAndreas Dilger					pctx.num = dx_dir->depth;
222ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o					code = PR_2_HTREE_BAD_DEPTH;
223ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o					fix_problem(ctx, code, &pctx);
224ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o					bad_dir++;
225ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o				}
226ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o			}
2278fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			/*
228efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o			 * This test doesn't apply for the root block
2298fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			 * at block #0
2308fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			 */
2318fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			if (b &&
2328fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			    (dx_db->max_hash > dx_db->node_max_hash)) {
2338fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				pctx.blk = dx_db->max_hash;
2348fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				pctx.blk2 = dx_db->node_max_hash;
2358fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				code = PR_2_HTREE_MAX_HASH;
2368fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				fix_problem(ctx, code, &pctx);
237503f9e7f6eb331c5b75d7f1ad126f71bcdcfb4e3Theodore Ts'o				bad_dir++;
2388fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			}
2398fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			if (!(dx_db->flags & DX_FLAG_REFERENCED)) {
2408fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				code = PR_2_HTREE_NOTREF;
2418fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				fix_problem(ctx, code, &pctx);
2428fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				bad_dir++;
2438fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			} else if (dx_db->flags & DX_FLAG_DUP_REF) {
2448fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				code = PR_2_HTREE_DUPREF;
2458fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				fix_problem(ctx, code, &pctx);
2468fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				bad_dir++;
2478fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			}
2488fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		}
2498fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		if (bad_dir && fix_problem(ctx, PR_2_HTREE_CLEAR, &pctx)) {
2508fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			clear_htree(ctx, dx_dir->ino);
25162acaa1de132a808949d71264731bba7fe095705Theodore Ts'o			dx_dir->numblocks = 0;
2528fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		}
2538fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	}
25423f75f6efaac6b756e0f3e4e1d33b6798347f66aTheodore Ts'o	e2fsck_free_dx_dir_info(ctx);
255149640fabcf140d8ede596b06ff8c191ca23cacaTheodore Ts'o
256c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	ext2fs_free_mem(&buf);
25721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	ext2fs_free_dblist(fs->dblist);
25821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o
2591b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (ctx->inode_bad_map) {
2601b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		ext2fs_free_inode_bitmap(ctx->inode_bad_map);
2611b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		ctx->inode_bad_map = 0;
2623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
263aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o	if (ctx->inode_reg_map) {
264aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o		ext2fs_free_inode_bitmap(ctx->inode_reg_map);
265aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o		ctx->inode_reg_map = 0;
266aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o	}
267dbff534ec685ea0815544746558dbd3e31284912Theodore Ts'o	if (ctx->encrypted_dirs) {
268dbff534ec685ea0815544746558dbd3e31284912Theodore Ts'o		ext2fs_u32_list_free(ctx->encrypted_dirs);
269dbff534ec685ea0815544746558dbd3e31284912Theodore Ts'o		ctx->encrypted_dirs = 0;
270dbff534ec685ea0815544746558dbd3e31284912Theodore Ts'o	}
271a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o
272a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o	clear_problem_context(&pctx);
273a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o	if (ctx->large_files) {
27486f3b6cf98a72c6dad0738e3af2512ddcbd49be9Darrick J. Wong		if (!ext2fs_has_feature_large_file(sb) &&
275a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o		    fix_problem(ctx, PR_2_FEATURE_LARGE_FILES, &pctx)) {
27686f3b6cf98a72c6dad0738e3af2512ddcbd49be9Darrick J. Wong			ext2fs_set_feature_large_file(sb);
2770cfce7f749ea519522929d91e705cf90518594c4Theodore Ts'o			fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
278a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o			ext2fs_mark_super_dirty(fs);
279a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o		}
280a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o		if (sb->s_rev_level == EXT2_GOOD_OLD_REV &&
281a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o		    fix_problem(ctx, PR_1_FS_REV_LEVEL, &pctx)) {
282a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o			ext2fs_update_dynamic_rev(fs);
283a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o			ext2fs_mark_super_dirty(fs);
284a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o		}
285a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o	}
286efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
2879facd076ae8af6e908e228392cea866ce0faf1bcKen Chen	print_resource_track(ctx, _("Pass 2"), &rtrack, fs->io);
2883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
2893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
290ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o#define MAX_DEPTH 32000
291ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'ostatic int htree_depth(struct dx_dir_info *dx_dir,
292ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		       struct dx_dirblock_info *dx_db)
293ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o{
294ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	int	depth = 0;
295ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o
296ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	while (dx_db->type != DX_DIRBLOCK_ROOT && depth < MAX_DEPTH) {
297ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		dx_db = &dx_dir->dx_block[dx_db->parent];
298ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		depth++;
299ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	}
300ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	return depth;
301ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o}
302ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o
3030926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'ostatic int dict_de_cmp(const void *a, const void *b)
3040926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o{
305520ead378ec5ddef828a8d206434cc3a444b2e9eTheodore Ts'o	const struct ext2_dir_entry *de_a, *de_b;
3060926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o	int	a_len, b_len;
3070926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o
308520ead378ec5ddef828a8d206434cc3a444b2e9eTheodore Ts'o	de_a = (const struct ext2_dir_entry *) a;
30970f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara	a_len = ext2fs_dirent_name_len(de_a);
310520ead378ec5ddef828a8d206434cc3a444b2e9eTheodore Ts'o	de_b = (const struct ext2_dir_entry *) b;
31170f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara	b_len = ext2fs_dirent_name_len(de_b);
3120926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o
3130926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o	if (a_len != b_len)
3140926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o		return (a_len - b_len);
3150926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o
316baa14bd17fb7f83b8f95e32318a7319a762ce000Theodore Ts'o	return memcmp(de_a->name, de_b->name, a_len);
3170926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o}
318ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o
3193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
320ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o * This is special sort function that makes sure that directory blocks
321ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o * with a dirblock of zero are sorted to the beginning of the list.
322ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o * This guarantees that the root node of the htree directories are
323ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o * processed first, so we know what hash version to use.
324ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o */
325ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'ostatic EXT2_QSORT_TYPE special_dir_block_cmp(const void *a, const void *b)
326ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o{
3276dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson	const struct ext2_db_entry2 *db_a =
3286dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson		(const struct ext2_db_entry2 *) a;
3296dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson	const struct ext2_db_entry2 *db_b =
3306dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson		(const struct ext2_db_entry2 *) b;
331ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o
332ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o	if (db_a->blockcnt && !db_b->blockcnt)
333ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o		return 1;
334ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o
335ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o	if (!db_a->blockcnt && db_b->blockcnt)
336ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o		return -1;
337efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
338ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o	if (db_a->blk != db_b->blk)
339ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o		return (int) (db_a->blk - db_b->blk);
340efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
341ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o	if (db_a->ino != db_b->ino)
342ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o		return (int) (db_a->ino - db_b->ino);
343ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o
344ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o	return (int) (db_a->blockcnt - db_b->blockcnt);
345ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o}
346ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o
347ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o
348ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o/*
3493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Make sure the first entry in the directory is '.', and that the
3503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * directory entry is sane.
3513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
3521b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'ostatic int check_dot(e2fsck_t ctx,
3533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		     struct ext2_dir_entry *dirent,
35486c627ec1136446409a0170d439e60c148e6eb48Theodore Ts'o		     ext2_ino_t ino, struct problem_context *pctx)
3553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
3563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct ext2_dir_entry *nextdir;
3578a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o	unsigned int	rec_len, new_len;
3583c7c6d73f1a0bd45835966f1179fc3e8236a7d9cTheodore Ts'o	int		status = 0;
3593c7c6d73f1a0bd45835966f1179fc3e8236a7d9cTheodore Ts'o	int		created = 0;
3603c7c6d73f1a0bd45835966f1179fc3e8236a7d9cTheodore Ts'o	problem_t	problem = 0;
361efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
36221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	if (!dirent->inode)
36321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		problem = PR_2_MISSING_DOT;
36470f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara	else if ((ext2fs_dirent_name_len(dirent) != 1) ||
36521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		 (dirent->name[0] != '.'))
36621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		problem = PR_2_1ST_NOT_DOT;
36721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	else if (dirent->name[1] != '\0')
36821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		problem = PR_2_DOT_NULL_TERM;
3695dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o
3708a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o	(void) ext2fs_get_rec_len(ctx->fs, dirent, &rec_len);
37121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	if (problem) {
3721b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		if (fix_problem(ctx, problem, pctx)) {
3735dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o			if (rec_len < 12)
3745dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o				rec_len = dirent->rec_len = 12;
3753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			dirent->inode = ino;
37670f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara			ext2fs_dirent_set_name_len(dirent, 1);
37770f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara			ext2fs_dirent_set_file_type(dirent, EXT2_FT_UNKNOWN);
3783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			dirent->name[0] = '.';
37921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			dirent->name[1] = '\0';
3803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			status = 1;
3813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			created = 1;
3823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
3833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
3843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (dirent->inode != ino) {
3851b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		if (fix_problem(ctx, PR_2_BAD_INODE_DOT, pctx)) {
3863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			dirent->inode = ino;
3873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			status = 1;
38821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		}
3893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
3905dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o	if (rec_len > 12) {
3915dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o		new_len = rec_len - 12;
3923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (new_len > 12) {
3933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			if (created ||
394f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o			    fix_problem(ctx, PR_2_SPLIT_DOT, pctx)) {
3953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				nextdir = (struct ext2_dir_entry *)
3963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o					((char *) dirent + 12);
3973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				dirent->rec_len = 12;
3988a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o				(void) ext2fs_set_rec_len(ctx->fs, new_len,
3998a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o							  nextdir);
4003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				nextdir->inode = 0;
40170f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara				ext2fs_dirent_set_name_len(nextdir, 0);
40270f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara				ext2fs_dirent_set_file_type(nextdir,
40370f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara							    EXT2_FT_UNKNOWN);
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{
4203c7c6d73f1a0bd45835966f1179fc3e8236a7d9cTheodore Ts'o	problem_t	problem = 0;
421cf5301d7f2c3bbed3d26600335102414cbf0c4baAndreas Dilger	unsigned int	rec_len;
422efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
42321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	if (!dirent->inode)
42421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		problem = PR_2_MISSING_DOT_DOT;
42570f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara	else if ((ext2fs_dirent_name_len(dirent) != 2) ||
42621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		 (dirent->name[0] != '.') ||
42721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		 (dirent->name[1] != '.'))
42821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		problem = PR_2_2ND_NOT_DOT_DOT;
42921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	else if (dirent->name[2] != '\0')
43021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		problem = PR_2_DOT_DOT_NULL_TERM;
43121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o
4328a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o	(void) ext2fs_get_rec_len(ctx->fs, dirent, &rec_len);
43321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	if (problem) {
4341b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		if (fix_problem(ctx, problem, pctx)) {
4355dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o			if (rec_len < 12)
43621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o				dirent->rec_len = 12;
4373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			/*
4383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			 * Note: we don't have the parent inode just
4393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			 * yet, so we will fill it in with the root
4403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			 * inode.  This will get fixed in pass 3.
4413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			 */
4423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			dirent->inode = EXT2_ROOT_INO;
44370f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara			ext2fs_dirent_set_name_len(dirent, 2);
44470f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara			ext2fs_dirent_set_file_type(dirent, EXT2_FT_UNKNOWN);
4453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			dirent->name[0] = '.';
4463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			dirent->name[1] = '.';
44721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			dirent->name[2] = '\0';
4483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			return 1;
449efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o		}
4503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
4513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
45228db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o	if (e2fsck_dir_info_set_dotdot(ctx, ino, dirent->inode)) {
45328db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o		fix_problem(ctx, PR_2_NO_DIRINFO, pctx);
45428db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o		return -1;
45528db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o	}
4563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
4573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
4583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
4603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Check to make sure a directory entry doesn't contain any illegal
4613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * characters.
4623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
4631b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'ostatic int check_name(e2fsck_t ctx,
4643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		      struct ext2_dir_entry *dirent,
465544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		      struct problem_context *pctx)
4663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
4673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int	i;
4683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int	fixup = -1;
4693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int	ret = 0;
470efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
47170f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara	for ( i = 0; i < ext2fs_dirent_name_len(dirent); i++) {
472dbff534ec685ea0815544746558dbd3e31284912Theodore Ts'o		if (dirent->name[i] != '/' && dirent->name[i] != '\0')
473dbff534ec685ea0815544746558dbd3e31284912Theodore Ts'o			continue;
474dbff534ec685ea0815544746558dbd3e31284912Theodore Ts'o		if (fixup < 0)
475dbff534ec685ea0815544746558dbd3e31284912Theodore Ts'o			fixup = fix_problem(ctx, PR_2_BAD_NAME, pctx);
476dbff534ec685ea0815544746558dbd3e31284912Theodore Ts'o		if (fixup == 0)
477dbff534ec685ea0815544746558dbd3e31284912Theodore Ts'o			return 0;
478dbff534ec685ea0815544746558dbd3e31284912Theodore Ts'o		dirent->name[i] = '.';
479dbff534ec685ea0815544746558dbd3e31284912Theodore Ts'o		ret = 1;
4803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
4813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return ret;
4823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
4833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
484e3dd5c6f1a1cf9baeb7073fe2ecc5214fdfe0621Theodore Ts'ostatic int encrypted_check_name(e2fsck_t ctx,
485e3dd5c6f1a1cf9baeb7073fe2ecc5214fdfe0621Theodore Ts'o				struct ext2_dir_entry *dirent,
486e3dd5c6f1a1cf9baeb7073fe2ecc5214fdfe0621Theodore Ts'o				struct problem_context *pctx)
487e3dd5c6f1a1cf9baeb7073fe2ecc5214fdfe0621Theodore Ts'o{
488e3dd5c6f1a1cf9baeb7073fe2ecc5214fdfe0621Theodore Ts'o	if (ext2fs_dirent_name_len(dirent) < EXT4_CRYPTO_BLOCK_SIZE) {
489e3dd5c6f1a1cf9baeb7073fe2ecc5214fdfe0621Theodore Ts'o		if (fix_problem(ctx, PR_2_BAD_ENCRYPTED_NAME, pctx)) {
490e3dd5c6f1a1cf9baeb7073fe2ecc5214fdfe0621Theodore Ts'o			dirent->inode = 0;
491e3dd5c6f1a1cf9baeb7073fe2ecc5214fdfe0621Theodore Ts'o			return 1;
492e3dd5c6f1a1cf9baeb7073fe2ecc5214fdfe0621Theodore Ts'o		}
493e3dd5c6f1a1cf9baeb7073fe2ecc5214fdfe0621Theodore Ts'o		ext2fs_unmark_valid(ctx->fs);
494e3dd5c6f1a1cf9baeb7073fe2ecc5214fdfe0621Theodore Ts'o	}
495e3dd5c6f1a1cf9baeb7073fe2ecc5214fdfe0621Theodore Ts'o	return 0;
496e3dd5c6f1a1cf9baeb7073fe2ecc5214fdfe0621Theodore Ts'o}
497e3dd5c6f1a1cf9baeb7073fe2ecc5214fdfe0621Theodore Ts'o
498aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o/*
499aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o * Check the directory filetype (if present)
500aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o */
501aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'ostatic _INLINE_ int check_filetype(e2fsck_t ctx,
502544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o				   struct ext2_dir_entry *dirent,
503544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o				   ext2_ino_t dir_ino EXT2FS_ATTR((unused)),
504544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o				   struct problem_context *pctx)
505aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o{
50670f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara	int	filetype = ext2fs_dirent_file_type(dirent);
507aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o	int	should_be = EXT2_FT_UNKNOWN;
508aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o	struct ext2_inode	inode;
509aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o
51086f3b6cf98a72c6dad0738e3af2512ddcbd49be9Darrick J. Wong	if (!ext2fs_has_feature_filetype(ctx->fs->super)) {
5117847c1d4fff9195c16b6d74194d104200b3f6c67Theodore Ts'o		if (filetype == 0 ||
5127847c1d4fff9195c16b6d74194d104200b3f6c67Theodore Ts'o		    !fix_problem(ctx, PR_2_CLEAR_FILETYPE, pctx))
5137847c1d4fff9195c16b6d74194d104200b3f6c67Theodore Ts'o			return 0;
51470f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara		ext2fs_dirent_set_file_type(dirent, EXT2_FT_UNKNOWN);
5157847c1d4fff9195c16b6d74194d104200b3f6c67Theodore Ts'o		return 1;
5167847c1d4fff9195c16b6d74194d104200b3f6c67Theodore Ts'o	}
517aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o
518c5d2f50dee996e48e96066155f85d7c925fcba0dValerie Aurora Henson	if (ext2fs_test_inode_bitmap2(ctx->inode_dir_map, dirent->inode)) {
519aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o		should_be = EXT2_FT_DIR;
520c5d2f50dee996e48e96066155f85d7c925fcba0dValerie Aurora Henson	} else if (ext2fs_test_inode_bitmap2(ctx->inode_reg_map,
521aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o					    dirent->inode)) {
522aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o		should_be = EXT2_FT_REG_FILE;
523aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o	} else if (ctx->inode_bad_map &&
524c5d2f50dee996e48e96066155f85d7c925fcba0dValerie Aurora Henson		   ext2fs_test_inode_bitmap2(ctx->inode_bad_map,
525aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o					    dirent->inode))
526aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o		should_be = 0;
527aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o	else {
528aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o		e2fsck_read_inode(ctx, dirent->inode, &inode,
529aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o				  "check_filetype");
5306fdc7a325c8bff67fc3a0489d0858bc7c48dc1a3Theodore Ts'o		should_be = ext2_file_type(inode.i_mode);
531aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o	}
532aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o	if (filetype == should_be)
533aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o		return 0;
534aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o	pctx->num = should_be;
535aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o
536aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o	if (fix_problem(ctx, filetype ? PR_2_BAD_FILETYPE : PR_2_SET_FILETYPE,
537aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o			pctx) == 0)
538aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o		return 0;
539efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
54070f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara	ext2fs_dirent_set_file_type(dirent, should_be);
541aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o	return 1;
542aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o}
543aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o
5448fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'ostatic void parse_int_node(ext2_filsys fs,
5456dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson			   struct ext2_db_entry2 *db,
5468fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			   struct check_dir_struct *cd,
5478fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			   struct dx_dir_info	*dx_dir,
54807307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong			   char *block_buf, int failed_csum)
5498fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o{
5508fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	struct 		ext2_dx_root_info  *root;
5518fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	struct 		ext2_dx_entry *ent;
5528fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	struct		ext2_dx_countlimit *limit;
5538fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	struct dx_dirblock_info	*dx_db;
554ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	int		i, expect_limit, count;
5558fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	blk_t		blk;
5568fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	ext2_dirhash_t	min_hash = 0xffffffff;
5578fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	ext2_dirhash_t	max_hash = 0;
558ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	ext2_dirhash_t	hash = 0, prev_hash;
55907307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong	int		csum_size = 0;
5608fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o
5618fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	if (db->blockcnt == 0) {
5628fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		root = (struct ext2_dx_root_info *) (block_buf + 24);
563efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
5648fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#ifdef DX_DEBUG
5658fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		printf("Root node dump:\n");
5668deb80a5d1078cbe43eaffcdeebf0a1a549d6a54Takashi Sato		printf("\t Reserved zero: %u\n", root->reserved_zero);
5678fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		printf("\t Hash Version: %d\n", root->hash_version);
5688fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		printf("\t Info length: %d\n", root->info_length);
5698fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		printf("\t Indirect levels: %d\n", root->indirect_levels);
5708fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		printf("\t Flags: %d\n", root->unused_flags);
5718fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#endif
5728fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o
5738fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		ent = (struct ext2_dx_entry *) (block_buf + 24 + root->info_length);
57407307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong
57507307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong		if (failed_csum &&
57607307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong		    (e2fsck_dir_will_be_rehashed(cd->ctx, cd->pctx.ino) ||
57707307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong		     fix_problem(cd->ctx, PR_2_HTREE_ROOT_CSUM_INVALID,
57807307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong				&cd->pctx)))
57907307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong			goto clear_and_exit;
5808fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	} else {
5818fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		ent = (struct ext2_dx_entry *) (block_buf+8);
58207307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong
58307307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong		if (failed_csum &&
58407307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong		    (e2fsck_dir_will_be_rehashed(cd->ctx, cd->pctx.ino) ||
58507307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong		     fix_problem(cd->ctx, PR_2_HTREE_NODE_CSUM_INVALID,
58607307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong				&cd->pctx)))
58707307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong			goto clear_and_exit;
5888fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	}
58907307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong
5908fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	limit = (struct ext2_dx_countlimit *) ent;
5918fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o
5928fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#ifdef DX_DEBUG
593efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o	printf("Number of entries (count): %d\n",
5948132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o	       ext2fs_le16_to_cpu(limit->count));
595efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o	printf("Number of entries (limit): %d\n",
5968132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o	       ext2fs_le16_to_cpu(limit->limit));
5978fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#endif
5988fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o
5998132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o	count = ext2fs_le16_to_cpu(limit->count);
60086f3b6cf98a72c6dad0738e3af2512ddcbd49be9Darrick J. Wong	if (ext2fs_has_feature_metadata_csum(fs->super))
60107307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong		csum_size = sizeof(struct ext2_dx_tail);
60207307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong	expect_limit = (fs->blocksize -
60307307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong			(csum_size + ((char *) ent - block_buf))) /
60407307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong		       sizeof(struct ext2_dx_entry);
6058132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o	if (ext2fs_le16_to_cpu(limit->limit) != expect_limit) {
6068132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o		cd->pctx.num = ext2fs_le16_to_cpu(limit->limit);
607ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		if (fix_problem(cd->ctx, PR_2_HTREE_BAD_LIMIT, &cd->pctx))
608ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o			goto clear_and_exit;
609ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	}
6108132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o	if (count > expect_limit) {
6118132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o		cd->pctx.num = count;
612ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		if (fix_problem(cd->ctx, PR_2_HTREE_BAD_COUNT, &cd->pctx))
613ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o			goto clear_and_exit;
614ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		count = expect_limit;
615ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	}
616efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
617ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	for (i=0; i < count; i++) {
618ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		prev_hash = hash;
6198132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o		hash = i ? (ext2fs_le32_to_cpu(ent[i].hash) & ~1) : 0;
6208fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#ifdef DX_DEBUG
6218deb80a5d1078cbe43eaffcdeebf0a1a549d6a54Takashi Sato		printf("Entry #%d: Hash 0x%08x, block %u\n", i,
6228132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o		       hash, ext2fs_le32_to_cpu(ent[i].block));
6238fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#endif
6248132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o		blk = ext2fs_le32_to_cpu(ent[i].block) & 0x0ffffff;
6258fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		/* Check to make sure the block is valid */
626977ac8731bf3bd934421dd8107e77325ec7e6de7Theodore Ts'o		if (blk >= (blk_t) dx_dir->numblocks) {
627b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o			cd->pctx.blk = blk;
6288fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			if (fix_problem(cd->ctx, PR_2_HTREE_BADBLK,
629ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o					&cd->pctx))
630ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o				goto clear_and_exit;
631977ac8731bf3bd934421dd8107e77325ec7e6de7Theodore Ts'o			continue;
6328fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		}
633ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		if (hash < prev_hash &&
634ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		    fix_problem(cd->ctx, PR_2_HTREE_HASH_ORDER, &cd->pctx))
635ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o			goto clear_and_exit;
6368fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		dx_db = &dx_dir->dx_block[blk];
6378fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		if (dx_db->flags & DX_FLAG_REFERENCED) {
6388fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			dx_db->flags |= DX_FLAG_DUP_REF;
6398fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		} else {
6408fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			dx_db->flags |= DX_FLAG_REFERENCED;
6418fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			dx_db->parent = db->blockcnt;
6428fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		}
6438fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		if (hash < min_hash)
6448fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			min_hash = hash;
6458fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		if (hash > max_hash)
6468fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			max_hash = hash;
6478fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		dx_db->node_min_hash = hash;
6488132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o		if ((i+1) < count)
649efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o			dx_db->node_max_hash =
6508132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o			  ext2fs_le32_to_cpu(ent[i+1].hash) & ~1;
6518fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		else {
6528fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			dx_db->node_max_hash = 0xfffffffe;
6538fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			dx_db->flags |= DX_FLAG_LAST;
6548fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		}
6558fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		if (i == 0)
6568fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			dx_db->flags |= DX_FLAG_FIRST;
6578fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	}
6588fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#ifdef DX_DEBUG
6598fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	printf("Blockcnt = %d, min hash 0x%08x, max hash 0x%08x\n",
6608fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	       db->blockcnt, min_hash, max_hash);
6618fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#endif
6628fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	dx_db = &dx_dir->dx_block[db->blockcnt];
6638fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	dx_db->min_hash = min_hash;
6648fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	dx_db->max_hash = max_hash;
665ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	return;
666ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o
667ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'oclear_and_exit:
668ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	clear_htree(cd->ctx, cd->pctx.ino);
669ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	dx_dir->numblocks = 0;
67007307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong	e2fsck_rehash_dir_later(cd->ctx, cd->pctx.ino);
6718fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o}
672aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o
673e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o/*
674e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o * Given a busted directory, try to salvage it somehow.
675efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o *
676e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o */
677ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'ostatic void salvage_directory(ext2_filsys fs,
678e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o			      struct ext2_dir_entry *dirent,
679e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o			      struct ext2_dir_entry *prev,
68082ad476d4709faf9f39a9aa581f9679e8181bbeaDarrick J. Wong			      unsigned int *offset,
68182ad476d4709faf9f39a9aa581f9679e8181bbeaDarrick J. Wong			      unsigned int block_len)
682e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o{
683e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	char	*cp = (char *) dirent;
6848a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o	int left;
6858a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o	unsigned int rec_len, prev_rec_len;
6864a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong	unsigned int name_len;
687e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o
6884a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong	/*
6894a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong	 * If the space left for the entry is too small to be an entry,
6904a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong	 * we can't access dirent's fields, so plumb in the values needed
6914a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong	 * so that the previous entry absorbs this one.
6924a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong	 */
6934a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong	if (block_len - *offset < EXT2_DIR_ENTRY_HEADER_LEN) {
6944a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong		name_len = 0;
6954a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong		rec_len = block_len - *offset;
6964a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong	} else {
6974a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong		name_len = ext2fs_dirent_name_len(dirent);
6984a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong		(void) ext2fs_get_rec_len(fs, dirent, &rec_len);
6994a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong	}
70082ad476d4709faf9f39a9aa581f9679e8181bbeaDarrick J. Wong	left = block_len - *offset - rec_len;
7015dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o
702e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	/*
703e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	 * Special case of directory entry of size 8: copy what's left
704e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	 * of the directory block up to cover up the invalid hole.
705e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	 */
7064a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong	if ((left >= 12) && (rec_len == EXT2_DIR_ENTRY_HEADER_LEN)) {
7074a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong		memmove(cp, cp+EXT2_DIR_ENTRY_HEADER_LEN, left);
7084a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong		memset(cp + left, 0, EXT2_DIR_ENTRY_HEADER_LEN);
709ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		return;
710ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	}
711ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	/*
712ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	 * If the directory entry overruns the end of the directory
713ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	 * block, and the name is small enough to fit, then adjust the
714ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	 * record length.
715ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	 */
716ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	if ((left < 0) &&
7174a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong	    ((int) rec_len + left > EXT2_DIR_ENTRY_HEADER_LEN) &&
7184a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong	    ((int) name_len + EXT2_DIR_ENTRY_HEADER_LEN <= (int) rec_len + left) &&
719ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	    dirent->inode <= fs->super->s_inodes_count &&
720ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	    strnlen(dirent->name, name_len) == name_len) {
7218a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o		(void) ext2fs_set_rec_len(fs, (int) rec_len + left, dirent);
722ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		return;
723e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	}
724e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	/*
725575307cc63d24766ff789262a5cea7b4faf2fa13Kalpak Shah	 * If the record length of the directory entry is a multiple
726575307cc63d24766ff789262a5cea7b4faf2fa13Kalpak Shah	 * of four, and not too big, such that it is valid, let the
727575307cc63d24766ff789262a5cea7b4faf2fa13Kalpak Shah	 * previous directory entry absorb the invalid one.
728e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	 */
7295dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o	if (prev && rec_len && (rec_len % 4) == 0 &&
73082ad476d4709faf9f39a9aa581f9679e8181bbeaDarrick J. Wong	    (*offset + rec_len <= block_len)) {
7318a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o		(void) ext2fs_get_rec_len(fs, prev, &prev_rec_len);
7328a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o		prev_rec_len += rec_len;
7338a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o		(void) ext2fs_set_rec_len(fs, prev_rec_len, prev);
7345dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o		*offset += rec_len;
735ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		return;
736e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	}
737e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	/*
738e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	 * Default salvage method --- kill all of the directory
739e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	 * entries for the rest of the block.  We will either try to
740e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	 * absorb it into the previous directory entry, or create a
741e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	 * new empty directory entry the rest of the directory block.
742e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	 */
743e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	if (prev) {
7448a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o		(void) ext2fs_get_rec_len(fs, prev, &prev_rec_len);
74582ad476d4709faf9f39a9aa581f9679e8181bbeaDarrick J. Wong		prev_rec_len += block_len - *offset;
7468a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o		(void) ext2fs_set_rec_len(fs, prev_rec_len, prev);
747ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		*offset = fs->blocksize;
748e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	} else {
74982ad476d4709faf9f39a9aa581f9679e8181bbeaDarrick J. Wong		rec_len = block_len - *offset;
7508a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o		(void) ext2fs_set_rec_len(fs, rec_len, dirent);
75170f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara		ext2fs_dirent_set_name_len(dirent, 0);
75270f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara		ext2fs_dirent_set_file_type(dirent, EXT2_FT_UNKNOWN);
753e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o		dirent->inode = 0;
754e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	}
755e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o}
756e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o
757d3eb1502fd07a4c751d20ad5fa4b75bfda039d52Darrick J. Wong#define NEXT_DIRENT(d)	((void *)((char *)(d) + (d)->rec_len))
75817641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wongstatic errcode_t insert_dirent_tail(ext2_filsys fs, void *dirbuf)
75917641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong{
76017641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong	struct ext2_dir_entry *d;
76117641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong	void *top;
76217641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong	struct ext2_dir_entry_tail *t;
76317641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong
76417641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong	d = dirbuf;
76517641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong	top = EXT2_DIRENT_TAIL(dirbuf, fs->blocksize);
76617641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong
767d3eb1502fd07a4c751d20ad5fa4b75bfda039d52Darrick J. Wong	while (d->rec_len && !(d->rec_len & 0x3) && NEXT_DIRENT(d) <= top)
768d3eb1502fd07a4c751d20ad5fa4b75bfda039d52Darrick J. Wong		d = NEXT_DIRENT(d);
76917641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong
77017641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong	if (d != top) {
77162f9bd0e4f7547fe01f829025888d477a973a539Theodore Ts'o		unsigned int min_size = EXT2_DIR_REC_LEN(
77217641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong				ext2fs_dirent_name_len(dirbuf));
77362f9bd0e4f7547fe01f829025888d477a973a539Theodore Ts'o		if (min_size > (char *)top - (char *)d)
77417641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong			return EXT2_ET_DIR_NO_SPACE_FOR_CSUM;
77562f9bd0e4f7547fe01f829025888d477a973a539Theodore Ts'o		d->rec_len = (char *)top - (char *)d;
77617641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong	}
77717641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong
77817641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong	t = (struct ext2_dir_entry_tail *)top;
77917641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong	if (t->det_reserved_zero1 ||
78017641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong	    t->det_rec_len != sizeof(struct ext2_dir_entry_tail) ||
78117641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong	    t->det_reserved_name_len != EXT2_DIR_NAME_LEN_CSUM)
78217641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong		ext2fs_initialize_dirent_tail(fs, t);
78317641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong
78417641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong	return 0;
78517641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong}
786d3eb1502fd07a4c751d20ad5fa4b75bfda039d52Darrick J. Wong#undef NEXT_DIRENT
78717641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong
78852b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wongstatic errcode_t fix_inline_dir_size(e2fsck_t ctx, ext2_ino_t ino,
78952b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong				     size_t *inline_data_size,
79052b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong				     struct problem_context *pctx,
79152b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong				     char *buf)
79252b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong{
79352b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	ext2_filsys fs = ctx->fs;
79452b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	struct ext2_inode inode;
79552b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	size_t new_size, old_size;
79652b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	errcode_t retval;
79752b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong
79852b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	old_size = *inline_data_size;
7990ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong	/*
8000ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong	 * If there's not enough bytes to start the "second" dir block
8010ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong	 * (in the EA space) then truncate everything to the first block.
8020ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong	 */
8030ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong	if (old_size > EXT4_MIN_INLINE_DATA_SIZE &&
8040ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong	    old_size < EXT4_MIN_INLINE_DATA_SIZE +
8050ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong		       EXT2_DIR_REC_LEN(1)) {
8060ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong		old_size = EXT4_MIN_INLINE_DATA_SIZE;
8070ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong		new_size = old_size;
8080ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong	} else
8090ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong		/* Increase to the next four-byte boundary for salvaging */
8100ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong		new_size = old_size + (4 - (old_size & 3));
81152b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	memset(buf + old_size, 0, new_size - old_size);
81252b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	retval = ext2fs_inline_data_set(fs, ino, 0, buf, new_size);
81352b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	if (retval == EXT2_ET_INLINE_DATA_NO_SPACE) {
8140ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong		/* Or we can't, so truncate. */
81552b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong		new_size -= 4;
81652b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong		retval = ext2fs_inline_data_set(fs, ino, 0, buf, new_size);
81752b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong		if (retval) {
81852b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong			if (fix_problem(ctx, PR_2_FIX_INLINE_DIR_FAILED,
81952b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong					pctx)) {
82052b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong				new_size = 0;
82152b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong				goto write_inode;
82252b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong			}
82352b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong			goto err;
82452b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong		}
82552b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	} else if (retval) {
82652b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong		if (fix_problem(ctx, PR_2_FIX_INLINE_DIR_FAILED,
82752b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong				pctx)) {
82852b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong			new_size = 0;
82952b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong			goto write_inode;
83052b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong		}
83152b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong		goto err;
83252b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	}
83352b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong
83452b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wongwrite_inode:
83552b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	retval = ext2fs_read_inode(fs, ino, &inode);
83652b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	if (retval)
83752b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong		goto err;
83852b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong
83952b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	retval = ext2fs_inode_size_set(fs, &inode, new_size);
84052b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	if (retval)
84152b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong		goto err;
84252b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	if (new_size == 0)
84352b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong		inode.i_flags &= ~EXT4_INLINE_DATA_FL;
84452b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	retval = ext2fs_write_inode(fs, ino, &inode);
84552b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	if (retval)
84652b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong		goto err;
84752b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	*inline_data_size = new_size;
84852b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong
84952b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wongerr:
85052b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	return retval;
85152b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong}
85252b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong
853a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wongstatic int check_dir_block2(ext2_filsys fs,
854a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong			   struct ext2_db_entry2 *db,
855a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong			   void *priv_data)
856a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong{
857a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong	int err;
858a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong	struct check_dir_struct *cd = priv_data;
859a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong
860a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong	if (cd->ra_entries && cd->list_offset >= cd->next_ra_off) {
861a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong		err = e2fsck_readahead_dblist(fs,
862a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong					E2FSCK_RA_DBLIST_IGNORE_BLOCKCNT,
863a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong					fs->dblist,
864a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong					cd->list_offset + cd->ra_entries / 8,
865a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong					cd->ra_entries);
866a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong		if (err)
867a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong			cd->ra_entries = 0;
868a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong		cd->next_ra_off = cd->list_offset + (cd->ra_entries * 7 / 8);
869a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong	}
870a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong
871a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong	err = check_dir_block(fs, db, priv_data);
872a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong	cd->list_offset++;
873a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong	return err;
874a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong}
875a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong
8763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic int check_dir_block(ext2_filsys fs,
8776dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson			   struct ext2_db_entry2 *db,
87854dc7ca2869897ae8cb81a9ab9880ebff11680bcTheodore Ts'o			   void *priv_data)
8793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
8808fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o 	struct dx_dir_info	*dx_dir;
8818fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	struct dx_dirblock_info	*dx_db = 0;
8826582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu	struct ext2_dir_entry 	*dirent, *prev, dot, dotdot;
8838fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	ext2_dirhash_t		hash;
884544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	unsigned int		offset = 0;
8853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int			dir_modified = 0;
88621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	int			dot_state;
88703fa6f8ae28a87018325c892f731097cc97d9eacTheodore Ts'o	unsigned int		rec_len;
8886dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson	blk64_t			block_nr = db->blk;
88986c627ec1136446409a0170d439e60c148e6eb48Theodore Ts'o	ext2_ino_t 		ino = db->ino;
89028db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o	ext2_ino_t 		subdir_parent;
89121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	__u16			links;
89254dc7ca2869897ae8cb81a9ab9880ebff11680bcTheodore Ts'o	struct check_dir_struct	*cd;
8930ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong	char			*buf, *ibuf;
8941b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	e2fsck_t		ctx;
8953c7c6d73f1a0bd45835966f1179fc3e8236a7d9cTheodore Ts'o	problem_t		problem;
896ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o	struct ext2_dx_root_info *root;
897e8254bfd3b49cb325a1ff6b21ca86570a1008744Theodore Ts'o	struct ext2_dx_countlimit *limit;
8980926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o	static dict_t de_dict;
8990926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o	struct problem_context	pctx;
9000926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o	int	dups_found = 0;
90128db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o	int	ret;
902e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong	int	dx_csum_size = 0, de_csum_size = 0;
90381683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	int	failed_csum = 0;
904e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong	int	is_leaf = 1;
90524997f1cd2b3c3ea7a5a2c7fe37013de36a6d8a3Darrick J. Wong	size_t	inline_data_size = 0;
9066582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu	int	filetype = 0;
90762ad24802c6e9abd0acf3e6d12aeaab3ae8c6f5aTheodore Ts'o	int	encrypted = 0;
9080ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong	size_t	max_block_size;
9091b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o
91054dc7ca2869897ae8cb81a9ab9880ebff11680bcTheodore Ts'o	cd = (struct check_dir_struct *) priv_data;
9110ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong	ibuf = buf = cd->buf;
9121b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ctx = cd->ctx;
913f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o
914db3d8718be6ad3bdd252b242827fa54914b8ec2eAndreas Dilger	if (ctx->flags & E2F_FLAG_RUN_RETURN)
9154cae04529eda0e482ceaa86b48e532f9c8d35f24Theodore Ts'o		return DIRENT_ABORT;
916efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
9174cae04529eda0e482ceaa86b48e532f9c8d35f24Theodore Ts'o	if (ctx->progress && (ctx->progress)(ctx, 2, cd->count++, cd->max))
9184cae04529eda0e482ceaa86b48e532f9c8d35f24Theodore Ts'o		return DIRENT_ABORT;
919efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
92086f3b6cf98a72c6dad0738e3af2512ddcbd49be9Darrick J. Wong	if (ext2fs_has_feature_metadata_csum(fs->super)) {
92107307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong		dx_csum_size = sizeof(struct ext2_dx_tail);
922e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong		de_csum_size = sizeof(struct ext2_dir_entry_tail);
923e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong	}
92407307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong
92586f3b6cf98a72c6dad0738e3af2512ddcbd49be9Darrick J. Wong	if (ext2fs_has_feature_filetype(fs->super))
9266582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu		filetype = EXT2_FT_DIR << 8;
9276582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu
9283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
929efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o	 * Make sure the inode is still in use (could have been
9303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * deleted in the duplicate/bad blocks pass.
9313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
932c5d2f50dee996e48e96066155f85d7c925fcba0dValerie Aurora Henson	if (!(ext2fs_test_inode_bitmap2(ctx->inode_used_map, ino)))
9333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
93450e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o
93521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	cd->pctx.ino = ino;
93621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	cd->pctx.blk = block_nr;
93721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	cd->pctx.blkcount = db->blockcnt;
93821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	cd->pctx.ino2 = 0;
93921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	cd->pctx.dirent = 0;
94021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	cd->pctx.num = 0;
94121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o
94286f3b6cf98a72c6dad0738e3af2512ddcbd49be9Darrick J. Wong	if (ext2fs_has_feature_inline_data(fs->super)) {
9436582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu		errcode_t ec;
9446582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu
9456582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu		ec = ext2fs_inline_data_size(fs, ino, &inline_data_size);
9466582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu		if (ec && ec != EXT2_ET_NO_INLINE_DATA)
9476582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu			return DIRENT_ABORT;
9486582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu	}
9496582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu
9506582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu	if (db->blk == 0 && !inline_data_size) {
9511b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		if (allocate_dir_block(ctx, db, buf, &cd->pctx))
95250e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o			return 0;
95350e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o		block_nr = db->blk;
95450e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	}
955efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
9563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (db->blockcnt)
9573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		dot_state = 2;
9583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	else
9593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		dot_state = 0;
9603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
9610926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o	if (ctx->dirs_to_hash &&
9620926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o	    ext2fs_u32_list_test(ctx->dirs_to_hash, ino))
9630926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o		dups_found++;
9640926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o
9653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#if 0
966f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	printf("In process_dir_block block %lu, #%d, inode %lu\n", block_nr,
9673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	       db->blockcnt, ino);
9683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#endif
969efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
970f85a9ae6397ff074193322a12ed721dbf5751e41Eric Sandeen	ehandler_operation(_("reading directory block"));
971cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong	if (inline_data_size) {
9724a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong		memset(buf, 0, fs->blocksize - inline_data_size);
9736582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu		cd->pctx.errcode = ext2fs_inline_data_get(fs, ino, 0, buf, 0);
974cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong		if (cd->pctx.errcode)
975cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong			goto inline_read_fail;
976cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong#ifdef WORDS_BIGENDIAN
9770ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong		if (db->blockcnt)
9780ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong			goto skip_first_read_swab;
979cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong		*((__u32 *)buf) = ext2fs_le32_to_cpu(*((__u32 *)buf));
980cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong		cd->pctx.errcode = ext2fs_dirent_swab_in2(fs,
981cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong				buf + EXT4_INLINE_DATA_DOTDOT_SIZE,
9820ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong				EXT4_MIN_INLINE_DATA_SIZE - EXT4_INLINE_DATA_DOTDOT_SIZE,
9830ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong				0);
9840ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong		if (cd->pctx.errcode)
9850ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong			goto inline_read_fail;
9860ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wongskip_first_read_swab:
9870ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong		if (inline_data_size <= EXT4_MIN_INLINE_DATA_SIZE ||
9880ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong		    !db->blockcnt)
9890ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong			goto inline_read_fail;
9900ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong		cd->pctx.errcode = ext2fs_dirent_swab_in2(fs,
9910ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong				buf + EXT4_MIN_INLINE_DATA_SIZE,
9920ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong				inline_data_size - EXT4_MIN_INLINE_DATA_SIZE,
993cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong				0);
994cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong#endif
995cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong	} else
9966582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu		cd->pctx.errcode = ext2fs_read_dir_block4(fs, block_nr,
9976582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu							  buf, 0, ino);
998cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wonginline_read_fail:
99952b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	pctx.ino = ino;
100052b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	pctx.num = inline_data_size;
10010ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong	if (((inline_data_size & 3) ||
10020ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong	     (inline_data_size > EXT4_MIN_INLINE_DATA_SIZE &&
10030ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong	      inline_data_size < EXT4_MIN_INLINE_DATA_SIZE +
10040ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong				 EXT2_DIR_REC_LEN(1))) &&
100552b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	    fix_problem(ctx, PR_2_BAD_INLINE_DIR_SIZE, &pctx)) {
100652b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong		errcode_t err = fix_inline_dir_size(ctx, ino,
100752b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong						    &inline_data_size, &pctx,
100852b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong						    buf);
100952b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong		if (err)
101052b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong			return DIRENT_ABORT;
101152b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong
101252b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	}
1013e94bc631648299dca43a6015520b18f6232d50dfTheodore Ts'o	ehandler_operation(0);
1014b9852cd87b42f79d569db68c3fdefe4a8f48ede1Theodore Ts'o	if (cd->pctx.errcode == EXT2_ET_DIR_CORRUPTED)
1015b9852cd87b42f79d569db68c3fdefe4a8f48ede1Theodore Ts'o		cd->pctx.errcode = 0; /* We'll handle this ourselves */
101681683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	else if (cd->pctx.errcode == EXT2_ET_DIR_CSUM_INVALID) {
101781683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong		cd->pctx.errcode = 0; /* We'll handle this ourselves */
101881683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong		failed_csum = 1;
101981683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	}
10201b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (cd->pctx.errcode) {
1021e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong		char *buf2;
102208b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		if (!fix_problem(ctx, PR_2_READ_DIRBLOCK, &cd->pctx)) {
102308b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o			ctx->flags |= E2F_FLAG_ABORT;
102408b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o			return DIRENT_ABORT;
102508b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		}
1026e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong		ext2fs_new_dir_block(fs, db->blockcnt == 0 ? ino : 0,
1027e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong				     EXT2_ROOT_INO, &buf2);
1028e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong		memcpy(buf, buf2, fs->blocksize);
1029e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong		ext2fs_free_mem(&buf2);
10303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
10318fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	dx_dir = e2fsck_get_dx_dir_info(ctx, ino);
103262acaa1de132a808949d71264731bba7fe095705Theodore Ts'o	if (dx_dir && dx_dir->numblocks) {
10338fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		if (db->blockcnt >= dx_dir->numblocks) {
1034ea9085c711e92c3727538a0637bc805141333d83Darrick J. Wong			pctx.dir = ino;
1035efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o			if (fix_problem(ctx, PR_2_UNEXPECTED_HTREE_BLOCK,
1036d45edec0fb2e5d100d122fdda0914560c64def44Theodore Ts'o					&pctx)) {
1037d45edec0fb2e5d100d122fdda0914560c64def44Theodore Ts'o				clear_htree(ctx, ino);
1038d45edec0fb2e5d100d122fdda0914560c64def44Theodore Ts'o				dx_dir->numblocks = 0;
1039d45edec0fb2e5d100d122fdda0914560c64def44Theodore Ts'o				dx_db = 0;
1040d45edec0fb2e5d100d122fdda0914560c64def44Theodore Ts'o				goto out_htree;
1041d45edec0fb2e5d100d122fdda0914560c64def44Theodore Ts'o			}
1042d45edec0fb2e5d100d122fdda0914560c64def44Theodore Ts'o			fatal_error(ctx, _("Can not continue."));
10438fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		}
10448fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		dx_db = &dx_dir->dx_block[db->blockcnt];
10458fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		dx_db->type = DX_DIRBLOCK_LEAF;
10468fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		dx_db->phys = block_nr;
10478fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		dx_db->min_hash = ~0;
10488fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		dx_db->max_hash = 0;
1049efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
10508fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		dirent = (struct ext2_dir_entry *) buf;
10518a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o		(void) ext2fs_get_rec_len(fs, dirent, &rec_len);
1052e8254bfd3b49cb325a1ff6b21ca86570a1008744Theodore Ts'o		limit = (struct ext2_dx_countlimit *) (buf+8);
10538fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		if (db->blockcnt == 0) {
1054ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o			root = (struct ext2_dx_root_info *) (buf + 24);
10558fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			dx_db->type = DX_DIRBLOCK_ROOT;
10568fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			dx_db->flags |= DX_FLAG_FIRST | DX_FLAG_LAST;
1057ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o			if ((root->reserved_zero ||
1058ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o			     root->info_length < 8 ||
1059ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o			     root->indirect_levels > 1) &&
1060ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o			    fix_problem(ctx, PR_2_HTREE_BAD_ROOT, &cd->pctx)) {
1061ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o				clear_htree(ctx, ino);
1062ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o				dx_dir->numblocks = 0;
1063ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o				dx_db = 0;
1064f77704e416fca7dbe4cc91abba674d2ae3c14f6fTheodore Ts'o			}
1065ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o			dx_dir->hashversion = root->hash_version;
1066f77704e416fca7dbe4cc91abba674d2ae3c14f6fTheodore Ts'o			if ((dx_dir->hashversion <= EXT2_HASH_TEA) &&
1067f77704e416fca7dbe4cc91abba674d2ae3c14f6fTheodore Ts'o			    (fs->super->s_flags & EXT2_FLAGS_UNSIGNED_HASH))
1068f77704e416fca7dbe4cc91abba674d2ae3c14f6fTheodore Ts'o				dx_dir->hashversion += 3;
1069ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o			dx_dir->depth = root->indirect_levels + 1;
10708fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		} else if ((dirent->inode == 0) &&
10715dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o			   (rec_len == fs->blocksize) &&
107270f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara			   (ext2fs_dirent_name_len(dirent) == 0) &&
1073efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o			   (ext2fs_le16_to_cpu(limit->limit) ==
107407307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong			    ((fs->blocksize - (8 + dx_csum_size)) /
10758132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o			     sizeof(struct ext2_dx_entry))))
10768fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			dx_db->type = DX_DIRBLOCK_NODE;
107795eca2e9228841496a5864605259bf908a5b2d0aDarrick J. Wong		is_leaf = (dx_db->type == DX_DIRBLOCK_LEAF);
10788fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	}
1079d45edec0fb2e5d100d122fdda0914560c64def44Theodore Ts'oout_htree:
10803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
10817f43a46fad362435f8420f656c6157dc8be8dd4dDarrick J. Wong	/* Leaf node with no space for csum?  Rebuild dirs in pass 3A. */
10827f43a46fad362435f8420f656c6157dc8be8dd4dDarrick J. Wong	if (is_leaf && !inline_data_size && failed_csum &&
10837f43a46fad362435f8420f656c6157dc8be8dd4dDarrick J. Wong	    !ext2fs_dirent_has_tail(fs, (struct ext2_dir_entry *)buf)) {
10847f43a46fad362435f8420f656c6157dc8be8dd4dDarrick J. Wong		de_csum_size = 0;
1085d02d019557d993c8dfe2f7d0fea841101f0d9e61Darrick J. Wong		if (e2fsck_dir_will_be_rehashed(ctx, ino)) {
1086d02d019557d993c8dfe2f7d0fea841101f0d9e61Darrick J. Wong			failed_csum = 0;
1087d02d019557d993c8dfe2f7d0fea841101f0d9e61Darrick J. Wong			goto skip_checksum;
1088d02d019557d993c8dfe2f7d0fea841101f0d9e61Darrick J. Wong		}
1089d02d019557d993c8dfe2f7d0fea841101f0d9e61Darrick J. Wong		if (!fix_problem(cd->ctx, PR_2_LEAF_NODE_MISSING_CSUM,
10907f43a46fad362435f8420f656c6157dc8be8dd4dDarrick J. Wong				 &cd->pctx))
1091e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong			goto skip_checksum;
10927f43a46fad362435f8420f656c6157dc8be8dd4dDarrick J. Wong		e2fsck_rehash_dir_later(ctx, ino);
1093d02d019557d993c8dfe2f7d0fea841101f0d9e61Darrick J. Wong		failed_csum = 0;
10947f43a46fad362435f8420f656c6157dc8be8dd4dDarrick J. Wong		goto skip_checksum;
1095e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong	}
1096e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong	/* htree nodes don't use fake dirents to store checksums */
1097e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong	if (!is_leaf)
1098e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong		de_csum_size = 0;
1099e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong
1100e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wongskip_checksum:
11010ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong	if (inline_data_size) {
11020ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong		if (db->blockcnt) {
11030ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong			buf += EXT4_MIN_INLINE_DATA_SIZE;
11040ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong			max_block_size = inline_data_size - EXT4_MIN_INLINE_DATA_SIZE;
11050ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong			/* Zero-length second block, just exit */
11060ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong			if (max_block_size == 0)
11070ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong				return 0;
11080ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong		} else {
11090ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong			max_block_size = EXT4_MIN_INLINE_DATA_SIZE;
11100ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong		}
11110ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong	} else
11120ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong		max_block_size = fs->blocksize - de_csum_size;
11130ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong
111462ad24802c6e9abd0acf3e6d12aeaab3ae8c6f5aTheodore Ts'o	if (ctx->encrypted_dirs)
111562ad24802c6e9abd0acf3e6d12aeaab3ae8c6f5aTheodore Ts'o		encrypted = ext2fs_u32_list_test(ctx->encrypted_dirs, ino);
111662ad24802c6e9abd0acf3e6d12aeaab3ae8c6f5aTheodore Ts'o
11170926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o	dict_init(&de_dict, DICTCOUNT_T_MAX, dict_de_cmp);
1118e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	prev = 0;
11193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	do {
11203971bfe878d6c30f9b5be3a2c0310943982a4775Theodore Ts'o		dgrp_t group;
112149a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos		ext2_ino_t first_unused_inode;
112270f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara		unsigned int name_len;
112349a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos
11241b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		problem = 0;
11256582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu		if (!inline_data_size || dot_state > 1) {
11266582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu			dirent = (struct ext2_dir_entry *) (buf + offset);
11274a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong			/*
11284a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong			 * If there's not even space for the entry header,
11294a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong			 * force salvaging this dir.
11304a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong			 */
11314a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong			if (max_block_size - offset < EXT2_DIR_ENTRY_HEADER_LEN)
11324a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong				rec_len = EXT2_DIR_REC_LEN(1);
11334a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong			else
11344a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong				(void) ext2fs_get_rec_len(fs, dirent, &rec_len);
11356582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu			cd->pctx.dirent = dirent;
11366582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu			cd->pctx.num = offset;
11374a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong			if ((offset + rec_len > max_block_size) ||
11386582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu			    (rec_len < 12) ||
11396582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu			    ((rec_len % 4) != 0) ||
114062f9bd0e4f7547fe01f829025888d477a973a539Theodore Ts'o			    (((unsigned) ext2fs_dirent_name_len(dirent) + EXT2_DIR_ENTRY_HEADER_LEN) > rec_len)) {
114182ad476d4709faf9f39a9aa581f9679e8181bbeaDarrick J. Wong				if (fix_problem(ctx, PR_2_DIR_CORRUPTED,
114282ad476d4709faf9f39a9aa581f9679e8181bbeaDarrick J. Wong						&cd->pctx)) {
11434348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong#ifdef WORDS_BIGENDIAN
11444348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong					/*
11454348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong					 * On big-endian systems, if the dirent
11464348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong					 * swap routine finds a rec_len that it
11474348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong					 * doesn't like, it continues
11484348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong					 * processing the block as if rec_len
11494a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong					 * == EXT2_DIR_ENTRY_HEADER_LEN.  This means that the name
11504348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong					 * field gets byte swapped, which means
11514348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong					 * that salvage will not detect the
11524348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong					 * correct name length (unless the name
11534348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong					 * has a length that's an exact
11544348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong					 * multiple of four bytes), and it'll
11554348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong					 * discard the entry (unnecessarily)
11564348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong					 * and the rest of the dirent block.
11574348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong					 * Therefore, swap the rest of the
11584348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong					 * block back to disk order, run
11594348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong					 * salvage, and re-swap anything after
11604348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong					 * the salvaged dirent.
11614348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong					 */
11624348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong					int need_reswab = 0;
11634a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong					if (rec_len < EXT2_DIR_ENTRY_HEADER_LEN || rec_len % 4) {
11644348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong						need_reswab = 1;
11654348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong						ext2fs_dirent_swab_in2(fs,
11664a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong							((char *)dirent) + EXT2_DIR_ENTRY_HEADER_LEN,
11674a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong							max_block_size - offset - EXT2_DIR_ENTRY_HEADER_LEN,
11684348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong							0);
11694348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong					}
11704348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong#endif
117182ad476d4709faf9f39a9aa581f9679e8181bbeaDarrick J. Wong					salvage_directory(fs, dirent, prev,
117282ad476d4709faf9f39a9aa581f9679e8181bbeaDarrick J. Wong							  &offset,
11733a748dfc1cc28878b5c0ffc1042c3efb3d26360eDarrick J. Wong							  max_block_size);
11744348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong#ifdef WORDS_BIGENDIAN
11754348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong					if (need_reswab) {
11764348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong						(void) ext2fs_get_rec_len(fs,
11774348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong							dirent, &rec_len);
11784348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong						ext2fs_dirent_swab_in2(fs,
11794348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong							((char *)dirent) + offset + rec_len,
11804348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong							max_block_size - offset - rec_len,
11814348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong							0);
11824348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong					}
11834348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong#endif
11846582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu					dir_modified++;
11856582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu					continue;
11866582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu				} else
11876582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu					goto abort_free_dict;
11886582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu			}
11896582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu		} else {
11906582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu			if (dot_state == 0) {
11916582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu				memset(&dot, 0, sizeof(dot));
11926582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu				dirent = &dot;
11936582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu				dirent->inode = ino;
11946582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu				dirent->rec_len = EXT2_DIR_REC_LEN(1);
11956582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu				dirent->name_len = 1 | filetype;
11966582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu				dirent->name[0] = '.';
11976582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu			} else if (dot_state == 1) {
11986582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu				memset(&dotdot, 0, sizeof(dotdot));
11996582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu				dirent = &dotdot;
12006582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu				dirent->inode =
12016582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu					((struct ext2_dir_entry *)buf)->inode;
12026582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu				dirent->rec_len = EXT2_DIR_REC_LEN(2);
12036582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu				dirent->name_len = 2 | filetype;
12046582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu				dirent->name[0] = '.';
12056582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu				dirent->name[1] = '.';
12066582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu			} else {
12076582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu				fatal_error(ctx, _("Can not continue."));
12086582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu			}
12096582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu			cd->pctx.dirent = dirent;
12106582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu			cd->pctx.num = offset;
12113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
121250e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o
1213e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o		if (dot_state == 0) {
12141b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			if (check_dot(ctx, dirent, ino, &cd->pctx))
12153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				dir_modified++;
1216e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o		} else if (dot_state == 1) {
121728db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o			ret = check_dotdot(ctx, dirent, ino, &cd->pctx);
121828db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o			if (ret < 0)
12190926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o				goto abort_free_dict;
122028db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o			if (ret)
12213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				dir_modified++;
12223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		} else if (dirent->inode == ino) {
12231b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			problem = PR_2_LINK_DOT;
12241b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			if (fix_problem(ctx, PR_2_LINK_DOT, &cd->pctx)) {
12253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				dirent->inode = 0;
12263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				dir_modified++;
122721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o				goto next;
12283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			}
12293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
1230efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o		if (!dirent->inode)
12313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			goto next;
1232efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
12333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		/*
12343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * Make sure the inode listed is a legal one.
1235efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o		 */
123670f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara		name_len = ext2fs_dirent_name_len(dirent);
12373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (((dirent->inode != EXT2_ROOT_INO) &&
12387f88b04341d88c5df0360d930832c38040303b61Theodore Ts'o		     (dirent->inode < EXT2_FIRST_INODE(fs->super))) ||
12393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		    (dirent->inode > fs->super->s_inodes_count)) {
12401b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			problem = PR_2_BAD_INO;
12411b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		} else if (ctx->inode_bb_map &&
1242c5d2f50dee996e48e96066155f85d7c925fcba0dValerie Aurora Henson			   (ext2fs_test_inode_bitmap2(ctx->inode_bb_map,
12431b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o						     dirent->inode))) {
12441b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			/*
12451b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 * If the inode is in a bad block, offer to
12461b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 * clear it.
12471b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 */
12481b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			problem = PR_2_BB_INODE;
124970f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara		} else if ((dot_state > 1) && (name_len == 1) &&
12501b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			   (dirent->name[0] == '.')) {
12511b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			/*
12521b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 * If there's a '.' entry in anything other
12531b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 * than the first directory entry, it's a
12541b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 * duplicate entry that should be removed.
12551b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 */
12561b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			problem = PR_2_DUP_DOT;
125770f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara		} else if ((dot_state > 1) && (name_len == 2) &&
1258efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o			   (dirent->name[0] == '.') &&
12591b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			   (dirent->name[1] == '.')) {
12601b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			/*
12611b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 * If there's a '..' entry in anything other
12621b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 * than the second directory entry, it's a
12631b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 * duplicate entry that should be removed.
12641b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 */
12651b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			problem = PR_2_DUP_DOT_DOT;
1266e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o		} else if ((dot_state > 1) &&
12671b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			   (dirent->inode == EXT2_ROOT_INO)) {
12681b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			/*
12691b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 * Don't allow links to the root directory.
12701b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 * We check this specially to make sure we
12711b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 * catch this error case even if the root
12721b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 * directory hasn't been created yet.
12731b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 */
12741b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			problem = PR_2_LINK_ROOT;
127570f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara		} else if ((dot_state > 1) && (name_len == 0)) {
1276c40db6d5717023bdd6bb4935161e7ce9678d6234Theodore Ts'o			/*
1277c40db6d5717023bdd6bb4935161e7ce9678d6234Theodore Ts'o			 * Don't allow zero-length directory names.
1278c40db6d5717023bdd6bb4935161e7ce9678d6234Theodore Ts'o			 */
1279c40db6d5717023bdd6bb4935161e7ce9678d6234Theodore Ts'o			problem = PR_2_NULL_NAME;
128021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		}
128121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o
12821b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		if (problem) {
12831b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			if (fix_problem(ctx, problem, &cd->pctx)) {
128421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o				dirent->inode = 0;
128521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o				dir_modified++;
128621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o				goto next;
12871b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			} else {
12881b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o				ext2fs_unmark_valid(fs);
12891b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o				if (problem == PR_2_BAD_INO)
12901b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o					goto next;
129121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			}
12923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
12933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
12943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		/*
12953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * If the inode was marked as having bad fields in
12963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * pass1, process it and offer to fix/clear it.
12973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * (We wait until now so that we can display the
12983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * pathname to the user.)
12993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 */
13001b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		if (ctx->inode_bad_map &&
1301c5d2f50dee996e48e96066155f85d7c925fcba0dValerie Aurora Henson		    ext2fs_test_inode_bitmap2(ctx->inode_bad_map,
13023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o					     dirent->inode)) {
1303e72a9ba39471364ad2f9397f645ca547090e3485Theodore Ts'o			if (e2fsck_process_bad_inode(ctx, ino,
1304bcf9c5d4016975c3c2afdb4a4b358569bd3c8681Theodore Ts'o						     dirent->inode,
1305bcf9c5d4016975c3c2afdb4a4b358569bd3c8681Theodore Ts'o						     buf + fs->blocksize)) {
13063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				dirent->inode = 0;
13073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				dir_modified++;
13083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				goto next;
13093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			}
1310a02ce9df5ff5db2982462aec7162f7142dc18131Theodore Ts'o			if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
131108b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o				return DIRENT_ABORT;
13123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
13133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
131449a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos		group = ext2fs_group_of_ino(fs, dirent->inode);
131549a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos		first_unused_inode = group * fs->super->s_inodes_per_group +
131649a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos					1 + fs->super->s_inodes_per_group -
1317d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson					ext2fs_bg_itable_unused(fs, group);
131849a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos		cd->pctx.group = group;
131949a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos
132049a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos		/*
132142e89ce7f8823ad14099b03469c2f4e4f6530d05Theodore Ts'o		 * Check if the inode was missed out because
132242e89ce7f8823ad14099b03469c2f4e4f6530d05Theodore Ts'o		 * _INODE_UNINIT flag was set or bg_itable_unused was
132342e89ce7f8823ad14099b03469c2f4e4f6530d05Theodore Ts'o		 * incorrect.  If so, clear the _INODE_UNINIT flag and
132442e89ce7f8823ad14099b03469c2f4e4f6530d05Theodore Ts'o		 * restart e2fsck.  In the future it would be nice if
132542e89ce7f8823ad14099b03469c2f4e4f6530d05Theodore Ts'o		 * we could call a function in pass1.c that checks the
132642e89ce7f8823ad14099b03469c2f4e4f6530d05Theodore Ts'o		 * newly visible inodes.
132749a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos		 */
1328cd65a24e756b8f6770a5961fd94c67eb00dd7baaTheodore Ts'o		if (ext2fs_bg_flags_test(fs, group, EXT2_BG_INODE_UNINIT)) {
13296267ee49be64035d8a9772c3bafed18a09874fa5Andreas Dilger			pctx.num = dirent->inode;
133049a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos			if (fix_problem(ctx, PR_2_INOREF_BG_INO_UNINIT,
133149a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos					&cd->pctx)){
1332e633b58ac75f2f544b7d6572e37d4b63da31e59cEric Sandeen				ext2fs_bg_flags_clear(fs, group,
1333732c8cd58ff30ffae0d3276c411a08920717a46cTheodore Ts'o						      EXT2_BG_INODE_UNINIT);
133442e89ce7f8823ad14099b03469c2f4e4f6530d05Theodore Ts'o				ext2fs_mark_super_dirty(fs);
13356267ee49be64035d8a9772c3bafed18a09874fa5Andreas Dilger				ctx->flags |= E2F_FLAG_RESTART_LATER;
133649a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos			} else {
133749a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos				ext2fs_unmark_valid(fs);
133849a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos				if (problem == PR_2_BAD_INO)
133949a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos					goto next;
134049a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos			}
134149a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos		} else if (dirent->inode >= first_unused_inode) {
13426267ee49be64035d8a9772c3bafed18a09874fa5Andreas Dilger			pctx.num = dirent->inode;
134349a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos			if (fix_problem(ctx, PR_2_INOREF_IN_UNUSED, &cd->pctx)){
1344d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson				ext2fs_bg_itable_unused_set(fs, group, 0);
134549a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos				ext2fs_mark_super_dirty(fs);
13466267ee49be64035d8a9772c3bafed18a09874fa5Andreas Dilger				ctx->flags |= E2F_FLAG_RESTART_LATER;
134749a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos			} else {
134849a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos				ext2fs_unmark_valid(fs);
134949a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos				if (problem == PR_2_BAD_INO)
135049a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos					goto next;
135149a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos			}
135249a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos		}
135349a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos
13540433c1f1b72bb85d9ea11e7716a415a878a655c8Theodore Ts'o		/*
13550433c1f1b72bb85d9ea11e7716a415a878a655c8Theodore Ts'o		 * Offer to clear unused inodes; if we are going to be
13560433c1f1b72bb85d9ea11e7716a415a878a655c8Theodore Ts'o		 * restarting the scan due to bg_itable_unused being
13570433c1f1b72bb85d9ea11e7716a415a878a655c8Theodore Ts'o		 * wrong, then don't clear any inodes to avoid zapping
13580433c1f1b72bb85d9ea11e7716a415a878a655c8Theodore Ts'o		 * inodes that were skipped during pass1 due to an
13590433c1f1b72bb85d9ea11e7716a415a878a655c8Theodore Ts'o		 * incorrect bg_itable_unused; we'll get any real
13600433c1f1b72bb85d9ea11e7716a415a878a655c8Theodore Ts'o		 * problems after we restart.
13610433c1f1b72bb85d9ea11e7716a415a878a655c8Theodore Ts'o		 */
13620433c1f1b72bb85d9ea11e7716a415a878a655c8Theodore Ts'o		if (!(ctx->flags & E2F_FLAG_RESTART_LATER) &&
136397d26ce9e3589e9f5fa17014467a9730a884d158Theodore Ts'o		    !(ext2fs_test_inode_bitmap2(ctx->inode_used_map,
136497d26ce9e3589e9f5fa17014467a9730a884d158Theodore Ts'o						dirent->inode)))
136549a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos			problem = PR_2_UNUSED_INODE;
136649a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos
136749a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos		if (problem) {
136849a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos			if (fix_problem(ctx, problem, &cd->pctx)) {
136949a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos				dirent->inode = 0;
137049a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos				dir_modified++;
137149a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos				goto next;
137249a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos			} else {
137349a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos				ext2fs_unmark_valid(fs);
137449a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos				if (problem == PR_2_BAD_INO)
137549a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos					goto next;
137649a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos			}
137749a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos		}
137849a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos
137925f291c9b32d8017e6969c72a75e37d354c0570bTheodore Ts'o		if (!encrypted && check_name(ctx, dirent, &cd->pctx))
13801b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			dir_modified++;
13811b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o
1382e3dd5c6f1a1cf9baeb7073fe2ecc5214fdfe0621Theodore Ts'o		if (encrypted && (dot_state) > 1 &&
1383e3dd5c6f1a1cf9baeb7073fe2ecc5214fdfe0621Theodore Ts'o		    encrypted_check_name(ctx, dirent, &cd->pctx)) {
1384e3dd5c6f1a1cf9baeb7073fe2ecc5214fdfe0621Theodore Ts'o			dir_modified++;
1385e3dd5c6f1a1cf9baeb7073fe2ecc5214fdfe0621Theodore Ts'o			goto next;
1386e3dd5c6f1a1cf9baeb7073fe2ecc5214fdfe0621Theodore Ts'o		}
1387e3dd5c6f1a1cf9baeb7073fe2ecc5214fdfe0621Theodore Ts'o
1388aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o		if (check_filetype(ctx, dirent, ino, &cd->pctx))
1389aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o			dir_modified++;
1390aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o
13918fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		if (dx_db) {
1392437651ad234e125e2ef9c9f213cb3f5c92e67307Theodore Ts'o			ext2fs_dirhash(dx_dir->hashversion, dirent->name,
1393437651ad234e125e2ef9c9f213cb3f5c92e67307Theodore Ts'o				       ext2fs_dirent_name_len(dirent),
1394437651ad234e125e2ef9c9f213cb3f5c92e67307Theodore Ts'o				       fs->super->s_hash_seed, &hash, 0);
13958fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			if (hash < dx_db->min_hash)
13968fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				dx_db->min_hash = hash;
13978fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			if (hash > dx_db->max_hash)
13988fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				dx_db->max_hash = hash;
13998fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		}
14008fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o
140121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		/*
14023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * If this is a directory, then mark its parent in its
14033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * dir_info structure.  If the parent field is already
14043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * filled in, then this directory has more than one
14053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * hard link.  We assume the first link is correct,
14063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * and ask the user if he/she wants to clear this one.
14073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 */
1408e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o		if ((dot_state > 1) &&
1409c5d2f50dee996e48e96066155f85d7c925fcba0dValerie Aurora Henson		    (ext2fs_test_inode_bitmap2(ctx->inode_dir_map,
14103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o					      dirent->inode))) {
141128db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o			if (e2fsck_dir_info_get_parent(ctx, dirent->inode,
141228db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o						       &subdir_parent)) {
14131b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o				cd->pctx.ino = dirent->inode;
14141b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o				fix_problem(ctx, PR_2_NO_DIRINFO, &cd->pctx);
14150926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o				goto abort_free_dict;
14163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			}
141728db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o			if (subdir_parent) {
141828db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o				cd->pctx.ino2 = subdir_parent;
14191b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o				if (fix_problem(ctx, PR_2_LINK_DIR,
142021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o						&cd->pctx)) {
14213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o					dirent->inode = 0;
14223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o					dir_modified++;
14233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o					goto next;
142421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o				}
142521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o				cd->pctx.ino2 = 0;
142628db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o			} else {
1427efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o				(void) e2fsck_dir_info_set_parent(ctx,
142828db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o						  dirent->inode, ino);
142928db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o			}
14303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
14310926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o
14320926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o		if (dups_found) {
14330926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o			;
14340926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o		} else if (dict_lookup(&de_dict, dirent)) {
14350926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o			clear_problem_context(&pctx);
14360926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o			pctx.ino = ino;
14370926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o			pctx.dirent = dirent;
14380926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o			fix_problem(ctx, PR_2_REPORT_DUP_DIRENT, &pctx);
1439e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong			e2fsck_rehash_dir_later(ctx, ino);
14400926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o			dups_found++;
14410926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o		} else
14420926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o			dict_alloc_insert(&de_dict, dirent, dirent);
1443efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
14441b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		ext2fs_icount_increment(ctx->inode_count, dirent->inode,
14451b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o					&links);
144621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		if (links > 1)
14471b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			ctx->fs_links_count++;
14481b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		ctx->fs_total_count++;
14493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	next:
1450e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o		prev = dirent;
14515dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o		if (dir_modified)
14528a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o			(void) ext2fs_get_rec_len(fs, dirent, &rec_len);
14536582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu		if (!inline_data_size || dot_state > 1) {
14546582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu			offset += rec_len;
14556582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu		} else {
14566698374cc0a0d99c954aa61db771ba4128432337Darrick J. Wong			if (dot_state == 1) {
14576582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu				offset = 4;
14586698374cc0a0d99c954aa61db771ba4128432337Darrick J. Wong				/*
14596698374cc0a0d99c954aa61db771ba4128432337Darrick J. Wong				 * If we get here, we're checking an inline
14606698374cc0a0d99c954aa61db771ba4128432337Darrick J. Wong				 * directory and we've just checked a (fake)
14616698374cc0a0d99c954aa61db771ba4128432337Darrick J. Wong				 * dotdot entry that we created on the stack.
14626698374cc0a0d99c954aa61db771ba4128432337Darrick J. Wong				 * Therefore set 'prev' to NULL so that if we
14636698374cc0a0d99c954aa61db771ba4128432337Darrick J. Wong				 * call salvage_directory on the next entry,
14646698374cc0a0d99c954aa61db771ba4128432337Darrick J. Wong				 * it won't try to absorb the next entry into
14656698374cc0a0d99c954aa61db771ba4128432337Darrick J. Wong				 * the on-stack dotdot entry.
14666698374cc0a0d99c954aa61db771ba4128432337Darrick J. Wong				 */
14676698374cc0a0d99c954aa61db771ba4128432337Darrick J. Wong				prev = NULL;
14686698374cc0a0d99c954aa61db771ba4128432337Darrick J. Wong			}
14696582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu		}
1470e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o		dot_state++;
14710ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong	} while (offset < max_block_size);
14723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#if 0
14733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	printf("\n");
14743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#endif
14758fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	if (dx_db) {
14768fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#ifdef DX_DEBUG
14778fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		printf("db_block %d, type %d, min_hash 0x%0x, max_hash 0x%0x\n",
14788fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		       db->blockcnt, dx_db->type,
14798fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		       dx_db->min_hash, dx_db->max_hash);
14808fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#endif
1481b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o		cd->pctx.dir = cd->pctx.ino;
14828fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		if ((dx_db->type == DX_DIRBLOCK_ROOT) ||
14838fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		    (dx_db->type == DX_DIRBLOCK_NODE))
148481683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong			parse_int_node(fs, db, cd, dx_dir, buf, failed_csum);
14858fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	}
1486e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong
14870ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong	if (offset != max_block_size) {
14880ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong		cd->pctx.num = rec_len + offset - max_block_size;
14890ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong		if (fix_problem(ctx, PR_2_FINAL_RECLEN, &cd->pctx)) {
14900ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong			dirent->rec_len = cd->pctx.num;
14910ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong			dir_modified++;
14921b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		}
14933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
14943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (dir_modified) {
14952e9d8391560ecde48e0b21f174fdb7bf3331345aDarrick J. Wong		int	flags, will_rehash;
1496e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong		/* leaf block with no tail?  Rehash dirs later. */
149786f3b6cf98a72c6dad0738e3af2512ddcbd49be9Darrick J. Wong		if (ext2fs_has_feature_metadata_csum(fs->super) &&
1498e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong		    is_leaf &&
149917641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong		    !inline_data_size &&
150017641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong		    !ext2fs_dirent_has_tail(fs, (struct ext2_dir_entry *)buf)) {
150117641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong			if (insert_dirent_tail(fs, buf) == 0)
150217641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong				goto write_and_fix;
1503e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong			e2fsck_rehash_dir_later(ctx, ino);
150417641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong		}
1505e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong
1506e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wongwrite_and_fix:
15072e9d8391560ecde48e0b21f174fdb7bf3331345aDarrick J. Wong		will_rehash = e2fsck_dir_will_be_rehashed(ctx, ino);
15082e9d8391560ecde48e0b21f174fdb7bf3331345aDarrick J. Wong		if (will_rehash) {
15092e9d8391560ecde48e0b21f174fdb7bf3331345aDarrick J. Wong			flags = ctx->fs->flags;
1510e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong			ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
15112e9d8391560ecde48e0b21f174fdb7bf3331345aDarrick J. Wong		}
15126582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu		if (inline_data_size) {
15130ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong			buf = ibuf;
1514cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong#ifdef WORDS_BIGENDIAN
15150ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong			if (db->blockcnt)
15160ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong				goto skip_first_write_swab;
1517cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong			*((__u32 *)buf) = ext2fs_le32_to_cpu(*((__u32 *)buf));
1518cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong			cd->pctx.errcode = ext2fs_dirent_swab_out2(fs,
1519cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong					buf + EXT4_INLINE_DATA_DOTDOT_SIZE,
15200ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong					EXT4_MIN_INLINE_DATA_SIZE -
1521cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong					EXT4_INLINE_DATA_DOTDOT_SIZE,
1522cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong					0);
15230ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong			if (cd->pctx.errcode)
15240ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong				goto skip_second_write_swab;
15250ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wongskip_first_write_swab:
15260ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong			if (inline_data_size <= EXT4_MIN_INLINE_DATA_SIZE ||
15270ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong			    !db->blockcnt)
15280ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong				goto skip_second_write_swab;
15290ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong			cd->pctx.errcode = ext2fs_dirent_swab_out2(fs,
15300ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong					buf + EXT4_MIN_INLINE_DATA_SIZE,
15310ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong					inline_data_size -
15320ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong					EXT4_MIN_INLINE_DATA_SIZE,
15330ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong					0);
15340ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wongskip_second_write_swab:
1535cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong			if (cd->pctx.errcode &&
1536cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong			    !fix_problem(ctx, PR_2_WRITE_DIRBLOCK, &cd->pctx))
1537cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong				goto abort_free_dict;
1538cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong#endif
15396582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu			cd->pctx.errcode =
15406582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu				ext2fs_inline_data_set(fs, ino, 0, buf,
15416582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu						       inline_data_size);
15426582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu		} else
15436582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu			cd->pctx.errcode = ext2fs_write_dir_block4(fs, block_nr,
15446582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu								   buf, 0, ino);
15452e9d8391560ecde48e0b21f174fdb7bf3331345aDarrick J. Wong		if (will_rehash)
15462e9d8391560ecde48e0b21f174fdb7bf3331345aDarrick J. Wong			ctx->fs->flags = (flags &
15472e9d8391560ecde48e0b21f174fdb7bf3331345aDarrick J. Wong					  EXT2_FLAG_IGNORE_CSUM_ERRORS) |
15482e9d8391560ecde48e0b21f174fdb7bf3331345aDarrick J. Wong					 (ctx->fs->flags &
15492e9d8391560ecde48e0b21f174fdb7bf3331345aDarrick J. Wong					  ~EXT2_FLAG_IGNORE_CSUM_ERRORS);
15501b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		if (cd->pctx.errcode) {
155108b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o			if (!fix_problem(ctx, PR_2_WRITE_DIRBLOCK,
15520926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o					 &cd->pctx))
15530926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o				goto abort_free_dict;
15543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
15553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		ext2fs_mark_changed(fs);
1556e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong	} else if (is_leaf && failed_csum && !dir_modified) {
1557e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong		/*
1558e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong		 * If a leaf node that fails csum makes it this far without
1559e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong		 * alteration, ask the user if the checksum should be fixed.
1560e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong		 */
1561e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong		if (fix_problem(ctx, PR_2_LEAF_NODE_ONLY_CSUM_INVALID,
1562e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong				&cd->pctx))
1563e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong			goto write_and_fix;
15643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
15650926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o	dict_free_nodes(&de_dict);
15663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
15670926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'oabort_free_dict:
15680926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o	ctx->flags |= E2F_FLAG_ABORT;
156949a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos	dict_free_nodes(&de_dict);
15700926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o	return DIRENT_ABORT;
15713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
15723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1573624e4a6466dba9889f5f80dc168f2bb7c2a3f5d0Aditya Kalistruct del_block {
1574624e4a6466dba9889f5f80dc168f2bb7c2a3f5d0Aditya Kali	e2fsck_t	ctx;
1575624e4a6466dba9889f5f80dc168f2bb7c2a3f5d0Aditya Kali	e2_blkcnt_t	num;
1576624e4a6466dba9889f5f80dc168f2bb7c2a3f5d0Aditya Kali};
1577624e4a6466dba9889f5f80dc168f2bb7c2a3f5d0Aditya Kali
15783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
15793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * This function is called to deallocate a block, and is an interator
15803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * functioned called by deallocate inode via ext2fs_iterate_block().
15813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
15823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic int deallocate_inode_block(ext2_filsys fs,
15836dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson				  blk64_t	*block_nr,
1584544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o				  e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
15856dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson				  blk64_t ref_block EXT2FS_ATTR((unused)),
1586544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o				  int ref_offset EXT2FS_ATTR((unused)),
1587133a56dc9da52054bc27b4c1a23f03e3405003dbTheodore Ts'o				  void *priv_data)
15883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
1589624e4a6466dba9889f5f80dc168f2bb7c2a3f5d0Aditya Kali	struct del_block *p = priv_data;
1590efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
15914a05268cf86f7138c78d80a53f7e162f32128a3dTheodore Ts'o	if (*block_nr == 0)
15923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
15931ba7a2f2b6a9b152828a06443955a7fb1d139930Theodore Ts'o	if ((*block_nr < fs->super->s_first_data_block) ||
15944efbac6fed75c29d3d5f1b676b932754653a2ac5Valerie Aurora Henson	    (*block_nr >= ext2fs_blocks_count(fs->super)))
15951ba7a2f2b6a9b152828a06443955a7fb1d139930Theodore Ts'o		return 0;
15968dd650ab9ac394c6d6d19b02e8bb22d5a1e5da0dDarrick J. Wong	if ((*block_nr % EXT2FS_CLUSTER_RATIO(fs)) == 0)
15978dd650ab9ac394c6d6d19b02e8bb22d5a1e5da0dDarrick J. Wong		ext2fs_block_alloc_stats2(fs, *block_nr, -1);
1598624e4a6466dba9889f5f80dc168f2bb7c2a3f5d0Aditya Kali	p->num++;
15993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
16003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
1601efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
16023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
16033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * This fuction deallocates an inode
16043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
16054035f40bc4550ce7520724cc837992a700794e00Theodore Ts'ostatic void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf)
16063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
16071b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ext2_filsys fs = ctx->fs;
16083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct ext2_inode	inode;
16091b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	struct problem_context	pctx;
16100684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o	__u32			count;
1611624e4a6466dba9889f5f80dc168f2bb7c2a3f5d0Aditya Kali	struct del_block	del_block;
1612efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
161308b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o	e2fsck_read_inode(ctx, ino, &inode, "deallocate_inode");
16141b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	clear_problem_context(&pctx);
16151b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	pctx.ino = ino;
1616f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
16173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
16183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Fix up the bitmaps...
16193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
1620f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o	e2fsck_read_bitmaps(ctx);
16210684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o	ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode));
16220684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o
16230c80c44bd08c60f3cd0ad87f12a71a75cac3bcaaTheodore Ts'o	if (ext2fs_file_acl_block(fs, &inode) &&
162486f3b6cf98a72c6dad0738e3af2512ddcbd49be9Darrick J. Wong	    ext2fs_has_feature_xattr(fs->super)) {
162539f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong		pctx.errcode = ext2fs_adjust_ea_refcount3(fs,
162639f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong				ext2fs_file_acl_block(fs, &inode),
162739f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong				block_buf, -1, &count, ino);
16280684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o		if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) {
16290684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o			pctx.errcode = 0;
16300684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o			count = 1;
16310684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o		}
16320684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o		if (pctx.errcode) {
16330c80c44bd08c60f3cd0ad87f12a71a75cac3bcaaTheodore Ts'o			pctx.blk = ext2fs_file_acl_block(fs, &inode);
16340684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o			fix_problem(ctx, PR_2_ADJ_EA_REFCOUNT, &pctx);
16350684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o			ctx->flags |= E2F_FLAG_ABORT;
16360684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o			return;
16370684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o		}
16380684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o		if (count == 0) {
163948f23054bb8ad0506c0baa9f06ba182acc2aa88bValerie Aurora Henson			ext2fs_block_alloc_stats2(fs,
16400c80c44bd08c60f3cd0ad87f12a71a75cac3bcaaTheodore Ts'o				  ext2fs_file_acl_block(fs, &inode), -1);
16410684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o		}
16420c80c44bd08c60f3cd0ad87f12a71a75cac3bcaaTheodore Ts'o		ext2fs_file_acl_block_set(fs, &inode, 0);
16430684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o	}
16443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
16450c80c44bd08c60f3cd0ad87f12a71a75cac3bcaaTheodore Ts'o	if (!ext2fs_inode_has_valid_blocks2(fs, &inode))
1646c8ec2bad18fdaa842f786f3b37c9320a3411aea3Theodore Ts'o		goto clear_inode;
1647a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o
16482ece839011f3074c2249dcfbf99945c93cc1927dDarrick J. Wong	/* Inline data inodes don't have blocks to iterate */
16492ece839011f3074c2249dcfbf99945c93cc1927dDarrick J. Wong	if (inode.i_flags & EXT4_INLINE_DATA_FL)
16502ece839011f3074c2249dcfbf99945c93cc1927dDarrick J. Wong		goto clear_inode;
16512ece839011f3074c2249dcfbf99945c93cc1927dDarrick J. Wong
16523b6c0938ec5aa401c7ae6c95e94e5ad30a7b8562Darrick J. Wong	if (LINUX_S_ISREG(inode.i_mode) &&
16533b6c0938ec5aa401c7ae6c95e94e5ad30a7b8562Darrick J. Wong	    ext2fs_needs_large_file_feature(EXT2_I_SIZE(&inode)))
1654a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o		ctx->large_files--;
1655a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o
1656624e4a6466dba9889f5f80dc168f2bb7c2a3f5d0Aditya Kali	del_block.ctx = ctx;
1657624e4a6466dba9889f5f80dc168f2bb7c2a3f5d0Aditya Kali	del_block.num = 0;
16586dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson	pctx.errcode = ext2fs_block_iterate3(fs, ino, 0, block_buf,
1659624e4a6466dba9889f5f80dc168f2bb7c2a3f5d0Aditya Kali					     deallocate_inode_block,
1660624e4a6466dba9889f5f80dc168f2bb7c2a3f5d0Aditya Kali					     &del_block);
16611b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (pctx.errcode) {
16621b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_2_DEALLOC_INODE, &pctx);
166308b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		ctx->flags |= E2F_FLAG_ABORT;
166408b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		return;
16651b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	}
1666c8ec2bad18fdaa842f786f3b37c9320a3411aea3Theodore Ts'oclear_inode:
1667c8ec2bad18fdaa842f786f3b37c9320a3411aea3Theodore Ts'o	/* Inode may have changed by block_iterate, so reread it */
1668c8ec2bad18fdaa842f786f3b37c9320a3411aea3Theodore Ts'o	e2fsck_read_inode(ctx, ino, &inode, "deallocate_inode");
1669c8ec2bad18fdaa842f786f3b37c9320a3411aea3Theodore Ts'o	e2fsck_clear_inode(ctx, ino, &inode, 0, "deallocate_inode");
16703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
16713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
16728fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o/*
16738fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o * This fuction clears the htree flag on an inode
16748fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o */
16758fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'ostatic void clear_htree(e2fsck_t ctx, ext2_ino_t ino)
16768fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o{
16778fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	struct ext2_inode	inode;
1678efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
16798fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	e2fsck_read_inode(ctx, ino, &inode, "clear_htree");
16808fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	inode.i_flags = inode.i_flags & ~EXT2_INDEX_FL;
16818fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	e2fsck_write_inode(ctx, ino, &inode, "clear_htree");
1682b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o	if (ctx->dirs_to_hash)
1683b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o		ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
16848fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o}
16858fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o
16868fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o
1687f404167dda29a59d2be2882328aeb074b9899669Theodore Ts'oint e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir,
1688f404167dda29a59d2be2882328aeb074b9899669Theodore Ts'o			     ext2_ino_t ino, char *buf)
16893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
16901b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ext2_filsys fs = ctx->fs;
16913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct ext2_inode	inode;
16923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int			inode_modified = 0;
16936c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o	int			not_fixed = 0;
16941e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o	unsigned char		*frag, *fsize;
169521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	struct problem_context	pctx;
16963c7c6d73f1a0bd45835966f1179fc3e8236a7d9cTheodore Ts'o	problem_t		problem = 0;
16973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
169808b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o	e2fsck_read_inode(ctx, ino, &inode, "process_bad_inode");
169921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o
170021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	clear_problem_context(&pctx);
170121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	pctx.ino = ino;
170221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	pctx.dir = dir;
170321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	pctx.inode = &inode;
170421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o
17050c80c44bd08c60f3cd0ad87f12a71a75cac3bcaaTheodore Ts'o	if (ext2fs_file_acl_block(fs, &inode) &&
170686f3b6cf98a72c6dad0738e3af2512ddcbd49be9Darrick J. Wong	    !ext2fs_has_feature_xattr(fs->super)) {
1707f76344fb6f9439ecd5060943930e73cd3b3dd9feTheodore Ts'o		if (fix_problem(ctx, PR_2_FILE_ACL_ZERO, &pctx)) {
17080c80c44bd08c60f3cd0ad87f12a71a75cac3bcaaTheodore Ts'o			ext2fs_file_acl_block_set(fs, &inode, 0);
1709f76344fb6f9439ecd5060943930e73cd3b3dd9feTheodore Ts'o			inode_modified++;
1710f76344fb6f9439ecd5060943930e73cd3b3dd9feTheodore Ts'o		} else
1711f76344fb6f9439ecd5060943930e73cd3b3dd9feTheodore Ts'o			not_fixed++;
1712f76344fb6f9439ecd5060943930e73cd3b3dd9feTheodore Ts'o	}
17136c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o
171450e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	if (!LINUX_S_ISDIR(inode.i_mode) && !LINUX_S_ISREG(inode.i_mode) &&
171550e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	    !LINUX_S_ISCHR(inode.i_mode) && !LINUX_S_ISBLK(inode.i_mode) &&
171650e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	    !LINUX_S_ISLNK(inode.i_mode) && !LINUX_S_ISFIFO(inode.i_mode) &&
171708b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o	    !(LINUX_S_ISSOCK(inode.i_mode)))
171808b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		problem = PR_2_BAD_MODE;
1719fdbdea09b87dbd8e39c23286f22653e7641599aeTheodore Ts'o	else if (LINUX_S_ISCHR(inode.i_mode)
17200684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o		 && !e2fsck_pass1_check_device_inode(fs, &inode))
172108b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		problem = PR_2_BAD_CHAR_DEV;
1722fdbdea09b87dbd8e39c23286f22653e7641599aeTheodore Ts'o	else if (LINUX_S_ISBLK(inode.i_mode)
17230684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o		 && !e2fsck_pass1_check_device_inode(fs, &inode))
172408b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		problem = PR_2_BAD_BLOCK_DEV;
1725fdbdea09b87dbd8e39c23286f22653e7641599aeTheodore Ts'o	else if (LINUX_S_ISFIFO(inode.i_mode)
17260684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o		 && !e2fsck_pass1_check_device_inode(fs, &inode))
17271dde43f0c1176f61dd0bf91aff265ce8cd1c5fd6Theodore Ts'o		problem = PR_2_BAD_FIFO;
1728fdbdea09b87dbd8e39c23286f22653e7641599aeTheodore Ts'o	else if (LINUX_S_ISSOCK(inode.i_mode)
17290684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o		 && !e2fsck_pass1_check_device_inode(fs, &inode))
17301dde43f0c1176f61dd0bf91aff265ce8cd1c5fd6Theodore Ts'o		problem = PR_2_BAD_SOCKET;
1731fdbdea09b87dbd8e39c23286f22653e7641599aeTheodore Ts'o	else if (LINUX_S_ISLNK(inode.i_mode)
17327cadc57780f3e3e8e644e8976e11a336902d4a25Theodore Ts'o		 && !e2fsck_pass1_check_symlink(fs, ino, &inode, buf)) {
1733bcf9c5d4016975c3c2afdb4a4b358569bd3c8681Theodore Ts'o		problem = PR_2_INVALID_SYMLINK;
173467052a8aeeca8cd80d1dd33c2792f917573accc8Andreas Dilger	}
17351dde43f0c1176f61dd0bf91aff265ce8cd1c5fd6Theodore Ts'o
173608b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o	if (problem) {
173708b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		if (fix_problem(ctx, problem, &pctx)) {
17381b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			deallocate_inode(ctx, ino, 0);
1739a02ce9df5ff5db2982462aec7162f7142dc18131Theodore Ts'o			if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
174008b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o				return 0;
17417cf73dcd3d173d88ceab26d381f4abac362d8518Theodore Ts'o			return 1;
17426c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o		} else
17436c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o			not_fixed++;
174408b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		problem = 0;
17457cf73dcd3d173d88ceab26d381f4abac362d8518Theodore Ts'o	}
1746efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
17476c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o	if (inode.i_faddr) {
17486c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o		if (fix_problem(ctx, PR_2_FADDR_ZERO, &pctx)) {
17496c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o			inode.i_faddr = 0;
17506c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o			inode_modified++;
17516c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o		} else
17526c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o			not_fixed++;
17533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
17541e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o
17551e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o	switch (fs->super->s_creator_os) {
17561e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o	    case EXT2_OS_HURD:
17571e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o		frag = &inode.osd2.hurd2.h_i_frag;
17581e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o		fsize = &inode.osd2.hurd2.h_i_fsize;
17591e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o		break;
17601e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o	    default:
17611e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o		frag = fsize = 0;
17621e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o	}
176321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	if (frag && *frag) {
176421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		pctx.num = *frag;
17651b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		if (fix_problem(ctx, PR_2_FRAG_ZERO, &pctx)) {
176621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			*frag = 0;
176721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			inode_modified++;
17687e0282c5f21add344b306876ca999aecd4d5fd0cTheodore Ts'o		} else
17697e0282c5f21add344b306876ca999aecd4d5fd0cTheodore Ts'o			not_fixed++;
177021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		pctx.num = 0;
177121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	}
177221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	if (fsize && *fsize) {
177321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		pctx.num = *fsize;
17741b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		if (fix_problem(ctx, PR_2_FSIZE_ZERO, &pctx)) {
177521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			*fsize = 0;
177621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			inode_modified++;
17776c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o		} else
17786c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o			not_fixed++;
177921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		pctx.num = 0;
178021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	}
178121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o
17825d17119d14fe1276936c85d7986695a4543b1aa1Theodore Ts'o	if ((fs->super->s_creator_os == EXT2_OS_LINUX) &&
178386f3b6cf98a72c6dad0738e3af2512ddcbd49be9Darrick J. Wong	    !ext2fs_has_feature_huge_file(fs->super) &&
17845d17119d14fe1276936c85d7986695a4543b1aa1Theodore Ts'o	    (inode.osd2.linux2.l_i_blocks_hi != 0)) {
17855d17119d14fe1276936c85d7986695a4543b1aa1Theodore Ts'o		pctx.num = inode.osd2.linux2.l_i_blocks_hi;
17865d17119d14fe1276936c85d7986695a4543b1aa1Theodore Ts'o		if (fix_problem(ctx, PR_2_BLOCKS_HI_ZERO, &pctx)) {
17875d17119d14fe1276936c85d7986695a4543b1aa1Theodore Ts'o			inode.osd2.linux2.l_i_blocks_hi = 0;
17885d17119d14fe1276936c85d7986695a4543b1aa1Theodore Ts'o			inode_modified++;
17895d17119d14fe1276936c85d7986695a4543b1aa1Theodore Ts'o		}
17905d17119d14fe1276936c85d7986695a4543b1aa1Theodore Ts'o	}
17915d17119d14fe1276936c85d7986695a4543b1aa1Theodore Ts'o
179236769c606c270094df0431cbcab9932905adcedcJustus Winter	if ((fs->super->s_creator_os == EXT2_OS_LINUX) &&
179386f3b6cf98a72c6dad0738e3af2512ddcbd49be9Darrick J. Wong	    !ext2fs_has_feature_64bit(fs->super) &&
1794911ec6261568ca56d2d7b9a15f00578c4d127cf4Theodore Ts'o	    inode.osd2.linux2.l_i_file_acl_high != 0) {
1795911ec6261568ca56d2d7b9a15f00578c4d127cf4Theodore Ts'o		pctx.num = inode.osd2.linux2.l_i_file_acl_high;
1796911ec6261568ca56d2d7b9a15f00578c4d127cf4Theodore Ts'o		if (fix_problem(ctx, PR_2_I_FILE_ACL_HI_ZERO, &pctx)) {
1797911ec6261568ca56d2d7b9a15f00578c4d127cf4Theodore Ts'o			inode.osd2.linux2.l_i_file_acl_high = 0;
1798911ec6261568ca56d2d7b9a15f00578c4d127cf4Theodore Ts'o			inode_modified++;
1799911ec6261568ca56d2d7b9a15f00578c4d127cf4Theodore Ts'o		} else
1800911ec6261568ca56d2d7b9a15f00578c4d127cf4Theodore Ts'o			not_fixed++;
1801911ec6261568ca56d2d7b9a15f00578c4d127cf4Theodore Ts'o	}
1802911ec6261568ca56d2d7b9a15f00578c4d127cf4Theodore Ts'o
18030c80c44bd08c60f3cd0ad87f12a71a75cac3bcaaTheodore Ts'o	if (ext2fs_file_acl_block(fs, &inode) &&
18040c80c44bd08c60f3cd0ad87f12a71a75cac3bcaaTheodore Ts'o	    ((ext2fs_file_acl_block(fs, &inode) < fs->super->s_first_data_block) ||
18050c80c44bd08c60f3cd0ad87f12a71a75cac3bcaaTheodore Ts'o	     (ext2fs_file_acl_block(fs, &inode) >= ext2fs_blocks_count(fs->super)))) {
18066c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o		if (fix_problem(ctx, PR_2_FILE_ACL_BAD, &pctx)) {
18070c80c44bd08c60f3cd0ad87f12a71a75cac3bcaaTheodore Ts'o			ext2fs_file_acl_block_set(fs, &inode, 0);
18086c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o			inode_modified++;
18096c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o		} else
18106c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o			not_fixed++;
1811342d847db355d81299218e07a1e58ece82080a04Theodore Ts'o	}
181221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	if (inode.i_dir_acl &&
18136c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o	    LINUX_S_ISDIR(inode.i_mode)) {
18146c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o		if (fix_problem(ctx, PR_2_DIR_ACL_ZERO, &pctx)) {
18156c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o			inode.i_dir_acl = 0;
18166c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o			inode_modified++;
18176c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o		} else
18186c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o			not_fixed++;
181921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	}
18206c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o
1821f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	if (inode_modified)
182208b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		e2fsck_write_inode(ctx, ino, &inode, "process_bad_inode");
1823f76344fb6f9439ecd5060943930e73cd3b3dd9feTheodore Ts'o	if (!not_fixed && ctx->inode_bad_map)
1824c5d2f50dee996e48e96066155f85d7c925fcba0dValerie Aurora Henson		ext2fs_unmark_inode_bitmap2(ctx->inode_bad_map, ino);
18253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
18263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
18273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
182850e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o/*
182950e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o * allocate_dir_block --- this function allocates a new directory
183050e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o * 	block for a particular inode; this is done if a directory has
183150e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o * 	a "hole" in it, or if a directory has a illegal block number
183250e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o * 	that was zeroed out and now needs to be replaced.
183350e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o */
18341b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'ostatic int allocate_dir_block(e2fsck_t ctx,
18356dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson			      struct ext2_db_entry2 *db,
1836efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o			      char *buf EXT2FS_ATTR((unused)),
1837544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			      struct problem_context *pctx)
183850e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o{
18391b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ext2_filsys fs = ctx->fs;
1840ff11309ecc24fae663a4d65947b24c371a04a5c7Darrick J. Wong	blk64_t			blk = 0;
184150e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	char			*block;
184250e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	struct ext2_inode	inode;
184350e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o
18441b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (fix_problem(ctx, PR_2_DIRECTORY_HOLE, pctx) == 0)
184550e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o		return 1;
184650e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o
184750e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	/*
184850e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	 * Read the inode and block bitmaps in; we'll be messing with
184950e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	 * them.
185050e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	 */
1851f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o	e2fsck_read_bitmaps(ctx);
1852efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
185350e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	/*
185450e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	 * First, find a free block
185550e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	 */
1856ff11309ecc24fae663a4d65947b24c371a04a5c7Darrick J. Wong	e2fsck_read_inode(ctx, db->ino, &inode, "allocate_dir_block");
1857ff11309ecc24fae663a4d65947b24c371a04a5c7Darrick J. Wong	pctx->errcode = ext2fs_map_cluster_block(fs, db->ino, &inode,
1858ff11309ecc24fae663a4d65947b24c371a04a5c7Darrick J. Wong						 db->blockcnt, &blk);
1859ff11309ecc24fae663a4d65947b24c371a04a5c7Darrick J. Wong	if (pctx->errcode || blk == 0) {
18607b486ec08cda3bc67b7f6bdcbcc9cb5783322e6cDarrick J. Wong		blk = ext2fs_find_inode_goal(fs, db->ino, &inode, db->blockcnt);
18617b486ec08cda3bc67b7f6bdcbcc9cb5783322e6cDarrick J. Wong		pctx->errcode = ext2fs_new_block2(fs, blk,
1862ff11309ecc24fae663a4d65947b24c371a04a5c7Darrick J. Wong						  ctx->block_found_map, &blk);
1863ff11309ecc24fae663a4d65947b24c371a04a5c7Darrick J. Wong		if (pctx->errcode) {
1864ff11309ecc24fae663a4d65947b24c371a04a5c7Darrick J. Wong			pctx->str = "ext2fs_new_block";
1865ff11309ecc24fae663a4d65947b24c371a04a5c7Darrick J. Wong			fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
1866ff11309ecc24fae663a4d65947b24c371a04a5c7Darrick J. Wong			return 1;
1867ff11309ecc24fae663a4d65947b24c371a04a5c7Darrick J. Wong		}
186850e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	}
1869c5d2f50dee996e48e96066155f85d7c925fcba0dValerie Aurora Henson	ext2fs_mark_block_bitmap2(ctx->block_found_map, blk);
1870c5d2f50dee996e48e96066155f85d7c925fcba0dValerie Aurora Henson	ext2fs_mark_block_bitmap2(fs->block_map, blk);
187150e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	ext2fs_mark_bb_dirty(fs);
187250e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o
187350e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	/*
187450e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	 * Now let's create the actual data block for the inode
187550e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	 */
187650e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	if (db->blockcnt)
18771b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx->errcode = ext2fs_new_dir_block(fs, 0, 0, &block);
187850e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	else
18791b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx->errcode = ext2fs_new_dir_block(fs, db->ino,
18801b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o						     EXT2_ROOT_INO, &block);
188150e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o
18821b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (pctx->errcode) {
18831b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx->str = "ext2fs_new_dir_block";
18841b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
188550e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o		return 1;
188650e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	}
188750e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o
188881683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	pctx->errcode = ext2fs_write_dir_block4(fs, blk, block, 0, db->ino);
1889c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	ext2fs_free_mem(&block);
18901b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (pctx->errcode) {
18911b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx->str = "ext2fs_write_dir_block";
18921b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
189350e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o		return 1;
189450e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	}
189550e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o
189650e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	/*
189750e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	 * Update the inode block count
189850e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	 */
18991ca1059fd0126fd2c065f272a566c18f14bab16dTheodore Ts'o	ext2fs_iblk_add_blocks(fs, &inode, 1);
190062f9bd0e4f7547fe01f829025888d477a973a539Theodore Ts'o	if (EXT2_I_SIZE(&inode) < ((__u64) db->blockcnt+1) * fs->blocksize) {
190197c607b1a25e1f4e83bf246c76b679d91470f5dcDarrick J. Wong		pctx->errcode = ext2fs_inode_size_set(fs, &inode,
190297c607b1a25e1f4e83bf246c76b679d91470f5dcDarrick J. Wong					(db->blockcnt+1) * fs->blocksize);
190397c607b1a25e1f4e83bf246c76b679d91470f5dcDarrick J. Wong		if (pctx->errcode) {
190497c607b1a25e1f4e83bf246c76b679d91470f5dcDarrick J. Wong			pctx->str = "ext2fs_inode_size_set";
190597c607b1a25e1f4e83bf246c76b679d91470f5dcDarrick J. Wong			fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
190697c607b1a25e1f4e83bf246c76b679d91470f5dcDarrick J. Wong			return 1;
190797c607b1a25e1f4e83bf246c76b679d91470f5dcDarrick J. Wong		}
190897c607b1a25e1f4e83bf246c76b679d91470f5dcDarrick J. Wong	}
190908b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o	e2fsck_write_inode(ctx, db->ino, &inode, "allocate_dir_block");
191050e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o
191150e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	/*
191250e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	 * Finally, update the block pointers for the inode
191350e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	 */
191450e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	db->blk = blk;
19152d07b3ad98bfe1db5fb1071f53a5338ab6c35522Theodore Ts'o	pctx->errcode = ext2fs_bmap2(fs, db->ino, &inode, 0, BMAP_SET,
19162d07b3ad98bfe1db5fb1071f53a5338ab6c35522Theodore Ts'o				     db->blockcnt, 0, &blk);
19171b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (pctx->errcode) {
19181b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx->str = "ext2fs_block_iterate";
19191b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
192050e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o		return 1;
192150e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	}
192250e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o
192350e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	return 0;
192450e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o}
1925