pass3.c revision 5596defa1e212242c1bf1b028139143fbb7777a0
13839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
23839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * pass3.c -- pass #3 of e2fsck: Check for directory connectivity
33839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *
421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o.
521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o *
621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * %Begin-Header%
721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * This file may be redistributed under the terms of the GNU Public
821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * License.
921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * %End-Header%
103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *
113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Pass #3 assures that all directories are connected to the
123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * filesystem tree, using the following algorithm:
133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *
143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * First, the root directory is checked to make sure it exists; if
153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * not, e2fsck will offer to create a new one.  It is then marked as
163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * "done".
173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *
183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Then, pass3 interates over all directory inodes; for each directory
193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * it attempts to trace up the filesystem tree, using dirinfo.parent
203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * until it reaches a directory which has been marked "done".  If it
213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * can not do so, then the directory must be disconnected, and e2fsck
223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * will offer to reconnect it to /lost+found.  While it is chasing
233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * parent pointers up the filesystem tree, if pass3 sees a directory
243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * twice, then it has detected a filesystem loop, and it will again
253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * offer to reconnect the directory to /lost+found in to break the
263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * filesystem loop.
273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *
2808b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o * Pass 3 also contains the subroutine, e2fsck_reconnect_file() to
2908b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o * reconnect inodes to /lost+found; this subroutine is also used by
3008b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o * pass 4.  e2fsck_reconnect_file() calls get_lost_and_found(), which
3108b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o * is responsible for creating /lost+found if it does not exist.
323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *
333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Pass 3 frees the following data structures:
343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *     	- The dirinfo directory information cache.
353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
3750e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o#ifdef HAVE_ERRNO_H
3850e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o#include <errno.h>
3950e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o#endif
403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include "e2fsck.h"
4221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o#include "problem.h"
433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
441b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'ostatic void check_root(e2fsck_t ctx);
451b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'ostatic void check_directory(e2fsck_t ctx, struct dir_info *dir,
4621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			    struct problem_context *pctx);
471b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'ostatic ino_t get_lost_and_found(e2fsck_t ctx);
481b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'ostatic void fix_dotdot(e2fsck_t ctx, struct dir_info *dir, ino_t parent);
491b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'ostatic errcode_t adjust_inode_count(e2fsck_t ctx, ino_t ino, int adj);
501b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'ostatic errcode_t expand_directory(e2fsck_t ctx, ino_t dir);
513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic ino_t lost_and_found = 0;
533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic int bad_lost_and_found = 0;
543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
55a02ce9df5ff5db2982462aec7162f7142dc18131Theodore Ts'ostatic ext2fs_inode_bitmap inode_loop_detect = 0;
56a02ce9df5ff5db2982462aec7162f7142dc18131Theodore Ts'ostatic ext2fs_inode_bitmap inode_done_map = 0;
573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5808b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'ovoid e2fsck_pass3(e2fsck_t ctx)
593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
601b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ext2_filsys fs = ctx->fs;
613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int		i;
628bf191e8660939687ef35c013066d2082cb16722Theodore Ts'o#ifdef RESOURCE_TRACK
633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct resource_track	rtrack;
648bf191e8660939687ef35c013066d2082cb16722Theodore Ts'o#endif
6521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	struct problem_context	pctx;
6621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	struct dir_info	*dir;
677f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o	unsigned long maxdirs, count;
68f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o
698bf191e8660939687ef35c013066d2082cb16722Theodore Ts'o#ifdef RESOURCE_TRACK
703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	init_resource_track(&rtrack);
718bf191e8660939687ef35c013066d2082cb16722Theodore Ts'o#endif
723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
731b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	clear_problem_context(&pctx);
741b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o
753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#ifdef MTRACE
763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	mtrace_print("Pass 3");
773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#endif
783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
791b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (!(ctx->options & E2F_OPT_PREEN))
801b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_3_PASS_HEADER, &pctx);
813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Allocate some bitmaps to do loop detection.
843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
851b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	pctx.errcode = ext2fs_allocate_inode_bitmap(fs,
861b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		    "inode loop detection bitmap", &inode_loop_detect);
871b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (pctx.errcode) {
881b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx.num = 1;
891b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_3_ALLOCATE_IBITMAP_ERROR, &pctx);
9008b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		ctx->flags |= E2F_FLAG_ABORT;
91a02ce9df5ff5db2982462aec7162f7142dc18131Theodore Ts'o		goto abort_exit;
923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
931b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	pctx.errcode = ext2fs_allocate_inode_bitmap(fs, "inode done bitmap",
941b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o						    &inode_done_map);
951b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (pctx.errcode) {
961b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx.num = 2;
971b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_3_ALLOCATE_IBITMAP_ERROR, &pctx);
9808b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		ctx->flags |= E2F_FLAG_ABORT;
99a02ce9df5ff5db2982462aec7162f7142dc18131Theodore Ts'o		goto abort_exit;
1003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
1018bf191e8660939687ef35c013066d2082cb16722Theodore Ts'o#ifdef RESOURCE_TRACK
1025596defa1e212242c1bf1b028139143fbb7777a0Theodore Ts'o	if (ctx->options & E2F_OPT_TIME) {
1035596defa1e212242c1bf1b028139143fbb7777a0Theodore Ts'o		e2fsck_clear_progbar(ctx);
1041b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		print_resource_track("Peak memory", &ctx->global_rtrack);
1055596defa1e212242c1bf1b028139143fbb7777a0Theodore Ts'o	}
1068bf191e8660939687ef35c013066d2082cb16722Theodore Ts'o#endif
1073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1081b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	check_root(ctx);
109a02ce9df5ff5db2982462aec7162f7142dc18131Theodore Ts'o	if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
110a02ce9df5ff5db2982462aec7162f7142dc18131Theodore Ts'o		goto abort_exit;
11108b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o
112f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	ext2fs_mark_inode_bitmap(inode_done_map, EXT2_ROOT_INO);
1133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1147f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o	maxdirs = e2fsck_get_num_dirinfo(ctx);
115f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	count = 1;
116f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o
117f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	if (ctx->progress)
1187f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o		if ((ctx->progress)(ctx, 3, 0, maxdirs))
119f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o			goto abort_exit;
120f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o
12108b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o	for (i=0; (dir = e2fsck_dir_info_iter(ctx, &i)) != 0;) {
122f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o		if (ctx->progress)
1237f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o			if ((ctx->progress)(ctx, 3, count++, maxdirs))
124a02ce9df5ff5db2982462aec7162f7142dc18131Theodore Ts'o				goto abort_exit;
1251b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, dir->ino))
1261b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			check_directory(ctx, dir, &pctx);
1273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
128a02ce9df5ff5db2982462aec7162f7142dc18131Theodore Ts'o
1295a679c8fb15540f86fc2eae3117412adc6ecbb33Theodore Ts'o	/*
1305a679c8fb15540f86fc2eae3117412adc6ecbb33Theodore Ts'o	 * Force the creation of /lost+found if not present
1315a679c8fb15540f86fc2eae3117412adc6ecbb33Theodore Ts'o	 */
1325a679c8fb15540f86fc2eae3117412adc6ecbb33Theodore Ts'o	if ((ctx->flags & E2F_OPT_READONLY) == 0)
1335a679c8fb15540f86fc2eae3117412adc6ecbb33Theodore Ts'o		get_lost_and_found(ctx);
1345a679c8fb15540f86fc2eae3117412adc6ecbb33Theodore Ts'o
135a02ce9df5ff5db2982462aec7162f7142dc18131Theodore Ts'oabort_exit:
13608b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o	e2fsck_free_dir_info(ctx);
137a02ce9df5ff5db2982462aec7162f7142dc18131Theodore Ts'o	if (inode_loop_detect)
138a02ce9df5ff5db2982462aec7162f7142dc18131Theodore Ts'o		ext2fs_free_inode_bitmap(inode_loop_detect);
139a02ce9df5ff5db2982462aec7162f7142dc18131Theodore Ts'o	if (inode_done_map)
140a02ce9df5ff5db2982462aec7162f7142dc18131Theodore Ts'o		ext2fs_free_inode_bitmap(inode_done_map);
1418bf191e8660939687ef35c013066d2082cb16722Theodore Ts'o#ifdef RESOURCE_TRACK
1425596defa1e212242c1bf1b028139143fbb7777a0Theodore Ts'o	if (ctx->options & E2F_OPT_TIME2) {
1435596defa1e212242c1bf1b028139143fbb7777a0Theodore Ts'o		e2fsck_clear_progbar(ctx);
1441b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		print_resource_track("Pass 3", &rtrack);
1455596defa1e212242c1bf1b028139143fbb7777a0Theodore Ts'o	}
1468bf191e8660939687ef35c013066d2082cb16722Theodore Ts'o#endif
1473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
1483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
1503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * This makes sure the root inode is present; if not, we ask if the
1513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * user wants us to create it.  Not creating it is a fatal error.
1523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
1531b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'ostatic void check_root(e2fsck_t ctx)
1543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
1551b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ext2_filsys fs = ctx->fs;
1563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	blk_t			blk;
1573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct ext2_inode	inode;
1583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char *			block;
1591b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	struct problem_context	pctx;
1603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1611b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	clear_problem_context(&pctx);
1621b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o
1631b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (ext2fs_test_inode_bitmap(ctx->inode_used_map, EXT2_ROOT_INO)) {
1643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		/*
16508b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		 * If the root inode is not a directory, die here.  The
1663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * user must have answered 'no' in pass1 when we
1673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * offered to clear it.
1683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 */
1691b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		if (!(ext2fs_test_inode_bitmap(ctx->inode_dir_map,
170f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o					       EXT2_ROOT_INO))) {
171f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o			fix_problem(ctx, PR_3_ROOT_NOT_DIR_ABORT, &pctx);
172f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o			ctx->flags |= E2F_FLAG_ABORT;
173f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o		}
1743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return;
1753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
1763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
177f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o	if (!fix_problem(ctx, PR_3_NO_ROOT_INODE, &pctx)) {
178f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o		fix_problem(ctx, PR_3_NO_ROOT_INODE_ABORT, &pctx);
179f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o		ctx->flags |= E2F_FLAG_ABORT;
180f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o		return;
181f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o	}
1823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
183f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o	e2fsck_read_bitmaps(ctx);
1843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
1863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * First, find a free block
1873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
1881b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	pctx.errcode = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk);
1891b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (pctx.errcode) {
1901b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx.str = "ext2fs_new_block";
1911b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
19208b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		ctx->flags |= E2F_FLAG_ABORT;
19308b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		return;
1943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
1951b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
196f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	ext2fs_mark_block_bitmap(fs->block_map, blk);
1973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	ext2fs_mark_bb_dirty(fs);
1983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
2003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Now let's create the actual data block for the inode
2013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
2021b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	pctx.errcode = ext2fs_new_dir_block(fs, EXT2_ROOT_INO, EXT2_ROOT_INO,
2031b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o					    &block);
2041b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (pctx.errcode) {
2051b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx.str = "ext2fs_new_dir_block";
2061b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
20708b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		ctx->flags |= E2F_FLAG_ABORT;
20808b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		return;
2093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
2103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
2111b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	pctx.errcode = ext2fs_write_dir_block(fs, blk, block);
2121b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (pctx.errcode) {
2131b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx.str = "ext2fs_write_dir_block";
2141b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
21508b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		ctx->flags |= E2F_FLAG_ABORT;
21608b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		return;
2173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
21808b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o	ext2fs_free_mem((void **) &block);
2193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
2203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
2213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Set up the inode structure
2223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
2233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	memset(&inode, 0, sizeof(inode));
2243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_mode = 040755;
2253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_size = fs->blocksize;
2263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_atime = inode.i_ctime = inode.i_mtime = time(0);
2273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_links_count = 2;
2283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_blocks = fs->blocksize / 512;
2293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_block[0] = blk;
2303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
2313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
2323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Write out the inode.
2333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
2341b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	pctx.errcode = ext2fs_write_inode(fs, EXT2_ROOT_INO, &inode);
2351b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (pctx.errcode) {
2361b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx.str = "ext2fs_write_inode";
2371b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
23808b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		ctx->flags |= E2F_FLAG_ABORT;
23908b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		return;
2403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
2413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
2423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
2433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Miscellaneous bookkeeping...
2443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
24508b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o	e2fsck_add_dir_info(ctx, EXT2_ROOT_INO, EXT2_ROOT_INO);
2461b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ext2fs_icount_store(ctx->inode_count, EXT2_ROOT_INO, 2);
2471b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ext2fs_icount_store(ctx->inode_link_info, EXT2_ROOT_INO, 2);
2483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
2491b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ext2fs_mark_inode_bitmap(ctx->inode_used_map, EXT2_ROOT_INO);
2501b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ext2fs_mark_inode_bitmap(ctx->inode_dir_map, EXT2_ROOT_INO);
251f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	ext2fs_mark_inode_bitmap(fs->inode_map, EXT2_ROOT_INO);
2523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	ext2fs_mark_ib_dirty(fs);
2533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
2543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
2553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
2563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * This subroutine is responsible for making sure that a particular
2573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * directory is connected to the root; if it isn't we trace it up as
2583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * far as we can go, and then offer to connect the resulting parent to
2593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * the lost+found.  We have to do loop detection; if we ever discover
2603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * a loop, we treat that as a disconnected directory and offer to
2613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * reparent it to lost+found.
2623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
2631b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'ostatic void check_directory(e2fsck_t ctx, struct dir_info *dir,
26421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			    struct problem_context *pctx)
2653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
2661b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ext2_filsys fs = ctx->fs;
26721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	struct dir_info *p = dir;
2683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
2697f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o	if (!p)
2707f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o		return;
2717f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o
272f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	ext2fs_clear_inode_bitmap(inode_loop_detect);
2737f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o
2747f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o	/*
2757f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o	 * Keep going until we find a parent which we've already
2767f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o	 * checked.  We know it's either already connected to the
2777f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o	 * directory tree, or it isn't but the user has already told
2787f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o	 * us he doesn't want us to reconnect the disconnected
2797f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o	 * subtree.
2807f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o	 */
2817f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o	while (!ext2fs_test_inode_bitmap(inode_done_map, p->ino)) {
2823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		/*
2833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * Mark this inode as being "done"; by the time we
2843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * return from this function, the inode we either be
2853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * verified as being connected to the directory tree,
2863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * or we will have offered to reconnect this to
2873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * lost+found.
2883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 */
289f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		ext2fs_mark_inode_bitmap(inode_done_map, p->ino);
2907f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o
2913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		/*
2923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * If this directory doesn't have a parent, or we've
2933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * seen the parent once already, then offer to
2943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * reparent it to lost+found
2953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 */
2963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (!p->parent ||
297f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		    (ext2fs_test_inode_bitmap(inode_loop_detect,
2987f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o					      p->parent))) {
2997f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o			pctx->ino = p->ino;
3007f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o			if (fix_problem(ctx, PR_3_UNCONNECTED_DIR, pctx)) {
3017f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o				if (e2fsck_reconnect_file(ctx, p->ino))
3027f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o					ext2fs_unmark_valid(fs);
3037f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o				else {
3047f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o					p->parent = lost_and_found;
3057f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o					fix_dotdot(ctx, p, lost_and_found);
3067f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o				}
3077f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o			}
3083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			break;
3097f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o		}
310f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		ext2fs_mark_inode_bitmap(inode_loop_detect,
3113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o					 p->parent);
3127f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o		pctx->ino = p->parent;
31308b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		p = e2fsck_get_dir_info(ctx, p->parent);
3147f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o		if (!p) {
3157f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o			fix_problem(ctx, PR_3_NO_DIRINFO, pctx);
3167f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o			return;
3173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
31821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	}
3193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
3203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
3213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Make sure that .. and the parent directory are the same;
3223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * offer to fix it if not.
3233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
3243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (dir->parent != dir->dotdot) {
32521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		pctx->ino = dir->ino;
32621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		pctx->ino2 = dir->dotdot;
32721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		pctx->dir = dir->parent;
3281b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		if (fix_problem(ctx, PR_3_BAD_DOT_DOT, pctx))
3291b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			fix_dotdot(ctx, dir, dir->parent);
3303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
3313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
3323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
3333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
3343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * This routine gets the lost_and_found inode, making it a directory
3353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * if necessary
3363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
3371b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'oino_t get_lost_and_found(e2fsck_t ctx)
3383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
3391b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ext2_filsys fs = ctx->fs;
3403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	ino_t			ino;
3413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	blk_t			blk;
3423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t		retval;
3433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct ext2_inode	inode;
3443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char *			block;
34521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	const char 		name[] = "lost+found";
3461b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	struct 	problem_context	pctx;
3474a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o	struct dir_info 	*dirinfo;
3483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
3491b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	clear_problem_context(&pctx);
3501b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o
35121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name,
35221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			       sizeof(name)-1, 0, &ino);
3534a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o	if (!retval) {
3544a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o		if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, ino))
3554a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o			return ino;
3564a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o		/* Lost+found isn't a directory! */
3574a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o		pctx.ino = ino;
3584a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o		if (!fix_problem(ctx, PR_3_LPF_NOTDIR, &pctx))
3594a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o			return 0;
3604a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o
361c54b3c3c99a5d3011f6f60934e90dae7f60b3b00Theodore Ts'o		/* OK, unlink the old /lost+found file. */
3624a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o		pctx.errcode = ext2fs_unlink(fs, EXT2_ROOT_INO, name, ino, 0);
3634a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o		if (pctx.errcode) {
3644a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o			pctx.str = "ext2fs_unlink";
3654a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o			fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
3664a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o			return 0;
3674a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o		}
3684a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o		dirinfo = e2fsck_get_dir_info(ctx, ino);
3694a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o		if (dirinfo)
3704a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o			dirinfo->parent = 0;
3714a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o		adjust_inode_count(ctx, ino, -1);
3724a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o	} else if (retval != EXT2_ET_FILE_NOT_FOUND) {
3731b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx.errcode = retval;
3741b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_3_ERR_FIND_LPF, &pctx);
3751b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	}
3761b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (!fix_problem(ctx, PR_3_NO_LF_DIR, 0))
3773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
3783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
3793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
3803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Read the inode and block bitmaps in; we'll be messing with
3813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * them.
3823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
383f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o	e2fsck_read_bitmaps(ctx);
3843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
3853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
3863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * First, find a free block
3873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
3881b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	retval = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk);
3893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval) {
3901b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx.errcode = retval;
3911b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_3_ERR_LPF_NEW_BLOCK, &pctx);
3923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
3933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
3941b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
395f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	ext2fs_mark_block_bitmap(fs->block_map, blk);
3963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	ext2fs_mark_bb_dirty(fs);
3973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
3983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
3993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Next find a free inode.
4003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
4011b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	retval = ext2fs_new_inode(fs, EXT2_ROOT_INO, 040755,
4021b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o				  ctx->inode_used_map, &ino);
4033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval) {
4041b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx.errcode = retval;
4051b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_3_ERR_LPF_NEW_INODE, &pctx);
4063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
4073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
4081b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
4091b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ext2fs_mark_inode_bitmap(ctx->inode_dir_map, ino);
410f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	ext2fs_mark_inode_bitmap(fs->inode_map, ino);
4113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	ext2fs_mark_ib_dirty(fs);
4123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
4143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Now let's create the actual data block for the inode
4153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
4163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = ext2fs_new_dir_block(fs, ino, EXT2_ROOT_INO, &block);
4173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval) {
4181b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx.errcode = retval;
4191b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_3_ERR_LPF_NEW_DIR_BLOCK, &pctx);
4203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
4213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
4223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
42350e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	retval = ext2fs_write_dir_block(fs, blk, block);
42408b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o	ext2fs_free_mem((void **) &block);
4253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval) {
4261b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx.errcode = retval;
4271b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_3_ERR_LPF_WRITE_BLOCK, &pctx);
4283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
4293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
4303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
4323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Set up the inode structure
4333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
4343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	memset(&inode, 0, sizeof(inode));
4353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_mode = 040755;
4363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_size = fs->blocksize;
4373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_atime = inode.i_ctime = inode.i_mtime = time(0);
4383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_links_count = 2;
4393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_blocks = fs->blocksize / 512;
4403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_block[0] = blk;
4413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
4433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Next, write out the inode.
4443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
4451b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	pctx.errcode = ext2fs_write_inode(fs, ino, &inode);
4461b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (pctx.errcode) {
4471b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx.str = "ext2fs_write_inode";
4481b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
4493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
4503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
4513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
4523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Finally, create the directory link
4533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
4541b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	pctx.errcode = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, 0);
4551b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (pctx.errcode) {
4561b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx.str = "ext2fs_link";
4571b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
4583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
4593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
4603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
4623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Miscellaneous bookkeeping that needs to be kept straight.
4633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
46408b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o	e2fsck_add_dir_info(ctx, ino, EXT2_ROOT_INO);
4651b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	adjust_inode_count(ctx, EXT2_ROOT_INO, +1);
4661b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ext2fs_icount_store(ctx->inode_count, ino, 2);
4671b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ext2fs_icount_store(ctx->inode_link_info, ino, 2);
4683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#if 0
469f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	printf("/lost+found created; inode #%lu\n", ino);
4703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#endif
4713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return ino;
4723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
4733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
4753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * This routine will connect a file to lost+found
4763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
47708b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'oint e2fsck_reconnect_file(e2fsck_t ctx, ino_t inode)
4783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
4791b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ext2_filsys fs = ctx->fs;
4803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
4813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char		name[80];
4821b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	struct problem_context	pctx;
4831b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o
4841b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	clear_problem_context(&pctx);
4851b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	pctx.ino = inode;
4861b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o
4871b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (!bad_lost_and_found && !lost_and_found) {
4881b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		lost_and_found = get_lost_and_found(ctx);
4891b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		if (!lost_and_found)
4901b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			bad_lost_and_found++;
4911b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	}
4923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (bad_lost_and_found) {
4931b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_3_NO_LPF, &pctx);
4943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 1;
4953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
4961b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o
497f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	sprintf(name, "#%lu", inode);
4983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = ext2fs_link(fs, lost_and_found, name, inode, 0);
4993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval == EXT2_ET_DIR_NO_SPACE) {
5001b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		if (!fix_problem(ctx, PR_3_EXPAND_LF_DIR, &pctx))
5013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			return 1;
5021b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		retval = expand_directory(ctx, lost_and_found);
5033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (retval) {
5041b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			pctx.errcode = retval;
5051b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			fix_problem(ctx, PR_3_CANT_EXPAND_LPF, &pctx);
5063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			return 1;
5073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
5083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		retval = ext2fs_link(fs, lost_and_found, name, inode, 0);
5093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
5103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval) {
5111b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx.errcode = retval;
5121b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_3_CANT_RECONNECT, &pctx);
5133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 1;
5143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
5151b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	adjust_inode_count(ctx, inode, +1);
5163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
5183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
5193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
5213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Utility routine to adjust the inode counts on an inode.
5223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
5231b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'ostatic errcode_t adjust_inode_count(e2fsck_t ctx, ino_t ino, int adj)
5243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
5251b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ext2_filsys fs = ctx->fs;
5263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t		retval;
5273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct ext2_inode 	inode;
5283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (!ino)
5303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
5313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = ext2fs_read_inode(fs, ino, &inode);
5333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval)
5343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return retval;
5353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#if 0
537f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	printf("Adjusting link count for inode %lu by %d (from %d)\n", ino, adj,
5383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	       inode.i_links_count);
5393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#endif
5403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_links_count += adj;
54221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	if (adj == 1) {
5431b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		ext2fs_icount_increment(ctx->inode_count, ino, 0);
5441b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		ext2fs_icount_increment(ctx->inode_link_info, ino, 0);
54521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	} else {
5461b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		ext2fs_icount_decrement(ctx->inode_count, ino, 0);
5471b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		ext2fs_icount_decrement(ctx->inode_link_info, ino, 0);
54821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	}
54921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o
5503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = ext2fs_write_inode(fs, ino, &inode);
5523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval)
5533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return retval;
5543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
5563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
5573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
5593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Fix parent --- this routine fixes up the parent of a directory.
5603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
5613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostruct fix_dotdot_struct {
5623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	ext2_filsys	fs;
5633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	ino_t		parent;
5643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int		done;
5651b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	e2fsck_t	ctx;
5663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o};
5673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic int fix_dotdot_proc(struct ext2_dir_entry *dirent,
5693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			   int	offset,
5703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			   int	blocksize,
5713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			   char	*buf,
57254dc7ca2869897ae8cb81a9ab9880ebff11680bcTheodore Ts'o			   void	*priv_data)
5733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
57454dc7ca2869897ae8cb81a9ab9880ebff11680bcTheodore Ts'o	struct fix_dotdot_struct *fp = (struct fix_dotdot_struct *) priv_data;
5753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
5761b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	struct problem_context pctx;
5773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
578b6f7983197fe217cf20862c93d72620be3b0fcecTheodore Ts'o	if ((dirent->name_len & 0xFF) != 2)
5793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
5803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (strncmp(dirent->name, "..", 2))
5813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
5823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5831b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	clear_problem_context(&pctx);
5841b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o
5851b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	retval = adjust_inode_count(fp->ctx, dirent->inode, -1);
5861b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (retval) {
5871b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx.errcode = retval;
5881b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx);
5891b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	}
5901b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	retval = adjust_inode_count(fp->ctx, fp->parent, 1);
5911b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (retval) {
5921b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx.errcode = retval;
5931b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx);
5941b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	}
5953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	dirent->inode = fp->parent;
5963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	fp->done++;
5983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return DIRENT_ABORT | DIRENT_CHANGED;
5993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
6003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
6011b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'ostatic void fix_dotdot(e2fsck_t ctx, struct dir_info *dir, ino_t parent)
6023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
6031b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ext2_filsys fs = ctx->fs;
6043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
6053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct fix_dotdot_struct fp;
6061b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	struct problem_context pctx;
6073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
6083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	fp.fs = fs;
6093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	fp.parent = parent;
6103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	fp.done = 0;
6111b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	fp.ctx = ctx;
6123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
6133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#if 0
614f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	printf("Fixing '..' of inode %lu to be %lu...\n", dir->ino, parent);
6153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#endif
6163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
6173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = ext2fs_dir_iterate(fs, dir->ino, DIRENT_FLAG_INCLUDE_EMPTY,
6183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				    0, fix_dotdot_proc, &fp);
6193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval || !fp.done) {
6201b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		clear_problem_context(&pctx);
6211b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx.ino = dir->ino;
6221b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx.errcode = retval;
6231b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, retval ? PR_3_FIX_PARENT_ERR :
6241b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			    PR_3_FIX_PARENT_NOFIND, &pctx);
6253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		ext2fs_unmark_valid(fs);
6263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
6273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	dir->dotdot = parent;
6283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
6293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return;
6303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
6313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
6323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
6333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * These routines are responsible for expanding a /lost+found if it is
6343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * too small.
6353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
6363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
6373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostruct expand_dir_struct {
6383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int	done;
6393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	err;
6401b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	e2fsck_t	ctx;
6413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o};
6423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
6433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic int expand_dir_proc(ext2_filsys fs,
6443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			   blk_t	*blocknr,
6453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			   int	blockcnt,
64654dc7ca2869897ae8cb81a9ab9880ebff11680bcTheodore Ts'o			   void	*priv_data)
6473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
64854dc7ca2869897ae8cb81a9ab9880ebff11680bcTheodore Ts'o	struct expand_dir_struct *es = (struct expand_dir_struct *) priv_data;
6493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	blk_t	new_blk;
6503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	static blk_t	last_blk = 0;
6513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char		*block;
6523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
6531b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	e2fsck_t	ctx;
6541b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o
6551b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ctx = es->ctx;
6563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
6573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (*blocknr) {
6583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		last_blk = *blocknr;
6593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
6603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
6611b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	retval = ext2fs_new_block(fs, last_blk, ctx->block_found_map,
6621b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o				  &new_blk);
6633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval) {
6643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		es->err = retval;
6653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return BLOCK_ABORT;
6663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
6673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (blockcnt > 0) {
6683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		retval = ext2fs_new_dir_block(fs, 0, 0, &block);
6693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (retval) {
6703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			es->err = retval;
6713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			return BLOCK_ABORT;
6723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
6733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		es->done = 1;
674b8647faa3b0a7dfbb2456a7b37321ee4bbda651cTheodore Ts'o		retval = ext2fs_write_dir_block(fs, new_blk, block);
6753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	} else {
67608b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		retval = ext2fs_get_mem(fs->blocksize, (void **) &block);
67708b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		if (retval) {
67808b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o			es->err = retval;
6793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			return BLOCK_ABORT;
6803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
6813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		memset(block, 0, fs->blocksize);
682b8647faa3b0a7dfbb2456a7b37321ee4bbda651cTheodore Ts'o		retval = io_channel_write_blk(fs->io, new_blk, 1, block);
6833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
6843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval) {
6853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		es->err = retval;
6863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return BLOCK_ABORT;
6873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
68808b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o	ext2fs_free_mem((void **) &block);
6893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	*blocknr = new_blk;
6901b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ext2fs_mark_block_bitmap(ctx->block_found_map, new_blk);
691f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	ext2fs_mark_block_bitmap(fs->block_map, new_blk);
6923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	ext2fs_mark_bb_dirty(fs);
6933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (es->done)
6943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return (BLOCK_CHANGED | BLOCK_ABORT);
6953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	else
6963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return BLOCK_CHANGED;
6973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
6983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
6991b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'ostatic errcode_t expand_directory(e2fsck_t ctx, ino_t dir)
7003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
7011b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ext2_filsys fs = ctx->fs;
7023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
7033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct expand_dir_struct es;
7043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct ext2_inode	inode;
7053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
7063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (!(fs->flags & EXT2_FLAG_RW))
7073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return EXT2_ET_RO_FILSYS;
7083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
709b8647faa3b0a7dfbb2456a7b37321ee4bbda651cTheodore Ts'o	/*
710b8647faa3b0a7dfbb2456a7b37321ee4bbda651cTheodore Ts'o	 * Read the inode and block bitmaps in; we'll be messing with
711b8647faa3b0a7dfbb2456a7b37321ee4bbda651cTheodore Ts'o	 * them.
712b8647faa3b0a7dfbb2456a7b37321ee4bbda651cTheodore Ts'o	 */
713b8647faa3b0a7dfbb2456a7b37321ee4bbda651cTheodore Ts'o	e2fsck_read_bitmaps(ctx);
714b8647faa3b0a7dfbb2456a7b37321ee4bbda651cTheodore Ts'o
7153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = ext2fs_check_directory(fs, dir);
7163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval)
7173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return retval;
7183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
7193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	es.done = 0;
7203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	es.err = 0;
7211b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	es.ctx = ctx;
7223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
7233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = ext2fs_block_iterate(fs, dir, BLOCK_FLAG_APPEND,
7243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				      0, expand_dir_proc, &es);
7253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
7263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (es.err)
7273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return es.err;
7283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (!es.done)
7293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return EXT2_ET_EXPAND_DIR_ERR;
7303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
7313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
7323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Update the size and block count fields in the inode.
7333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
7343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = ext2fs_read_inode(fs, dir, &inode);
7353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval)
7363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return retval;
7373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
7383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_size += fs->blocksize;
7393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_blocks += fs->blocksize / 512;
7403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
74108b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o	e2fsck_write_inode(ctx, dir, &inode, "expand_directory");
7423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
7433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
7443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
745