pass2.c revision e0ed7404719a9ddd2ba427a80db5365c8bad18c0
1/*
2 * pass2.c --- check directory structure
3 *
4 * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 *
11 * Pass 2 of e2fsck iterates through all active directory inodes, and
12 * applies to following tests to each directory entry in the directory
13 * blocks in the inodes:
14 *
15 *	- The length of the directory entry (rec_len) should be at
16 * 		least 8 bytes, and no more than the remaining space
17 * 		left in the directory block.
18 * 	- The length of the name in the directory entry (name_len)
19 * 		should be less than (rec_len - 8).
20 *	- The inode number in the directory entry should be within
21 * 		legal bounds.
22 * 	- The inode number should refer to a in-use inode.
23 *	- The first entry should be '.', and its inode should be
24 * 		the inode of the directory.
25 * 	- The second entry should be '..'.
26 *
27 * To minimize disk seek time, the directory blocks are processed in
28 * sorted order of block numbers.
29 *
30 * Pass 2 also collects the following information:
31 * 	- The inode numbers of the subdirectories for each directory.
32 *
33 * Pass 2 relies on the following information from previous passes:
34 * 	- The directory information collected in pass 1.
35 * 	- The inode_used_map bitmap
36 * 	- The inode_bad_map bitmap
37 * 	- The inode_dir_map bitmap
38 *
39 * Pass 2 frees the following data structures
40 * 	- The inode_bad_map bitmap
41 * 	- The inode_reg_map bitmap
42 */
43
44#define _GNU_SOURCE 1 /* get strnlen() */
45#include <string.h>
46
47#include "e2fsck.h"
48#include "problem.h"
49#include "dict.h"
50
51#ifdef NO_INLINE_FUNCS
52#define _INLINE_
53#else
54#define _INLINE_ inline
55#endif
56
57/* #define DX_DEBUG */
58
59/*
60 * Keeps track of how many times an inode is referenced.
61 */
62static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf);
63static int check_dir_block(ext2_filsys fs,
64			   struct ext2_db_entry2 *dir_blocks_info,
65			   void *priv_data);
66static int allocate_dir_block(e2fsck_t ctx,
67			      struct ext2_db_entry2 *dir_blocks_info,
68			      char *buf, struct problem_context *pctx);
69static void clear_htree(e2fsck_t ctx, ext2_ino_t ino);
70static int htree_depth(struct dx_dir_info *dx_dir,
71		       struct dx_dirblock_info *dx_db);
72static EXT2_QSORT_TYPE special_dir_block_cmp(const void *a, const void *b);
73
74struct check_dir_struct {
75	char *buf;
76	struct problem_context	pctx;
77	int	count, max;
78	e2fsck_t ctx;
79};
80
81void e2fsck_pass2(e2fsck_t ctx)
82{
83	struct ext2_super_block *sb = ctx->fs->super;
84	struct problem_context	pctx;
85	ext2_filsys 		fs = ctx->fs;
86	char			*buf;
87#ifdef RESOURCE_TRACK
88	struct resource_track	rtrack;
89#endif
90	struct check_dir_struct cd;
91	struct dx_dir_info	*dx_dir;
92	struct dx_dirblock_info	*dx_db, *dx_parent;
93	unsigned int		save_type;
94	int			b;
95	int			i, depth;
96	problem_t		code;
97	int			bad_dir;
98
99	init_resource_track(&rtrack, ctx->fs->io);
100	clear_problem_context(&cd.pctx);
101
102#ifdef MTRACE
103	mtrace_print("Pass 2");
104#endif
105
106	if (!(ctx->options & E2F_OPT_PREEN))
107		fix_problem(ctx, PR_2_PASS_HEADER, &cd.pctx);
108
109	e2fsck_setup_tdb_icount(ctx, EXT2_ICOUNT_OPT_INCREMENT,
110				&ctx->inode_count);
111	if (ctx->inode_count)
112		cd.pctx.errcode = 0;
113	else {
114		e2fsck_set_bitmap_type(fs, EXT2FS_BMAP64_RBTREE,
115				       "inode_count", &save_type);
116		cd.pctx.errcode = ext2fs_create_icount2(fs,
117						EXT2_ICOUNT_OPT_INCREMENT,
118						0, ctx->inode_link_info,
119						&ctx->inode_count);
120		fs->default_bitmap_type = save_type;
121	}
122	if (cd.pctx.errcode) {
123		fix_problem(ctx, PR_2_ALLOCATE_ICOUNT, &cd.pctx);
124		ctx->flags |= E2F_FLAG_ABORT;
125		return;
126	}
127	buf = (char *) e2fsck_allocate_memory(ctx, 2*fs->blocksize,
128					      "directory scan buffer");
129
130	/*
131	 * Set up the parent pointer for the root directory, if
132	 * present.  (If the root directory is not present, we will
133	 * create it in pass 3.)
134	 */
135	(void) e2fsck_dir_info_set_parent(ctx, EXT2_ROOT_INO, EXT2_ROOT_INO);
136
137	cd.buf = buf;
138	cd.ctx = ctx;
139	cd.count = 1;
140	cd.max = ext2fs_dblist_count2(fs->dblist);
141
142	if (ctx->progress)
143		(void) (ctx->progress)(ctx, 2, 0, cd.max);
144
145	if (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX)
146		ext2fs_dblist_sort2(fs->dblist, special_dir_block_cmp);
147
148	cd.pctx.errcode = ext2fs_dblist_iterate2(fs->dblist, check_dir_block,
149						 &cd);
150	if (ctx->flags & E2F_FLAG_SIGNAL_MASK || ctx->flags & E2F_FLAG_RESTART)
151		return;
152
153	if (ctx->flags & E2F_FLAG_RESTART_LATER) {
154		ctx->flags |= E2F_FLAG_RESTART;
155		return;
156	}
157
158	if (cd.pctx.errcode) {
159		fix_problem(ctx, PR_2_DBLIST_ITERATE, &cd.pctx);
160		ctx->flags |= E2F_FLAG_ABORT;
161		return;
162	}
163
164#ifdef ENABLE_HTREE
165	for (i=0; (dx_dir = e2fsck_dx_dir_info_iter(ctx, &i)) != 0;) {
166		if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
167			return;
168		if (dx_dir->numblocks == 0)
169			continue;
170		clear_problem_context(&pctx);
171		bad_dir = 0;
172		pctx.dir = dx_dir->ino;
173		dx_db = dx_dir->dx_block;
174		if (dx_db->flags & DX_FLAG_REFERENCED)
175			dx_db->flags |= DX_FLAG_DUP_REF;
176		else
177			dx_db->flags |= DX_FLAG_REFERENCED;
178		/*
179		 * Find all of the first and last leaf blocks, and
180		 * update their parent's min and max hash values
181		 */
182		for (b=0, dx_db = dx_dir->dx_block;
183		     b < dx_dir->numblocks;
184		     b++, dx_db++) {
185			if ((dx_db->type != DX_DIRBLOCK_LEAF) ||
186			    !(dx_db->flags & (DX_FLAG_FIRST | DX_FLAG_LAST)))
187				continue;
188			dx_parent = &dx_dir->dx_block[dx_db->parent];
189			/*
190			 * XXX Make sure dx_parent->min_hash > dx_db->min_hash
191			 */
192			if (dx_db->flags & DX_FLAG_FIRST)
193				dx_parent->min_hash = dx_db->min_hash;
194			/*
195			 * XXX Make sure dx_parent->max_hash < dx_db->max_hash
196			 */
197			if (dx_db->flags & DX_FLAG_LAST)
198				dx_parent->max_hash = dx_db->max_hash;
199		}
200
201		for (b=0, dx_db = dx_dir->dx_block;
202		     b < dx_dir->numblocks;
203		     b++, dx_db++) {
204			pctx.blkcount = b;
205			pctx.group = dx_db->parent;
206			code = 0;
207			if (!(dx_db->flags & DX_FLAG_FIRST) &&
208			    (dx_db->min_hash < dx_db->node_min_hash)) {
209				pctx.blk = dx_db->min_hash;
210				pctx.blk2 = dx_db->node_min_hash;
211				code = PR_2_HTREE_MIN_HASH;
212				fix_problem(ctx, code, &pctx);
213				bad_dir++;
214			}
215			if (dx_db->type == DX_DIRBLOCK_LEAF) {
216				depth = htree_depth(dx_dir, dx_db);
217				if (depth != dx_dir->depth) {
218					pctx.num = dx_dir->depth;
219					code = PR_2_HTREE_BAD_DEPTH;
220					fix_problem(ctx, code, &pctx);
221					bad_dir++;
222				}
223			}
224			/*
225			 * This test doesn't apply for the root block
226			 * at block #0
227			 */
228			if (b &&
229			    (dx_db->max_hash > dx_db->node_max_hash)) {
230				pctx.blk = dx_db->max_hash;
231				pctx.blk2 = dx_db->node_max_hash;
232				code = PR_2_HTREE_MAX_HASH;
233				fix_problem(ctx, code, &pctx);
234				bad_dir++;
235			}
236			if (!(dx_db->flags & DX_FLAG_REFERENCED)) {
237				code = PR_2_HTREE_NOTREF;
238				fix_problem(ctx, code, &pctx);
239				bad_dir++;
240			} else if (dx_db->flags & DX_FLAG_DUP_REF) {
241				code = PR_2_HTREE_DUPREF;
242				fix_problem(ctx, code, &pctx);
243				bad_dir++;
244			}
245		}
246		if (bad_dir && fix_problem(ctx, PR_2_HTREE_CLEAR, &pctx)) {
247			clear_htree(ctx, dx_dir->ino);
248			dx_dir->numblocks = 0;
249		}
250	}
251	e2fsck_free_dx_dir_info(ctx);
252#endif
253	ext2fs_free_mem(&buf);
254	ext2fs_free_dblist(fs->dblist);
255
256	if (ctx->inode_bad_map) {
257		ext2fs_free_inode_bitmap(ctx->inode_bad_map);
258		ctx->inode_bad_map = 0;
259	}
260	if (ctx->inode_reg_map) {
261		ext2fs_free_inode_bitmap(ctx->inode_reg_map);
262		ctx->inode_reg_map = 0;
263	}
264
265	clear_problem_context(&pctx);
266	if (ctx->large_files) {
267		if (!(sb->s_feature_ro_compat &
268		      EXT2_FEATURE_RO_COMPAT_LARGE_FILE) &&
269		    fix_problem(ctx, PR_2_FEATURE_LARGE_FILES, &pctx)) {
270			sb->s_feature_ro_compat |=
271				EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
272			fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
273			ext2fs_mark_super_dirty(fs);
274		}
275		if (sb->s_rev_level == EXT2_GOOD_OLD_REV &&
276		    fix_problem(ctx, PR_1_FS_REV_LEVEL, &pctx)) {
277			ext2fs_update_dynamic_rev(fs);
278			ext2fs_mark_super_dirty(fs);
279		}
280	}
281
282	print_resource_track(ctx, _("Pass 2"), &rtrack, fs->io);
283}
284
285#define MAX_DEPTH 32000
286static int htree_depth(struct dx_dir_info *dx_dir,
287		       struct dx_dirblock_info *dx_db)
288{
289	int	depth = 0;
290
291	while (dx_db->type != DX_DIRBLOCK_ROOT && depth < MAX_DEPTH) {
292		dx_db = &dx_dir->dx_block[dx_db->parent];
293		depth++;
294	}
295	return depth;
296}
297
298static int dict_de_cmp(const void *a, const void *b)
299{
300	const struct ext2_dir_entry *de_a, *de_b;
301	int	a_len, b_len;
302
303	de_a = (const struct ext2_dir_entry *) a;
304	a_len = de_a->name_len & 0xFF;
305	de_b = (const struct ext2_dir_entry *) b;
306	b_len = de_b->name_len & 0xFF;
307
308	if (a_len != b_len)
309		return (a_len - b_len);
310
311	return strncmp(de_a->name, de_b->name, a_len);
312}
313
314/*
315 * This is special sort function that makes sure that directory blocks
316 * with a dirblock of zero are sorted to the beginning of the list.
317 * This guarantees that the root node of the htree directories are
318 * processed first, so we know what hash version to use.
319 */
320static EXT2_QSORT_TYPE special_dir_block_cmp(const void *a, const void *b)
321{
322	const struct ext2_db_entry2 *db_a =
323		(const struct ext2_db_entry2 *) a;
324	const struct ext2_db_entry2 *db_b =
325		(const struct ext2_db_entry2 *) b;
326
327	if (db_a->blockcnt && !db_b->blockcnt)
328		return 1;
329
330	if (!db_a->blockcnt && db_b->blockcnt)
331		return -1;
332
333	if (db_a->blk != db_b->blk)
334		return (int) (db_a->blk - db_b->blk);
335
336	if (db_a->ino != db_b->ino)
337		return (int) (db_a->ino - db_b->ino);
338
339	return (int) (db_a->blockcnt - db_b->blockcnt);
340}
341
342
343/*
344 * Make sure the first entry in the directory is '.', and that the
345 * directory entry is sane.
346 */
347static int check_dot(e2fsck_t ctx,
348		     struct ext2_dir_entry *dirent,
349		     ext2_ino_t ino, struct problem_context *pctx)
350{
351	struct ext2_dir_entry *nextdir;
352	unsigned int	rec_len, new_len;
353	int		status = 0;
354	int		created = 0;
355	problem_t	problem = 0;
356
357	if (!dirent->inode)
358		problem = PR_2_MISSING_DOT;
359	else if (((dirent->name_len & 0xFF) != 1) ||
360		 (dirent->name[0] != '.'))
361		problem = PR_2_1ST_NOT_DOT;
362	else if (dirent->name[1] != '\0')
363		problem = PR_2_DOT_NULL_TERM;
364
365	(void) ext2fs_get_rec_len(ctx->fs, dirent, &rec_len);
366	if (problem) {
367		if (fix_problem(ctx, problem, pctx)) {
368			if (rec_len < 12)
369				rec_len = dirent->rec_len = 12;
370			dirent->inode = ino;
371			dirent->name_len = 1;
372			dirent->name[0] = '.';
373			dirent->name[1] = '\0';
374			status = 1;
375			created = 1;
376		}
377	}
378	if (dirent->inode != ino) {
379		if (fix_problem(ctx, PR_2_BAD_INODE_DOT, pctx)) {
380			dirent->inode = ino;
381			status = 1;
382		}
383	}
384	if (rec_len > 12) {
385		new_len = rec_len - 12;
386		if (new_len > 12) {
387			if (created ||
388			    fix_problem(ctx, PR_2_SPLIT_DOT, pctx)) {
389				nextdir = (struct ext2_dir_entry *)
390					((char *) dirent + 12);
391				dirent->rec_len = 12;
392				(void) ext2fs_set_rec_len(ctx->fs, new_len,
393							  nextdir);
394				nextdir->inode = 0;
395				nextdir->name_len = 0;
396				status = 1;
397			}
398		}
399	}
400	return status;
401}
402
403/*
404 * Make sure the second entry in the directory is '..', and that the
405 * directory entry is sane.  We do not check the inode number of '..'
406 * here; this gets done in pass 3.
407 */
408static int check_dotdot(e2fsck_t ctx,
409			struct ext2_dir_entry *dirent,
410			ext2_ino_t ino, struct problem_context *pctx)
411{
412	problem_t	problem = 0;
413	unsigned int	rec_len;
414
415	if (!dirent->inode)
416		problem = PR_2_MISSING_DOT_DOT;
417	else if (((dirent->name_len & 0xFF) != 2) ||
418		 (dirent->name[0] != '.') ||
419		 (dirent->name[1] != '.'))
420		problem = PR_2_2ND_NOT_DOT_DOT;
421	else if (dirent->name[2] != '\0')
422		problem = PR_2_DOT_DOT_NULL_TERM;
423
424	(void) ext2fs_get_rec_len(ctx->fs, dirent, &rec_len);
425	if (problem) {
426		if (fix_problem(ctx, problem, pctx)) {
427			if (rec_len < 12)
428				dirent->rec_len = 12;
429			/*
430			 * Note: we don't have the parent inode just
431			 * yet, so we will fill it in with the root
432			 * inode.  This will get fixed in pass 3.
433			 */
434			dirent->inode = EXT2_ROOT_INO;
435			dirent->name_len = 2;
436			dirent->name[0] = '.';
437			dirent->name[1] = '.';
438			dirent->name[2] = '\0';
439			return 1;
440		}
441		return 0;
442	}
443	if (e2fsck_dir_info_set_dotdot(ctx, ino, dirent->inode)) {
444		fix_problem(ctx, PR_2_NO_DIRINFO, pctx);
445		return -1;
446	}
447	return 0;
448}
449
450/*
451 * Check to make sure a directory entry doesn't contain any illegal
452 * characters.
453 */
454static int check_name(e2fsck_t ctx,
455		      struct ext2_dir_entry *dirent,
456		      ext2_ino_t dir_ino EXT2FS_ATTR((unused)),
457		      struct problem_context *pctx)
458{
459	int	i;
460	int	fixup = -1;
461	int	ret = 0;
462
463	for ( i = 0; i < (dirent->name_len & 0xFF); i++) {
464		if (dirent->name[i] == '/' || dirent->name[i] == '\0') {
465			if (fixup < 0) {
466				fixup = fix_problem(ctx, PR_2_BAD_NAME, pctx);
467			}
468			if (fixup) {
469				dirent->name[i] = '.';
470				ret = 1;
471			}
472		}
473	}
474	return ret;
475}
476
477/*
478 * Check the directory filetype (if present)
479 */
480static _INLINE_ int check_filetype(e2fsck_t ctx,
481				   struct ext2_dir_entry *dirent,
482				   ext2_ino_t dir_ino EXT2FS_ATTR((unused)),
483				   struct problem_context *pctx)
484{
485	int	filetype = dirent->name_len >> 8;
486	int	should_be = EXT2_FT_UNKNOWN;
487	struct ext2_inode	inode;
488
489	if (!(ctx->fs->super->s_feature_incompat &
490	      EXT2_FEATURE_INCOMPAT_FILETYPE)) {
491		if (filetype == 0 ||
492		    !fix_problem(ctx, PR_2_CLEAR_FILETYPE, pctx))
493			return 0;
494		dirent->name_len = dirent->name_len & 0xFF;
495		return 1;
496	}
497
498	if (ext2fs_test_inode_bitmap2(ctx->inode_dir_map, dirent->inode)) {
499		should_be = EXT2_FT_DIR;
500	} else if (ext2fs_test_inode_bitmap2(ctx->inode_reg_map,
501					    dirent->inode)) {
502		should_be = EXT2_FT_REG_FILE;
503	} else if (ctx->inode_bad_map &&
504		   ext2fs_test_inode_bitmap2(ctx->inode_bad_map,
505					    dirent->inode))
506		should_be = 0;
507	else {
508		e2fsck_read_inode(ctx, dirent->inode, &inode,
509				  "check_filetype");
510		should_be = ext2_file_type(inode.i_mode);
511	}
512	if (filetype == should_be)
513		return 0;
514	pctx->num = should_be;
515
516	if (fix_problem(ctx, filetype ? PR_2_BAD_FILETYPE : PR_2_SET_FILETYPE,
517			pctx) == 0)
518		return 0;
519
520	dirent->name_len = (dirent->name_len & 0xFF) | should_be << 8;
521	return 1;
522}
523
524#ifdef ENABLE_HTREE
525static void parse_int_node(ext2_filsys fs,
526			   struct ext2_db_entry2 *db,
527			   struct check_dir_struct *cd,
528			   struct dx_dir_info	*dx_dir,
529			   char *block_buf)
530{
531	struct 		ext2_dx_root_info  *root;
532	struct 		ext2_dx_entry *ent;
533	struct		ext2_dx_countlimit *limit;
534	struct dx_dirblock_info	*dx_db;
535	int		i, expect_limit, count;
536	blk_t		blk;
537	ext2_dirhash_t	min_hash = 0xffffffff;
538	ext2_dirhash_t	max_hash = 0;
539	ext2_dirhash_t	hash = 0, prev_hash;
540
541	if (db->blockcnt == 0) {
542		root = (struct ext2_dx_root_info *) (block_buf + 24);
543
544#ifdef DX_DEBUG
545		printf("Root node dump:\n");
546		printf("\t Reserved zero: %u\n", root->reserved_zero);
547		printf("\t Hash Version: %d\n", root->hash_version);
548		printf("\t Info length: %d\n", root->info_length);
549		printf("\t Indirect levels: %d\n", root->indirect_levels);
550		printf("\t Flags: %d\n", root->unused_flags);
551#endif
552
553		ent = (struct ext2_dx_entry *) (block_buf + 24 + root->info_length);
554	} else {
555		ent = (struct ext2_dx_entry *) (block_buf+8);
556	}
557	limit = (struct ext2_dx_countlimit *) ent;
558
559#ifdef DX_DEBUG
560	printf("Number of entries (count): %d\n",
561	       ext2fs_le16_to_cpu(limit->count));
562	printf("Number of entries (limit): %d\n",
563	       ext2fs_le16_to_cpu(limit->limit));
564#endif
565
566	count = ext2fs_le16_to_cpu(limit->count);
567	expect_limit = (fs->blocksize - ((char *) ent - block_buf)) /
568		sizeof(struct ext2_dx_entry);
569	if (ext2fs_le16_to_cpu(limit->limit) != expect_limit) {
570		cd->pctx.num = ext2fs_le16_to_cpu(limit->limit);
571		if (fix_problem(cd->ctx, PR_2_HTREE_BAD_LIMIT, &cd->pctx))
572			goto clear_and_exit;
573	}
574	if (count > expect_limit) {
575		cd->pctx.num = count;
576		if (fix_problem(cd->ctx, PR_2_HTREE_BAD_COUNT, &cd->pctx))
577			goto clear_and_exit;
578		count = expect_limit;
579	}
580
581	for (i=0; i < count; i++) {
582		prev_hash = hash;
583		hash = i ? (ext2fs_le32_to_cpu(ent[i].hash) & ~1) : 0;
584#ifdef DX_DEBUG
585		printf("Entry #%d: Hash 0x%08x, block %u\n", i,
586		       hash, ext2fs_le32_to_cpu(ent[i].block));
587#endif
588		blk = ext2fs_le32_to_cpu(ent[i].block) & 0x0ffffff;
589		/* Check to make sure the block is valid */
590		if (blk >= (blk_t) dx_dir->numblocks) {
591			cd->pctx.blk = blk;
592			if (fix_problem(cd->ctx, PR_2_HTREE_BADBLK,
593					&cd->pctx))
594				goto clear_and_exit;
595			continue;
596		}
597		if (hash < prev_hash &&
598		    fix_problem(cd->ctx, PR_2_HTREE_HASH_ORDER, &cd->pctx))
599			goto clear_and_exit;
600		dx_db = &dx_dir->dx_block[blk];
601		if (dx_db->flags & DX_FLAG_REFERENCED) {
602			dx_db->flags |= DX_FLAG_DUP_REF;
603		} else {
604			dx_db->flags |= DX_FLAG_REFERENCED;
605			dx_db->parent = db->blockcnt;
606		}
607		if (hash < min_hash)
608			min_hash = hash;
609		if (hash > max_hash)
610			max_hash = hash;
611		dx_db->node_min_hash = hash;
612		if ((i+1) < count)
613			dx_db->node_max_hash =
614			  ext2fs_le32_to_cpu(ent[i+1].hash) & ~1;
615		else {
616			dx_db->node_max_hash = 0xfffffffe;
617			dx_db->flags |= DX_FLAG_LAST;
618		}
619		if (i == 0)
620			dx_db->flags |= DX_FLAG_FIRST;
621	}
622#ifdef DX_DEBUG
623	printf("Blockcnt = %d, min hash 0x%08x, max hash 0x%08x\n",
624	       db->blockcnt, min_hash, max_hash);
625#endif
626	dx_db = &dx_dir->dx_block[db->blockcnt];
627	dx_db->min_hash = min_hash;
628	dx_db->max_hash = max_hash;
629	return;
630
631clear_and_exit:
632	clear_htree(cd->ctx, cd->pctx.ino);
633	dx_dir->numblocks = 0;
634}
635#endif /* ENABLE_HTREE */
636
637/*
638 * Given a busted directory, try to salvage it somehow.
639 *
640 */
641static void salvage_directory(ext2_filsys fs,
642			      struct ext2_dir_entry *dirent,
643			      struct ext2_dir_entry *prev,
644			      unsigned int *offset)
645{
646	char	*cp = (char *) dirent;
647	int left;
648	unsigned int rec_len, prev_rec_len;
649	unsigned int name_len = dirent->name_len & 0xFF;
650
651	(void) ext2fs_get_rec_len(fs, dirent, &rec_len);
652	left = fs->blocksize - *offset - rec_len;
653
654	/*
655	 * Special case of directory entry of size 8: copy what's left
656	 * of the directory block up to cover up the invalid hole.
657	 */
658	if ((left >= 12) && (rec_len == 8)) {
659		memmove(cp, cp+8, left);
660		memset(cp + left, 0, 8);
661		return;
662	}
663	/*
664	 * If the directory entry overruns the end of the directory
665	 * block, and the name is small enough to fit, then adjust the
666	 * record length.
667	 */
668	if ((left < 0) &&
669	    ((int) rec_len + left > 8) &&
670	    ((int) name_len + 8 <= (int) rec_len + left) &&
671	    dirent->inode <= fs->super->s_inodes_count &&
672	    strnlen(dirent->name, name_len) == name_len) {
673		(void) ext2fs_set_rec_len(fs, (int) rec_len + left, dirent);
674		return;
675	}
676	/*
677	 * If the record length of the directory entry is a multiple
678	 * of four, and not too big, such that it is valid, let the
679	 * previous directory entry absorb the invalid one.
680	 */
681	if (prev && rec_len && (rec_len % 4) == 0 &&
682	    (*offset + rec_len <= fs->blocksize)) {
683		(void) ext2fs_get_rec_len(fs, prev, &prev_rec_len);
684		prev_rec_len += rec_len;
685		(void) ext2fs_set_rec_len(fs, prev_rec_len, prev);
686		*offset += rec_len;
687		return;
688	}
689	/*
690	 * Default salvage method --- kill all of the directory
691	 * entries for the rest of the block.  We will either try to
692	 * absorb it into the previous directory entry, or create a
693	 * new empty directory entry the rest of the directory block.
694	 */
695	if (prev) {
696		(void) ext2fs_get_rec_len(fs, prev, &prev_rec_len);
697		prev_rec_len += fs->blocksize - *offset;
698		(void) ext2fs_set_rec_len(fs, prev_rec_len, prev);
699		*offset = fs->blocksize;
700	} else {
701		rec_len = fs->blocksize - *offset;
702		(void) ext2fs_set_rec_len(fs, rec_len, dirent);
703		dirent->name_len = 0;
704		dirent->inode = 0;
705	}
706}
707
708static int check_dir_block(ext2_filsys fs,
709			   struct ext2_db_entry2 *db,
710			   void *priv_data)
711{
712 	struct dx_dir_info	*dx_dir;
713#ifdef ENABLE_HTREE
714	struct dx_dirblock_info	*dx_db = 0;
715#endif /* ENABLE_HTREE */
716	struct ext2_dir_entry 	*dirent, *prev;
717	ext2_dirhash_t		hash;
718	unsigned int		offset = 0;
719	int			dir_modified = 0;
720	int			dot_state;
721	unsigned int		rec_len;
722	blk64_t			block_nr = db->blk;
723	ext2_ino_t 		ino = db->ino;
724	ext2_ino_t 		subdir_parent;
725	__u16			links;
726	struct check_dir_struct	*cd;
727	char 			*buf;
728	e2fsck_t		ctx;
729	problem_t		problem;
730	struct ext2_dx_root_info *root;
731	struct ext2_dx_countlimit *limit;
732	static dict_t de_dict;
733	struct problem_context	pctx;
734	int	dups_found = 0;
735	int	ret;
736
737	cd = (struct check_dir_struct *) priv_data;
738	buf = cd->buf;
739	ctx = cd->ctx;
740
741	if (ctx->flags & E2F_FLAG_SIGNAL_MASK || ctx->flags & E2F_FLAG_RESTART)
742		return DIRENT_ABORT;
743
744	if (ctx->progress && (ctx->progress)(ctx, 2, cd->count++, cd->max))
745		return DIRENT_ABORT;
746
747	/*
748	 * Make sure the inode is still in use (could have been
749	 * deleted in the duplicate/bad blocks pass.
750	 */
751	if (!(ext2fs_test_inode_bitmap2(ctx->inode_used_map, ino)))
752		return 0;
753
754	cd->pctx.ino = ino;
755	cd->pctx.blk = block_nr;
756	cd->pctx.blkcount = db->blockcnt;
757	cd->pctx.ino2 = 0;
758	cd->pctx.dirent = 0;
759	cd->pctx.num = 0;
760
761	if (db->blk == 0) {
762		if (allocate_dir_block(ctx, db, buf, &cd->pctx))
763			return 0;
764		block_nr = db->blk;
765	}
766
767	if (db->blockcnt)
768		dot_state = 2;
769	else
770		dot_state = 0;
771
772	if (ctx->dirs_to_hash &&
773	    ext2fs_u32_list_test(ctx->dirs_to_hash, ino))
774		dups_found++;
775
776#if 0
777	printf("In process_dir_block block %lu, #%d, inode %lu\n", block_nr,
778	       db->blockcnt, ino);
779#endif
780
781	ehandler_operation(_("reading directory block"));
782	cd->pctx.errcode = ext2fs_read_dir_block3(fs, block_nr, buf, 0);
783	ehandler_operation(0);
784	if (cd->pctx.errcode == EXT2_ET_DIR_CORRUPTED)
785		cd->pctx.errcode = 0; /* We'll handle this ourselves */
786	if (cd->pctx.errcode) {
787		if (!fix_problem(ctx, PR_2_READ_DIRBLOCK, &cd->pctx)) {
788			ctx->flags |= E2F_FLAG_ABORT;
789			return DIRENT_ABORT;
790		}
791		memset(buf, 0, fs->blocksize);
792	}
793#ifdef ENABLE_HTREE
794	dx_dir = e2fsck_get_dx_dir_info(ctx, ino);
795	if (dx_dir && dx_dir->numblocks) {
796		if (db->blockcnt >= dx_dir->numblocks) {
797			if (fix_problem(ctx, PR_2_UNEXPECTED_HTREE_BLOCK,
798					&pctx)) {
799				clear_htree(ctx, ino);
800				dx_dir->numblocks = 0;
801				dx_db = 0;
802				goto out_htree;
803			}
804			fatal_error(ctx, _("Can not continue."));
805		}
806		dx_db = &dx_dir->dx_block[db->blockcnt];
807		dx_db->type = DX_DIRBLOCK_LEAF;
808		dx_db->phys = block_nr;
809		dx_db->min_hash = ~0;
810		dx_db->max_hash = 0;
811
812		dirent = (struct ext2_dir_entry *) buf;
813		(void) ext2fs_get_rec_len(fs, dirent, &rec_len);
814		limit = (struct ext2_dx_countlimit *) (buf+8);
815		if (db->blockcnt == 0) {
816			root = (struct ext2_dx_root_info *) (buf + 24);
817			dx_db->type = DX_DIRBLOCK_ROOT;
818			dx_db->flags |= DX_FLAG_FIRST | DX_FLAG_LAST;
819			if ((root->reserved_zero ||
820			     root->info_length < 8 ||
821			     root->indirect_levels > 1) &&
822			    fix_problem(ctx, PR_2_HTREE_BAD_ROOT, &cd->pctx)) {
823				clear_htree(ctx, ino);
824				dx_dir->numblocks = 0;
825				dx_db = 0;
826			}
827			dx_dir->hashversion = root->hash_version;
828			if ((dx_dir->hashversion <= EXT2_HASH_TEA) &&
829			    (fs->super->s_flags & EXT2_FLAGS_UNSIGNED_HASH))
830				dx_dir->hashversion += 3;
831			dx_dir->depth = root->indirect_levels + 1;
832		} else if ((dirent->inode == 0) &&
833			   (rec_len == fs->blocksize) &&
834			   (dirent->name_len == 0) &&
835			   (ext2fs_le16_to_cpu(limit->limit) ==
836			    ((fs->blocksize-8) /
837			     sizeof(struct ext2_dx_entry))))
838			dx_db->type = DX_DIRBLOCK_NODE;
839	}
840out_htree:
841#endif /* ENABLE_HTREE */
842
843	dict_init(&de_dict, DICTCOUNT_T_MAX, dict_de_cmp);
844	prev = 0;
845	do {
846		dgrp_t group;
847		ext2_ino_t first_unused_inode;
848
849		problem = 0;
850		dirent = (struct ext2_dir_entry *) (buf + offset);
851		(void) ext2fs_get_rec_len(fs, dirent, &rec_len);
852		cd->pctx.dirent = dirent;
853		cd->pctx.num = offset;
854		if (((offset + rec_len) > fs->blocksize) ||
855		    (rec_len < 12) ||
856		    ((rec_len % 4) != 0) ||
857		    (((dirent->name_len & (unsigned) 0xFF)+8) > rec_len)) {
858			if (fix_problem(ctx, PR_2_DIR_CORRUPTED, &cd->pctx)) {
859				salvage_directory(fs, dirent, prev, &offset);
860				dir_modified++;
861				continue;
862			} else
863				goto abort_free_dict;
864		}
865
866		if (dot_state == 0) {
867			if (check_dot(ctx, dirent, ino, &cd->pctx))
868				dir_modified++;
869		} else if (dot_state == 1) {
870			ret = check_dotdot(ctx, dirent, ino, &cd->pctx);
871			if (ret < 0)
872				goto abort_free_dict;
873			if (ret)
874				dir_modified++;
875		} else if (dirent->inode == ino) {
876			problem = PR_2_LINK_DOT;
877			if (fix_problem(ctx, PR_2_LINK_DOT, &cd->pctx)) {
878				dirent->inode = 0;
879				dir_modified++;
880				goto next;
881			}
882		}
883		if (!dirent->inode)
884			goto next;
885
886		/*
887		 * Make sure the inode listed is a legal one.
888		 */
889		if (((dirent->inode != EXT2_ROOT_INO) &&
890		     (dirent->inode < EXT2_FIRST_INODE(fs->super))) ||
891		    (dirent->inode > fs->super->s_inodes_count)) {
892			problem = PR_2_BAD_INO;
893		} else if (ctx->inode_bb_map &&
894			   (ext2fs_test_inode_bitmap2(ctx->inode_bb_map,
895						     dirent->inode))) {
896			/*
897			 * If the inode is in a bad block, offer to
898			 * clear it.
899			 */
900			problem = PR_2_BB_INODE;
901		} else if ((dot_state > 1) &&
902			   ((dirent->name_len & 0xFF) == 1) &&
903			   (dirent->name[0] == '.')) {
904			/*
905			 * If there's a '.' entry in anything other
906			 * than the first directory entry, it's a
907			 * duplicate entry that should be removed.
908			 */
909			problem = PR_2_DUP_DOT;
910		} else if ((dot_state > 1) &&
911			   ((dirent->name_len & 0xFF) == 2) &&
912			   (dirent->name[0] == '.') &&
913			   (dirent->name[1] == '.')) {
914			/*
915			 * If there's a '..' entry in anything other
916			 * than the second directory entry, it's a
917			 * duplicate entry that should be removed.
918			 */
919			problem = PR_2_DUP_DOT_DOT;
920		} else if ((dot_state > 1) &&
921			   (dirent->inode == EXT2_ROOT_INO)) {
922			/*
923			 * Don't allow links to the root directory.
924			 * We check this specially to make sure we
925			 * catch this error case even if the root
926			 * directory hasn't been created yet.
927			 */
928			problem = PR_2_LINK_ROOT;
929		} else if ((dot_state > 1) &&
930			   (dirent->name_len & 0xFF) == 0) {
931			/*
932			 * Don't allow zero-length directory names.
933			 */
934			problem = PR_2_NULL_NAME;
935		}
936
937		if (problem) {
938			if (fix_problem(ctx, problem, &cd->pctx)) {
939				dirent->inode = 0;
940				dir_modified++;
941				goto next;
942			} else {
943				ext2fs_unmark_valid(fs);
944				if (problem == PR_2_BAD_INO)
945					goto next;
946			}
947		}
948
949		/*
950		 * If the inode was marked as having bad fields in
951		 * pass1, process it and offer to fix/clear it.
952		 * (We wait until now so that we can display the
953		 * pathname to the user.)
954		 */
955		if (ctx->inode_bad_map &&
956		    ext2fs_test_inode_bitmap2(ctx->inode_bad_map,
957					     dirent->inode)) {
958			if (e2fsck_process_bad_inode(ctx, ino,
959						     dirent->inode,
960						     buf + fs->blocksize)) {
961				dirent->inode = 0;
962				dir_modified++;
963				goto next;
964			}
965			if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
966				return DIRENT_ABORT;
967		}
968
969		group = ext2fs_group_of_ino(fs, dirent->inode);
970		first_unused_inode = group * fs->super->s_inodes_per_group +
971					1 + fs->super->s_inodes_per_group -
972					ext2fs_bg_itable_unused(fs, group);
973		cd->pctx.group = group;
974
975		/*
976		 * Check if the inode was missed out because
977		 * _INODE_UNINIT flag was set or bg_itable_unused was
978		 * incorrect.  If so, clear the _INODE_UNINIT flag and
979		 * restart e2fsck.  In the future it would be nice if
980		 * we could call a function in pass1.c that checks the
981		 * newly visible inodes.
982		 */
983		if (ext2fs_bg_flags_test(fs, group, EXT2_BG_INODE_UNINIT)) {
984			pctx.num = dirent->inode;
985			if (fix_problem(ctx, PR_2_INOREF_BG_INO_UNINIT,
986					&cd->pctx)){
987				ext2fs_bg_flags_clear(fs, group,
988						      EXT2_BG_INODE_UNINIT);
989				ext2fs_mark_super_dirty(fs);
990				ctx->flags |= E2F_FLAG_RESTART_LATER;
991			} else {
992				ext2fs_unmark_valid(fs);
993				if (problem == PR_2_BAD_INO)
994					goto next;
995			}
996		} else if (dirent->inode >= first_unused_inode) {
997			pctx.num = dirent->inode;
998			if (fix_problem(ctx, PR_2_INOREF_IN_UNUSED, &cd->pctx)){
999				ext2fs_bg_itable_unused_set(fs, group, 0);
1000				ext2fs_mark_super_dirty(fs);
1001				ctx->flags |= E2F_FLAG_RESTART_LATER;
1002			} else {
1003				ext2fs_unmark_valid(fs);
1004				if (problem == PR_2_BAD_INO)
1005					goto next;
1006			}
1007		}
1008
1009		/*
1010		 * Offer to clear unused inodes; if we are going to be
1011		 * restarting the scan due to bg_itable_unused being
1012		 * wrong, then don't clear any inodes to avoid zapping
1013		 * inodes that were skipped during pass1 due to an
1014		 * incorrect bg_itable_unused; we'll get any real
1015		 * problems after we restart.
1016		 */
1017		if (!(ctx->flags & E2F_FLAG_RESTART_LATER) &&
1018		    !(ext2fs_test_inode_bitmap2(ctx->inode_used_map,
1019						dirent->inode)))
1020			problem = PR_2_UNUSED_INODE;
1021
1022		if (problem) {
1023			if (fix_problem(ctx, problem, &cd->pctx)) {
1024				dirent->inode = 0;
1025				dir_modified++;
1026				goto next;
1027			} else {
1028				ext2fs_unmark_valid(fs);
1029				if (problem == PR_2_BAD_INO)
1030					goto next;
1031			}
1032		}
1033
1034		if (check_name(ctx, dirent, ino, &cd->pctx))
1035			dir_modified++;
1036
1037		if (check_filetype(ctx, dirent, ino, &cd->pctx))
1038			dir_modified++;
1039
1040#ifdef ENABLE_HTREE
1041		if (dx_db) {
1042			ext2fs_dirhash(dx_dir->hashversion, dirent->name,
1043				       (dirent->name_len & 0xFF),
1044				       fs->super->s_hash_seed, &hash, 0);
1045			if (hash < dx_db->min_hash)
1046				dx_db->min_hash = hash;
1047			if (hash > dx_db->max_hash)
1048				dx_db->max_hash = hash;
1049		}
1050#endif
1051
1052		/*
1053		 * If this is a directory, then mark its parent in its
1054		 * dir_info structure.  If the parent field is already
1055		 * filled in, then this directory has more than one
1056		 * hard link.  We assume the first link is correct,
1057		 * and ask the user if he/she wants to clear this one.
1058		 */
1059		if ((dot_state > 1) &&
1060		    (ext2fs_test_inode_bitmap2(ctx->inode_dir_map,
1061					      dirent->inode))) {
1062			if (e2fsck_dir_info_get_parent(ctx, dirent->inode,
1063						       &subdir_parent)) {
1064				cd->pctx.ino = dirent->inode;
1065				fix_problem(ctx, PR_2_NO_DIRINFO, &cd->pctx);
1066				goto abort_free_dict;
1067			}
1068			if (subdir_parent) {
1069				cd->pctx.ino2 = subdir_parent;
1070				if (fix_problem(ctx, PR_2_LINK_DIR,
1071						&cd->pctx)) {
1072					dirent->inode = 0;
1073					dir_modified++;
1074					goto next;
1075				}
1076				cd->pctx.ino2 = 0;
1077			} else {
1078				(void) e2fsck_dir_info_set_parent(ctx,
1079						  dirent->inode, ino);
1080			}
1081		}
1082
1083		if (dups_found) {
1084			;
1085		} else if (dict_lookup(&de_dict, dirent)) {
1086			clear_problem_context(&pctx);
1087			pctx.ino = ino;
1088			pctx.dirent = dirent;
1089			fix_problem(ctx, PR_2_REPORT_DUP_DIRENT, &pctx);
1090			if (!ctx->dirs_to_hash)
1091				ext2fs_u32_list_create(&ctx->dirs_to_hash, 50);
1092			if (ctx->dirs_to_hash)
1093				ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
1094			dups_found++;
1095		} else
1096			dict_alloc_insert(&de_dict, dirent, dirent);
1097
1098		ext2fs_icount_increment(ctx->inode_count, dirent->inode,
1099					&links);
1100		if (links > 1)
1101			ctx->fs_links_count++;
1102		ctx->fs_total_count++;
1103	next:
1104		prev = dirent;
1105		if (dir_modified)
1106			(void) ext2fs_get_rec_len(fs, dirent, &rec_len);
1107		offset += rec_len;
1108		dot_state++;
1109	} while (offset < fs->blocksize);
1110#if 0
1111	printf("\n");
1112#endif
1113#ifdef ENABLE_HTREE
1114	if (dx_db) {
1115#ifdef DX_DEBUG
1116		printf("db_block %d, type %d, min_hash 0x%0x, max_hash 0x%0x\n",
1117		       db->blockcnt, dx_db->type,
1118		       dx_db->min_hash, dx_db->max_hash);
1119#endif
1120		cd->pctx.dir = cd->pctx.ino;
1121		if ((dx_db->type == DX_DIRBLOCK_ROOT) ||
1122		    (dx_db->type == DX_DIRBLOCK_NODE))
1123			parse_int_node(fs, db, cd, dx_dir, buf);
1124	}
1125#endif /* ENABLE_HTREE */
1126	if (offset != fs->blocksize) {
1127		cd->pctx.num = rec_len - fs->blocksize + offset;
1128		if (fix_problem(ctx, PR_2_FINAL_RECLEN, &cd->pctx)) {
1129			dirent->rec_len = cd->pctx.num;
1130			dir_modified++;
1131		}
1132	}
1133	if (dir_modified) {
1134		cd->pctx.errcode = ext2fs_write_dir_block3(fs, block_nr, buf, 0);
1135		if (cd->pctx.errcode) {
1136			if (!fix_problem(ctx, PR_2_WRITE_DIRBLOCK,
1137					 &cd->pctx))
1138				goto abort_free_dict;
1139		}
1140		ext2fs_mark_changed(fs);
1141	}
1142	dict_free_nodes(&de_dict);
1143	return 0;
1144abort_free_dict:
1145	ctx->flags |= E2F_FLAG_ABORT;
1146	dict_free_nodes(&de_dict);
1147	return DIRENT_ABORT;
1148}
1149
1150struct del_block {
1151	e2fsck_t	ctx;
1152	e2_blkcnt_t	num;
1153};
1154
1155/*
1156 * This function is called to deallocate a block, and is an interator
1157 * functioned called by deallocate inode via ext2fs_iterate_block().
1158 */
1159static int deallocate_inode_block(ext2_filsys fs,
1160				  blk64_t	*block_nr,
1161				  e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
1162				  blk64_t ref_block EXT2FS_ATTR((unused)),
1163				  int ref_offset EXT2FS_ATTR((unused)),
1164				  void *priv_data)
1165{
1166	struct del_block *p = priv_data;
1167
1168	if (HOLE_BLKADDR(*block_nr))
1169		return 0;
1170	if ((*block_nr < fs->super->s_first_data_block) ||
1171	    (*block_nr >= ext2fs_blocks_count(fs->super)))
1172		return 0;
1173	ext2fs_unmark_block_bitmap2(p->ctx->block_found_map, *block_nr);
1174	ext2fs_block_alloc_stats2(fs, *block_nr, -1);
1175	p->num++;
1176	return 0;
1177}
1178
1179/*
1180 * This fuction deallocates an inode
1181 */
1182static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf)
1183{
1184	ext2_filsys fs = ctx->fs;
1185	struct ext2_inode	inode;
1186	struct problem_context	pctx;
1187	__u32			count;
1188	struct del_block	del_block;
1189
1190	e2fsck_read_inode(ctx, ino, &inode, "deallocate_inode");
1191	clear_problem_context(&pctx);
1192	pctx.ino = ino;
1193
1194	/*
1195	 * Fix up the bitmaps...
1196	 */
1197	e2fsck_read_bitmaps(ctx);
1198	ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode));
1199
1200	if (ext2fs_file_acl_block(fs, &inode) &&
1201	    (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) {
1202		pctx.errcode = ext2fs_adjust_ea_refcount2(fs,
1203					ext2fs_file_acl_block(fs, &inode),
1204					block_buf, -1, &count);
1205		if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) {
1206			pctx.errcode = 0;
1207			count = 1;
1208		}
1209		if (pctx.errcode) {
1210			pctx.blk = ext2fs_file_acl_block(fs, &inode);
1211			fix_problem(ctx, PR_2_ADJ_EA_REFCOUNT, &pctx);
1212			ctx->flags |= E2F_FLAG_ABORT;
1213			return;
1214		}
1215		if (count == 0) {
1216			ext2fs_unmark_block_bitmap2(ctx->block_found_map,
1217					ext2fs_file_acl_block(fs, &inode));
1218			ext2fs_block_alloc_stats2(fs,
1219				  ext2fs_file_acl_block(fs, &inode), -1);
1220		}
1221		ext2fs_file_acl_block_set(fs, &inode, 0);
1222	}
1223
1224	if (!ext2fs_inode_has_valid_blocks2(fs, &inode))
1225		goto clear_inode;
1226
1227	if (LINUX_S_ISREG(inode.i_mode) &&
1228	    ext2fs_needs_large_file_feature(EXT2_I_SIZE(&inode)))
1229		ctx->large_files--;
1230
1231	del_block.ctx = ctx;
1232	del_block.num = 0;
1233	pctx.errcode = ext2fs_block_iterate3(fs, ino, 0, block_buf,
1234					     deallocate_inode_block,
1235					     &del_block);
1236	if (pctx.errcode) {
1237		fix_problem(ctx, PR_2_DEALLOC_INODE, &pctx);
1238		ctx->flags |= E2F_FLAG_ABORT;
1239		return;
1240	}
1241clear_inode:
1242	/* Inode may have changed by block_iterate, so reread it */
1243	e2fsck_read_inode(ctx, ino, &inode, "deallocate_inode");
1244	e2fsck_clear_inode(ctx, ino, &inode, 0, "deallocate_inode");
1245}
1246
1247/*
1248 * This fuction clears the htree flag on an inode
1249 */
1250static void clear_htree(e2fsck_t ctx, ext2_ino_t ino)
1251{
1252	struct ext2_inode	inode;
1253
1254	e2fsck_read_inode(ctx, ino, &inode, "clear_htree");
1255	inode.i_flags = inode.i_flags & ~EXT2_INDEX_FL;
1256	e2fsck_write_inode(ctx, ino, &inode, "clear_htree");
1257	if (ctx->dirs_to_hash)
1258		ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
1259}
1260
1261
1262int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir,
1263			     ext2_ino_t ino, char *buf)
1264{
1265	ext2_filsys fs = ctx->fs;
1266	struct ext2_inode	inode;
1267	int			inode_modified = 0;
1268	int			not_fixed = 0;
1269	unsigned char		*frag, *fsize;
1270	struct problem_context	pctx;
1271	problem_t		problem = 0;
1272
1273	e2fsck_read_inode(ctx, ino, &inode, "process_bad_inode");
1274
1275	clear_problem_context(&pctx);
1276	pctx.ino = ino;
1277	pctx.dir = dir;
1278	pctx.inode = &inode;
1279
1280	if (ext2fs_file_acl_block(fs, &inode) &&
1281	    !(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) {
1282		if (fix_problem(ctx, PR_2_FILE_ACL_ZERO, &pctx)) {
1283			ext2fs_file_acl_block_set(fs, &inode, 0);
1284			inode_modified++;
1285		} else
1286			not_fixed++;
1287	}
1288
1289	if (!LINUX_S_ISDIR(inode.i_mode) && !LINUX_S_ISREG(inode.i_mode) &&
1290	    !LINUX_S_ISCHR(inode.i_mode) && !LINUX_S_ISBLK(inode.i_mode) &&
1291	    !LINUX_S_ISLNK(inode.i_mode) && !LINUX_S_ISFIFO(inode.i_mode) &&
1292	    !(LINUX_S_ISSOCK(inode.i_mode)))
1293		problem = PR_2_BAD_MODE;
1294	else if (LINUX_S_ISCHR(inode.i_mode)
1295		 && !e2fsck_pass1_check_device_inode(fs, &inode))
1296		problem = PR_2_BAD_CHAR_DEV;
1297	else if (LINUX_S_ISBLK(inode.i_mode)
1298		 && !e2fsck_pass1_check_device_inode(fs, &inode))
1299		problem = PR_2_BAD_BLOCK_DEV;
1300	else if (LINUX_S_ISFIFO(inode.i_mode)
1301		 && !e2fsck_pass1_check_device_inode(fs, &inode))
1302		problem = PR_2_BAD_FIFO;
1303	else if (LINUX_S_ISSOCK(inode.i_mode)
1304		 && !e2fsck_pass1_check_device_inode(fs, &inode))
1305		problem = PR_2_BAD_SOCKET;
1306	else if (LINUX_S_ISLNK(inode.i_mode)
1307		 && !e2fsck_pass1_check_symlink(fs, ino, &inode, buf)) {
1308		problem = PR_2_INVALID_SYMLINK;
1309	}
1310
1311	if (problem) {
1312		if (fix_problem(ctx, problem, &pctx)) {
1313			deallocate_inode(ctx, ino, 0);
1314			if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
1315				return 0;
1316			return 1;
1317		} else
1318			not_fixed++;
1319		problem = 0;
1320	}
1321
1322	if (inode.i_faddr) {
1323		if (fix_problem(ctx, PR_2_FADDR_ZERO, &pctx)) {
1324			inode.i_faddr = 0;
1325			inode_modified++;
1326		} else
1327			not_fixed++;
1328	}
1329
1330	switch (fs->super->s_creator_os) {
1331	    case EXT2_OS_HURD:
1332		frag = &inode.osd2.hurd2.h_i_frag;
1333		fsize = &inode.osd2.hurd2.h_i_fsize;
1334		break;
1335	    default:
1336		frag = fsize = 0;
1337	}
1338	if (frag && *frag) {
1339		pctx.num = *frag;
1340		if (fix_problem(ctx, PR_2_FRAG_ZERO, &pctx)) {
1341			*frag = 0;
1342			inode_modified++;
1343		} else
1344			not_fixed++;
1345		pctx.num = 0;
1346	}
1347	if (fsize && *fsize) {
1348		pctx.num = *fsize;
1349		if (fix_problem(ctx, PR_2_FSIZE_ZERO, &pctx)) {
1350			*fsize = 0;
1351			inode_modified++;
1352		} else
1353			not_fixed++;
1354		pctx.num = 0;
1355	}
1356
1357	if ((fs->super->s_creator_os == EXT2_OS_LINUX) &&
1358	    !(fs->super->s_feature_ro_compat &
1359	      EXT4_FEATURE_RO_COMPAT_HUGE_FILE) &&
1360	    (inode.osd2.linux2.l_i_blocks_hi != 0)) {
1361		pctx.num = inode.osd2.linux2.l_i_blocks_hi;
1362		if (fix_problem(ctx, PR_2_BLOCKS_HI_ZERO, &pctx)) {
1363			inode.osd2.linux2.l_i_blocks_hi = 0;
1364			inode_modified++;
1365		}
1366	}
1367
1368	if (!(fs->super->s_feature_incompat &
1369	     EXT4_FEATURE_INCOMPAT_64BIT) &&
1370	    inode.osd2.linux2.l_i_file_acl_high != 0) {
1371		pctx.num = inode.osd2.linux2.l_i_file_acl_high;
1372		if (fix_problem(ctx, PR_2_I_FILE_ACL_HI_ZERO, &pctx)) {
1373			inode.osd2.linux2.l_i_file_acl_high = 0;
1374			inode_modified++;
1375		} else
1376			not_fixed++;
1377	}
1378
1379	if (ext2fs_file_acl_block(fs, &inode) &&
1380	    ((ext2fs_file_acl_block(fs, &inode) < fs->super->s_first_data_block) ||
1381	     (ext2fs_file_acl_block(fs, &inode) >= ext2fs_blocks_count(fs->super)))) {
1382		if (fix_problem(ctx, PR_2_FILE_ACL_BAD, &pctx)) {
1383			ext2fs_file_acl_block_set(fs, &inode, 0);
1384			inode_modified++;
1385		} else
1386			not_fixed++;
1387	}
1388	if (inode.i_dir_acl &&
1389	    LINUX_S_ISDIR(inode.i_mode)) {
1390		if (fix_problem(ctx, PR_2_DIR_ACL_ZERO, &pctx)) {
1391			inode.i_dir_acl = 0;
1392			inode_modified++;
1393		} else
1394			not_fixed++;
1395	}
1396
1397	if (inode_modified)
1398		e2fsck_write_inode(ctx, ino, &inode, "process_bad_inode");
1399	if (!not_fixed && ctx->inode_bad_map)
1400		ext2fs_unmark_inode_bitmap2(ctx->inode_bad_map, ino);
1401	return 0;
1402}
1403
1404
1405/*
1406 * allocate_dir_block --- this function allocates a new directory
1407 * 	block for a particular inode; this is done if a directory has
1408 * 	a "hole" in it, or if a directory has a illegal block number
1409 * 	that was zeroed out and now needs to be replaced.
1410 */
1411static int allocate_dir_block(e2fsck_t ctx,
1412			      struct ext2_db_entry2 *db,
1413			      char *buf EXT2FS_ATTR((unused)),
1414			      struct problem_context *pctx)
1415{
1416	ext2_filsys fs = ctx->fs;
1417	blk64_t			blk;
1418	char			*block;
1419	struct ext2_inode	inode;
1420
1421	if (fix_problem(ctx, PR_2_DIRECTORY_HOLE, pctx) == 0)
1422		return 1;
1423
1424	/*
1425	 * Read the inode and block bitmaps in; we'll be messing with
1426	 * them.
1427	 */
1428	e2fsck_read_bitmaps(ctx);
1429
1430	/*
1431	 * First, find a free block
1432	 */
1433	pctx->errcode = ext2fs_new_block2(fs, 0, ctx->block_found_map, &blk);
1434	if (pctx->errcode) {
1435		pctx->str = "ext2fs_new_block";
1436		fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
1437		return 1;
1438	}
1439	ext2fs_mark_block_bitmap2(ctx->block_found_map, blk);
1440	ext2fs_mark_block_bitmap2(fs->block_map, blk);
1441	ext2fs_mark_bb_dirty(fs);
1442
1443	/*
1444	 * Now let's create the actual data block for the inode
1445	 */
1446	if (db->blockcnt)
1447		pctx->errcode = ext2fs_new_dir_block(fs, 0, 0, &block);
1448	else
1449		pctx->errcode = ext2fs_new_dir_block(fs, db->ino,
1450						     EXT2_ROOT_INO, &block);
1451
1452	if (pctx->errcode) {
1453		pctx->str = "ext2fs_new_dir_block";
1454		fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
1455		return 1;
1456	}
1457
1458	pctx->errcode = ext2fs_write_dir_block3(fs, blk, block, 0);
1459	ext2fs_free_mem(&block);
1460	if (pctx->errcode) {
1461		pctx->str = "ext2fs_write_dir_block";
1462		fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
1463		return 1;
1464	}
1465
1466	/*
1467	 * Update the inode block count
1468	 */
1469	e2fsck_read_inode(ctx, db->ino, &inode, "allocate_dir_block");
1470	ext2fs_iblk_add_blocks(fs, &inode, 1);
1471	if (inode.i_size < (db->blockcnt+1) * fs->blocksize)
1472		inode.i_size = (db->blockcnt+1) * fs->blocksize;
1473	e2fsck_write_inode(ctx, db->ino, &inode, "allocate_dir_block");
1474
1475	/*
1476	 * Finally, update the block pointers for the inode
1477	 */
1478	db->blk = blk;
1479	pctx->errcode = ext2fs_bmap2(fs, db->ino, &inode, 0, BMAP_SET,
1480				     db->blockcnt, 0, &blk);
1481	if (pctx->errcode) {
1482		pctx->str = "ext2fs_block_iterate";
1483		fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
1484		return 1;
1485	}
1486
1487	return 0;
1488}
1489