13839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
23839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * pass3.c -- pass #3 of e2fsck: Check for directory connectivity
33839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *
4c1faf9cc3a2418c536eee472f054c9604ad3f213Theodore Ts'o * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999 Theodore Ts'o.
521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o *
621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * %Begin-Header%
721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * This file may be redistributed under the terms of the GNU Public
821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * License.
921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * %End-Header%
10efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o *
113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Pass #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".
17efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore 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.
27efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore 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);
4528db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'ostatic int check_directory(e2fsck_t ctx, ext2_ino_t ino,
4628ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o			   struct problem_context *pctx);
4728db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'ostatic void fix_dotdot(e2fsck_t ctx, ext2_ino_t ino, ext2_ino_t parent);
483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
49a02ce9df5ff5db2982462aec7162f7142dc18131Theodore Ts'ostatic ext2fs_inode_bitmap inode_loop_detect = 0;
50a02ce9df5ff5db2982462aec7162f7142dc18131Theodore Ts'ostatic ext2fs_inode_bitmap inode_done_map = 0;
51efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
5208b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'ovoid e2fsck_pass3(e2fsck_t ctx)
533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
541b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ext2_filsys fs = ctx->fs;
55e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	struct dir_info_iter *iter = NULL;
568bf191e8660939687ef35c013066d2082cb16722Theodore Ts'o#ifdef RESOURCE_TRACK
573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct resource_track	rtrack;
588bf191e8660939687ef35c013066d2082cb16722Theodore Ts'o#endif
5921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	struct problem_context	pctx;
6021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	struct dir_info	*dir;
617f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o	unsigned long maxdirs, count;
62f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o
636d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	init_resource_track(&rtrack, ctx->fs->io);
641b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	clear_problem_context(&pctx);
651b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o
663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#ifdef MTRACE
673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	mtrace_print("Pass 3");
683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#endif
693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
701b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (!(ctx->options & E2F_OPT_PREEN))
711b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_3_PASS_HEADER, &pctx);
723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Allocate some bitmaps to do loop detection.
753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
76e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	pctx.errcode = e2fsck_allocate_inode_bitmap(fs, _("inode done bitmap"),
77e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall					EXT2FS_BMAP64_AUTODIR,
78e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall					"inode_done_map", &inode_done_map);
791b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (pctx.errcode) {
801b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx.num = 2;
811b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_3_ALLOCATE_IBITMAP_ERROR, &pctx);
8208b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		ctx->flags |= E2F_FLAG_ABORT;
83a02ce9df5ff5db2982462aec7162f7142dc18131Theodore Ts'o		goto abort_exit;
843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
859facd076ae8af6e908e228392cea866ce0faf1bcKen Chen	print_resource_track(ctx, _("Peak memory"), &ctx->global_rtrack, NULL);
863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
871b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	check_root(ctx);
88a02ce9df5ff5db2982462aec7162f7142dc18131Theodore Ts'o	if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
89a02ce9df5ff5db2982462aec7162f7142dc18131Theodore Ts'o		goto abort_exit;
9008b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o
91e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ext2fs_mark_inode_bitmap2(inode_done_map, EXT2_ROOT_INO);
923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
937f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o	maxdirs = e2fsck_get_num_dirinfo(ctx);
94f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	count = 1;
95f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o
96f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	if (ctx->progress)
977f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o		if ((ctx->progress)(ctx, 3, 0, maxdirs))
98f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o			goto abort_exit;
99efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
10028db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o	iter = e2fsck_dir_info_iter_begin(ctx);
10128db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o	while ((dir = e2fsck_dir_info_iter(ctx, iter)) != 0) {
1024cae04529eda0e482ceaa86b48e532f9c8d35f24Theodore Ts'o		if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
1034cae04529eda0e482ceaa86b48e532f9c8d35f24Theodore Ts'o			goto abort_exit;
1044cae04529eda0e482ceaa86b48e532f9c8d35f24Theodore Ts'o		if (ctx->progress && (ctx->progress)(ctx, 3, count++, maxdirs))
1054cae04529eda0e482ceaa86b48e532f9c8d35f24Theodore Ts'o			goto abort_exit;
106e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		if (ext2fs_test_inode_bitmap2(ctx->inode_dir_map, dir->ino))
10728db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o			if (check_directory(ctx, dir->ino, &pctx))
10828ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o				goto abort_exit;
1093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
110a02ce9df5ff5db2982462aec7162f7142dc18131Theodore Ts'o
1115a679c8fb15540f86fc2eae3117412adc6ecbb33Theodore Ts'o	/*
1125a679c8fb15540f86fc2eae3117412adc6ecbb33Theodore Ts'o	 * Force the creation of /lost+found if not present
1135a679c8fb15540f86fc2eae3117412adc6ecbb33Theodore Ts'o	 */
114e9a8c0c2d46a46c01c6a6daa5db14df72a7ad6aaJohan Erlandsson	if ((ctx->options & E2F_OPT_READONLY) == 0)
115850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o		e2fsck_get_lost_and_found(ctx, 1);
1165a679c8fb15540f86fc2eae3117412adc6ecbb33Theodore Ts'o
117850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o	/*
118850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o	 * If there are any directories that need to be indexed or
119850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o	 * optimized, do it here.
120850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o	 */
121850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o	e2fsck_rehash_directories(ctx);
122efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
123a02ce9df5ff5db2982462aec7162f7142dc18131Theodore Ts'oabort_exit:
124e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (iter)
125e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		e2fsck_dir_info_iter_end(ctx, iter);
12608b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o	e2fsck_free_dir_info(ctx);
12728ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o	if (inode_loop_detect) {
128a02ce9df5ff5db2982462aec7162f7142dc18131Theodore Ts'o		ext2fs_free_inode_bitmap(inode_loop_detect);
12928ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o		inode_loop_detect = 0;
13028ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o	}
13128ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o	if (inode_done_map) {
132a02ce9df5ff5db2982462aec7162f7142dc18131Theodore Ts'o		ext2fs_free_inode_bitmap(inode_done_map);
13328ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o		inode_done_map = 0;
13428ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o	}
135b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o
1369facd076ae8af6e908e228392cea866ce0faf1bcKen Chen	print_resource_track(ctx, _("Pass 3"), &rtrack, ctx->fs->io);
1373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
1383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
1403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * This makes sure the root inode is present; if not, we ask if the
1413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * user wants us to create it.  Not creating it is a fatal error.
1423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
1431b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'ostatic void check_root(e2fsck_t ctx)
1443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
1451b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ext2_filsys fs = ctx->fs;
146e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	blk64_t			blk;
1473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct ext2_inode	inode;
1483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char *			block;
1491b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	struct problem_context	pctx;
150efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
1511b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	clear_problem_context(&pctx);
152efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
153e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (ext2fs_test_inode_bitmap2(ctx->inode_used_map, EXT2_ROOT_INO)) {
1543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		/*
15508b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		 * If the root inode is not a directory, die here.  The
1563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * user must have answered 'no' in pass1 when we
1573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * offered to clear it.
1583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 */
159e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		if (!(ext2fs_test_inode_bitmap2(ctx->inode_dir_map,
160f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o					       EXT2_ROOT_INO))) {
161f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o			fix_problem(ctx, PR_3_ROOT_NOT_DIR_ABORT, &pctx);
162f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o			ctx->flags |= E2F_FLAG_ABORT;
163f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o		}
1643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return;
1653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
1663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
167f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o	if (!fix_problem(ctx, PR_3_NO_ROOT_INODE, &pctx)) {
168f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o		fix_problem(ctx, PR_3_NO_ROOT_INODE_ABORT, &pctx);
169f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o		ctx->flags |= E2F_FLAG_ABORT;
170f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o		return;
171f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o	}
1723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
173f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o	e2fsck_read_bitmaps(ctx);
174efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
1753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
1763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * First, find a free block
1773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
178e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	pctx.errcode = ext2fs_new_block2(fs, 0, ctx->block_found_map, &blk);
1791b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (pctx.errcode) {
1801b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx.str = "ext2fs_new_block";
1811b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
18208b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		ctx->flags |= E2F_FLAG_ABORT;
18308b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		return;
1843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
185e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ext2fs_mark_block_bitmap2(ctx->block_found_map, blk);
186e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ext2fs_mark_block_bitmap2(fs->block_map, blk);
1873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	ext2fs_mark_bb_dirty(fs);
1883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
1903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Now let's create the actual data block for the inode
1913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
1921b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	pctx.errcode = ext2fs_new_dir_block(fs, EXT2_ROOT_INO, EXT2_ROOT_INO,
1931b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o					    &block);
1941b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (pctx.errcode) {
1951b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx.str = "ext2fs_new_dir_block";
1961b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
19708b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		ctx->flags |= E2F_FLAG_ABORT;
19808b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		return;
1993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
2003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
201e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	pctx.errcode = ext2fs_write_dir_block3(fs, blk, block, 0);
2021b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (pctx.errcode) {
203e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		pctx.str = "ext2fs_write_dir_block3";
2041b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
20508b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		ctx->flags |= E2F_FLAG_ABORT;
20608b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		return;
2073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
208c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	ext2fs_free_mem(&block);
2093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
2103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
2113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Set up the inode structure
2123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
2133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	memset(&inode, 0, sizeof(inode));
2143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_mode = 040755;
2153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_size = fs->blocksize;
2161f3ad14a5ad5df3ac4012d41ef5d76411cd8fff3Theodore Ts'o	inode.i_atime = inode.i_ctime = inode.i_mtime = ctx->now;
2173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_links_count = 2;
2181ca1059fd0126fd2c065f272a566c18f14bab16dTheodore Ts'o	ext2fs_iblk_set(fs, &inode, 1);
2193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_block[0] = blk;
2203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
2213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
2223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Write out the inode.
2233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
224030970ed750b6a169c32ffb8b19bce3150198629Theodore Ts'o	pctx.errcode = ext2fs_write_new_inode(fs, EXT2_ROOT_INO, &inode);
2251b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (pctx.errcode) {
2261b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx.str = "ext2fs_write_inode";
2271b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
22808b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		ctx->flags |= E2F_FLAG_ABORT;
22908b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		return;
2303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
231efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
2323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
2333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Miscellaneous bookkeeping...
2343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
23508b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o	e2fsck_add_dir_info(ctx, EXT2_ROOT_INO, EXT2_ROOT_INO);
2361b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ext2fs_icount_store(ctx->inode_count, EXT2_ROOT_INO, 2);
2371b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ext2fs_icount_store(ctx->inode_link_info, EXT2_ROOT_INO, 2);
2383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
239e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ext2fs_mark_inode_bitmap2(ctx->inode_used_map, EXT2_ROOT_INO);
240e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ext2fs_mark_inode_bitmap2(ctx->inode_dir_map, EXT2_ROOT_INO);
241e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ext2fs_mark_inode_bitmap2(fs->inode_map, EXT2_ROOT_INO);
2423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	ext2fs_mark_ib_dirty(fs);
2433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
2443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
2453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
2463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * This subroutine is responsible for making sure that a particular
2473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * directory is connected to the root; if it isn't we trace it up as
2483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * far as we can go, and then offer to connect the resulting parent to
2493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * the lost+found.  We have to do loop detection; if we ever discover
2503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * a loop, we treat that as a disconnected directory and offer to
2513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * reparent it to lost+found.
252efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o *
25328ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o * However, loop detection is expensive, because for very large
25428ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o * filesystems, the inode_loop_detect bitmap is huge, and clearing it
25528ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o * is non-trivial.  Loops in filesystems are also a rare error case,
25628ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o * and we shouldn't optimize for error cases.  So we try two passes of
25728ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o * the algorithm.  The first time, we ignore loop detection and merely
25828ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o * increment a counter; if the counter exceeds some extreme threshold,
25928ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o * then we try again with the loop detection bitmap enabled.
2603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
26128db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'ostatic int check_directory(e2fsck_t ctx, ext2_ino_t dir,
26228ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o			   struct problem_context *pctx)
2633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
26428ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o	ext2_filsys 	fs = ctx->fs;
26528db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o	ext2_ino_t	ino = dir, parent;
26628ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o	int		loop_pass = 0, parent_count = 0;
2673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
26828ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o	while (1) {
2693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		/*
2703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * Mark this inode as being "done"; by the time we
2713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * return from this function, the inode we either be
2723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * verified as being connected to the directory tree,
2733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * or we will have offered to reconnect this to
2743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * lost+found.
27528ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o		 *
27628ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o		 * If it was marked done already, then we've reached a
27728ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o		 * parent we've already checked.
2783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 */
279e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	  	if (ext2fs_mark_inode_bitmap2(inode_done_map, ino))
28028ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o			break;
2817f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o
28228db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o		if (e2fsck_dir_info_get_parent(ctx, ino, &parent)) {
28328db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o			fix_problem(ctx, PR_3_NO_DIRINFO, pctx);
28428db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o			return 0;
28528db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o		}
28628db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o
2873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		/*
2883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * If this directory doesn't have a parent, or we've
2893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * seen the parent once already, then offer to
2903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * reparent it to lost+found
2913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 */
29228db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o		if (!parent ||
293efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o		    (loop_pass &&
294e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		     (ext2fs_test_inode_bitmap2(inode_loop_detect,
29528db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o					       parent)))) {
29628db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o			pctx->ino = ino;
2977f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o			if (fix_problem(ctx, PR_3_UNCONNECTED_DIR, pctx)) {
2982e5fcce05ea583c480b28bf3b1f2aa427a3dcc07Theodore Ts'o				if (e2fsck_reconnect_file(ctx, pctx->ino))
2997f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o					ext2fs_unmark_valid(fs);
3007f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o				else {
301efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o					fix_dotdot(ctx, pctx->ino,
30228db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o						   ctx->lost_and_found);
30328db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o					parent = ctx->lost_and_found;
3047f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o				}
3057f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o			}
3063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			break;
3077f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o		}
30828db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o		ino = parent;
30928ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o		if (loop_pass) {
310e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			ext2fs_mark_inode_bitmap2(inode_loop_detect, ino);
31128ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o		} else if (parent_count++ > 2048) {
31228ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o			/*
31328ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o			 * If we've run into a path depth that's
31428ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o			 * greater than 2048, try again with the inode
31528ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o			 * loop bitmap turned on and start from the
31628ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o			 * top.
31728ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o			 */
31828ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o			loop_pass = 1;
31928ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o			if (inode_loop_detect)
32028ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o				ext2fs_clear_inode_bitmap(inode_loop_detect);
32128ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o			else {
322e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				pctx->errcode = e2fsck_allocate_inode_bitmap(fs, _("inode loop detection bitmap"), EXT2FS_BMAP64_AUTODIR, "inode_loop_detect", &inode_loop_detect);
32328ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o				if (pctx->errcode) {
32428ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o					pctx->num = 1;
325efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o					fix_problem(ctx,
32628ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o				    PR_3_ALLOCATE_IBITMAP_ERROR, pctx);
32728ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o					ctx->flags |= E2F_FLAG_ABORT;
32828ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o					return -1;
32928ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o				}
33028ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o			}
33128db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o			ino = dir;
3323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
33321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	}
3343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
3353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
3363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Make sure that .. and the parent directory are the same;
3373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * offer to fix it if not.
3383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
33928db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o	pctx->ino = dir;
34028db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o	if (e2fsck_dir_info_get_dotdot(ctx, dir, &pctx->ino2) ||
34128db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o	    e2fsck_dir_info_get_parent(ctx, dir, &pctx->dir)) {
34228db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o		fix_problem(ctx, PR_3_NO_DIRINFO, pctx);
34328db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o		return 0;
34428db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o	}
34528db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o	if (pctx->ino2 != pctx->dir) {
3461b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		if (fix_problem(ctx, PR_3_BAD_DOT_DOT, pctx))
34728db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o			fix_dotdot(ctx, dir, pctx->dir);
3483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
34928ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o	return 0;
350b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o}
3513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
3523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
3533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * This routine gets the lost_and_found inode, making it a directory
3543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * if necessary
3553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
356850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'oext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix)
3573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
3581b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ext2_filsys fs = ctx->fs;
35986c627ec1136446409a0170d439e60c148e6eb48Theodore Ts'o	ext2_ino_t			ino;
360e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	blk64_t			blk;
3613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t		retval;
3623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct ext2_inode	inode;
3633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char *			block;
36453ef44c40a3e425d2c700d8fd77a6b655aa121feTheodore Ts'o	static const char	name[] = "lost+found";
3651b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	struct 	problem_context	pctx;
3663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
367850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o	if (ctx->lost_and_found)
368850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o		return ctx->lost_and_found;
369850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o
3701b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	clear_problem_context(&pctx);
371efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
37221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name,
37321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			       sizeof(name)-1, 0, &ino);
374850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o	if (retval && !fix)
375850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o		return 0;
3764a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o	if (!retval) {
377e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		if (ext2fs_test_inode_bitmap2(ctx->inode_dir_map, ino)) {
378850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o			ctx->lost_and_found = ino;
3794a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o			return ino;
380850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o		}
381efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
3824a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o		/* Lost+found isn't a directory! */
383850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o		if (!fix)
384850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o			return 0;
3854a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o		pctx.ino = ino;
3864a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o		if (!fix_problem(ctx, PR_3_LPF_NOTDIR, &pctx))
3874a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o			return 0;
3884a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o
389c54b3c3c99a5d3011f6f60934e90dae7f60b3b00Theodore Ts'o		/* OK, unlink the old /lost+found file. */
3904a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o		pctx.errcode = ext2fs_unlink(fs, EXT2_ROOT_INO, name, ino, 0);
3914a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o		if (pctx.errcode) {
3924a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o			pctx.str = "ext2fs_unlink";
3934a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o			fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
3944a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o			return 0;
3954a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o		}
39628db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o		(void) e2fsck_dir_info_set_parent(ctx, ino, 0);
397b0700a1b6083f2f0c19c349f07ca80e70ec456beTheodore Ts'o		e2fsck_adjust_inode_count(ctx, ino, -1);
3984a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o	} else if (retval != EXT2_ET_FILE_NOT_FOUND) {
3991b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx.errcode = retval;
4001b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_3_ERR_FIND_LPF, &pctx);
4011b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	}
4021b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (!fix_problem(ctx, PR_3_NO_LF_DIR, 0))
4033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
4043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
4063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Read the inode and block bitmaps in; we'll be messing with
4073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * them.
4083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
409f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o	e2fsck_read_bitmaps(ctx);
410efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
4113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
4123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * First, find a free block
4133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
414e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	retval = ext2fs_new_block2(fs, 0, ctx->block_found_map, &blk);
4153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval) {
4161b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx.errcode = retval;
4171b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_3_ERR_LPF_NEW_BLOCK, &pctx);
4183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
4193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
420e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ext2fs_mark_block_bitmap2(ctx->block_found_map, blk);
421e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ext2fs_block_alloc_stats2(fs, blk, +1);
4223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
4243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Next find a free inode.
4253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
426b0700a1b6083f2f0c19c349f07ca80e70ec456beTheodore Ts'o	retval = ext2fs_new_inode(fs, EXT2_ROOT_INO, 040700,
4271b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o				  ctx->inode_used_map, &ino);
4283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval) {
4291b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx.errcode = retval;
4301b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_3_ERR_LPF_NEW_INODE, &pctx);
4313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
4323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
433e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino);
434e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ext2fs_mark_inode_bitmap2(ctx->inode_dir_map, ino);
4350684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o	ext2fs_inode_alloc_stats2(fs, ino, +1, 1);
4363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
4383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Now let's create the actual data block for the inode
4393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
4403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = ext2fs_new_dir_block(fs, ino, EXT2_ROOT_INO, &block);
4413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval) {
4421b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx.errcode = retval;
4431b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_3_ERR_LPF_NEW_DIR_BLOCK, &pctx);
4443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
4453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
4463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
447e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	retval = ext2fs_write_dir_block3(fs, blk, block, 0);
448c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	ext2fs_free_mem(&block);
4493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval) {
4501b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx.errcode = retval;
4511b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_3_ERR_LPF_WRITE_BLOCK, &pctx);
4523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
4533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
4543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
4563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Set up the inode structure
4573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
4583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	memset(&inode, 0, sizeof(inode));
45964aecc4dd35b48f66f452f06c49587c838990d39Theodore Ts'o	inode.i_mode = 040700;
4603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_size = fs->blocksize;
4611f3ad14a5ad5df3ac4012d41ef5d76411cd8fff3Theodore Ts'o	inode.i_atime = inode.i_ctime = inode.i_mtime = ctx->now;
4623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_links_count = 2;
4631ca1059fd0126fd2c065f272a566c18f14bab16dTheodore Ts'o	ext2fs_iblk_set(fs, &inode, 1);
4643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_block[0] = blk;
4653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
4673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Next, write out the inode.
4683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
469030970ed750b6a169c32ffb8b19bce3150198629Theodore Ts'o	pctx.errcode = ext2fs_write_new_inode(fs, ino, &inode);
4701b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (pctx.errcode) {
4711b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx.str = "ext2fs_write_inode";
4721b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
4733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
4743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
4753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
4763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Finally, create the directory link
4773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
4786fdc7a325c8bff67fc3a0489d0858bc7c48dc1a3Theodore Ts'o	pctx.errcode = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, EXT2_FT_DIR);
4791b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (pctx.errcode) {
4801b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx.str = "ext2fs_link";
4811b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
4823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
4833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
4843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
4863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Miscellaneous bookkeeping that needs to be kept straight.
4873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
48808b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o	e2fsck_add_dir_info(ctx, ino, EXT2_ROOT_INO);
489b0700a1b6083f2f0c19c349f07ca80e70ec456beTheodore Ts'o	e2fsck_adjust_inode_count(ctx, EXT2_ROOT_INO, 1);
4901b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ext2fs_icount_store(ctx->inode_count, ino, 2);
4911b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ext2fs_icount_store(ctx->inode_link_info, ino, 2);
492850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o	ctx->lost_and_found = ino;
493e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	quota_data_add(ctx->qctx, &inode, ino, fs->blocksize);
494e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	quota_data_inodes(ctx->qctx, &inode, ino, +1);
4953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#if 0
496f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	printf("/lost+found created; inode #%lu\n", ino);
4973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#endif
4983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return ino;
4993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
5003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
5023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * This routine will connect a file to lost+found
5033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
50486c627ec1136446409a0170d439e60c148e6eb48Theodore Ts'oint e2fsck_reconnect_file(e2fsck_t ctx, ext2_ino_t ino)
5053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
5061b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ext2_filsys fs = ctx->fs;
5073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
5083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char		name[80];
5091b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	struct problem_context	pctx;
5106fdc7a325c8bff67fc3a0489d0858bc7c48dc1a3Theodore Ts'o	struct ext2_inode 	inode;
5116fdc7a325c8bff67fc3a0489d0858bc7c48dc1a3Theodore Ts'o	int		file_type = 0;
5121b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o
5131b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	clear_problem_context(&pctx);
5146fdc7a325c8bff67fc3a0489d0858bc7c48dc1a3Theodore Ts'o	pctx.ino = ino;
5151b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o
516850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o	if (!ctx->bad_lost_and_found && !ctx->lost_and_found) {
517850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o		if (e2fsck_get_lost_and_found(ctx, 1) == 0)
518850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o			ctx->bad_lost_and_found++;
5191b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	}
520850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o	if (ctx->bad_lost_and_found) {
5211b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_3_NO_LPF, &pctx);
5223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 1;
5233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
524efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
52586c627ec1136446409a0170d439e60c148e6eb48Theodore Ts'o	sprintf(name, "#%u", ino);
5266fdc7a325c8bff67fc3a0489d0858bc7c48dc1a3Theodore Ts'o	if (ext2fs_read_inode(fs, ino, &inode) == 0)
5276fdc7a325c8bff67fc3a0489d0858bc7c48dc1a3Theodore Ts'o		file_type = ext2_file_type(inode.i_mode);
528850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o	retval = ext2fs_link(fs, ctx->lost_and_found, name, ino, file_type);
5293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval == EXT2_ET_DIR_NO_SPACE) {
5301b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		if (!fix_problem(ctx, PR_3_EXPAND_LF_DIR, &pctx))
5313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			return 1;
532efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o		retval = e2fsck_expand_directory(ctx, ctx->lost_and_found,
533850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o						 1, 0);
5343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (retval) {
5351b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			pctx.errcode = retval;
5361b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			fix_problem(ctx, PR_3_CANT_EXPAND_LPF, &pctx);
5373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			return 1;
5383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
539850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o		retval = ext2fs_link(fs, ctx->lost_and_found, name,
540850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o				     ino, file_type);
5413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
5423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval) {
5431b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx.errcode = retval;
5441b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_3_CANT_RECONNECT, &pctx);
5453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 1;
5463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
547b0700a1b6083f2f0c19c349f07ca80e70ec456beTheodore Ts'o	e2fsck_adjust_inode_count(ctx, ino, 1);
5483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
5503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
5513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
5533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Utility routine to adjust the inode counts on an inode.
5543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
555b0700a1b6083f2f0c19c349f07ca80e70ec456beTheodore Ts'oerrcode_t e2fsck_adjust_inode_count(e2fsck_t ctx, ext2_ino_t ino, int adj)
5563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
5571b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ext2_filsys fs = ctx->fs;
5583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t		retval;
5593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct ext2_inode 	inode;
560efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
5613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (!ino)
5623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
5633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = ext2fs_read_inode(fs, ino, &inode);
5653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval)
5663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return retval;
5673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#if 0
569f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	printf("Adjusting link count for inode %lu by %d (from %d)\n", ino, adj,
5703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	       inode.i_links_count);
5713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#endif
5723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
57321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	if (adj == 1) {
5741b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		ext2fs_icount_increment(ctx->inode_count, ino, 0);
575c1faf9cc3a2418c536eee472f054c9604ad3f213Theodore Ts'o		if (inode.i_links_count == (__u16) ~0)
576c1faf9cc3a2418c536eee472f054c9604ad3f213Theodore Ts'o			return 0;
5771b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		ext2fs_icount_increment(ctx->inode_link_info, ino, 0);
578c1faf9cc3a2418c536eee472f054c9604ad3f213Theodore Ts'o		inode.i_links_count++;
579c1faf9cc3a2418c536eee472f054c9604ad3f213Theodore Ts'o	} else if (adj == -1) {
5801b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		ext2fs_icount_decrement(ctx->inode_count, ino, 0);
581c1faf9cc3a2418c536eee472f054c9604ad3f213Theodore Ts'o		if (inode.i_links_count == 0)
582c1faf9cc3a2418c536eee472f054c9604ad3f213Theodore Ts'o			return 0;
5831b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		ext2fs_icount_decrement(ctx->inode_link_info, ino, 0);
584c1faf9cc3a2418c536eee472f054c9604ad3f213Theodore Ts'o		inode.i_links_count--;
58521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	}
586efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
5873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = ext2fs_write_inode(fs, ino, &inode);
5883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval)
5893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return retval;
5903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
5923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
5933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
5953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Fix parent --- this routine fixes up the parent of a directory.
5963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
5973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostruct fix_dotdot_struct {
5983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	ext2_filsys	fs;
59986c627ec1136446409a0170d439e60c148e6eb48Theodore Ts'o	ext2_ino_t	parent;
6003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int		done;
6011b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	e2fsck_t	ctx;
6023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o};
6033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
6043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic int fix_dotdot_proc(struct ext2_dir_entry *dirent,
605544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			   int	offset EXT2FS_ATTR((unused)),
606544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			   int	blocksize EXT2FS_ATTR((unused)),
607544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			   char	*buf EXT2FS_ATTR((unused)),
60854dc7ca2869897ae8cb81a9ab9880ebff11680bcTheodore Ts'o			   void	*priv_data)
6093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
61054dc7ca2869897ae8cb81a9ab9880ebff11680bcTheodore Ts'o	struct fix_dotdot_struct *fp = (struct fix_dotdot_struct *) priv_data;
6113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
6121b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	struct problem_context pctx;
6133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
614b6f7983197fe217cf20862c93d72620be3b0fcecTheodore Ts'o	if ((dirent->name_len & 0xFF) != 2)
6153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
6163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (strncmp(dirent->name, "..", 2))
6173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
6183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
6191b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	clear_problem_context(&pctx);
620efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
621b0700a1b6083f2f0c19c349f07ca80e70ec456beTheodore Ts'o	retval = e2fsck_adjust_inode_count(fp->ctx, dirent->inode, -1);
6221b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (retval) {
6231b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx.errcode = retval;
6241b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx);
6251b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	}
626b0700a1b6083f2f0c19c349f07ca80e70ec456beTheodore Ts'o	retval = e2fsck_adjust_inode_count(fp->ctx, fp->parent, 1);
6271b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (retval) {
6281b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx.errcode = retval;
6291b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx);
6301b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	}
6313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	dirent->inode = fp->parent;
63256c8c592ac48c0fc9772153bb7bdf621b1de0ab9Theodore Ts'o	if (fp->ctx->fs->super->s_feature_incompat &
63356c8c592ac48c0fc9772153bb7bdf621b1de0ab9Theodore Ts'o	    EXT2_FEATURE_INCOMPAT_FILETYPE)
634efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o		dirent->name_len = (dirent->name_len & 0xFF) |
63556c8c592ac48c0fc9772153bb7bdf621b1de0ab9Theodore Ts'o			(EXT2_FT_DIR << 8);
63656c8c592ac48c0fc9772153bb7bdf621b1de0ab9Theodore Ts'o	else
63756c8c592ac48c0fc9772153bb7bdf621b1de0ab9Theodore Ts'o		dirent->name_len = dirent->name_len & 0xFF;
6383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
6393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	fp->done++;
6403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return DIRENT_ABORT | DIRENT_CHANGED;
6413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
6423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
64328db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'ostatic void fix_dotdot(e2fsck_t ctx, ext2_ino_t ino, ext2_ino_t parent)
6443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
6451b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ext2_filsys fs = ctx->fs;
6463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
6473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct fix_dotdot_struct fp;
6481b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	struct problem_context pctx;
6493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
6503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	fp.fs = fs;
6513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	fp.parent = parent;
6523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	fp.done = 0;
6531b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	fp.ctx = ctx;
6543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
6553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#if 0
65628db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o	printf("Fixing '..' of inode %lu to be %lu...\n", ino, parent);
6573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#endif
658efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
65928db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o	clear_problem_context(&pctx);
66028db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o	pctx.ino = ino;
66128db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o	retval = ext2fs_dir_iterate(fs, ino, DIRENT_FLAG_INCLUDE_EMPTY,
6623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				    0, fix_dotdot_proc, &fp);
6633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval || !fp.done) {
6641b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx.errcode = retval;
6651b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, retval ? PR_3_FIX_PARENT_ERR :
6661b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			    PR_3_FIX_PARENT_NOFIND, &pctx);
6673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		ext2fs_unmark_valid(fs);
6683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
66928db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o	(void) e2fsck_dir_info_set_dotdot(ctx, ino, parent);
67028db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o	if (e2fsck_dir_info_set_parent(ctx, ino, ctx->lost_and_found))
67128db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o		fix_problem(ctx, PR_3_NO_DIRINFO, &pctx);
67228db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o
6733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return;
6743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
6753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
6763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
6773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * These routines are responsible for expanding a /lost+found if it is
6783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * too small.
6793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
6803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
6813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostruct expand_dir_struct {
682e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	blk64_t			num;
683e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	e2_blkcnt_t		guaranteed_size;
684e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	blk64_t			newblocks;
685e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	blk64_t			last_block;
686c1faf9cc3a2418c536eee472f054c9604ad3f213Theodore Ts'o	errcode_t		err;
687c1faf9cc3a2418c536eee472f054c9604ad3f213Theodore Ts'o	e2fsck_t		ctx;
6883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o};
6893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
6903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic int expand_dir_proc(ext2_filsys fs,
691e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			   blk64_t	*blocknr,
692133a56dc9da52054bc27b4c1a23f03e3405003dbTheodore Ts'o			   e2_blkcnt_t	blockcnt,
693e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			   blk64_t ref_block EXT2FS_ATTR((unused)),
694544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			   int ref_offset EXT2FS_ATTR((unused)),
69554dc7ca2869897ae8cb81a9ab9880ebff11680bcTheodore Ts'o			   void	*priv_data)
6963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
69754dc7ca2869897ae8cb81a9ab9880ebff11680bcTheodore Ts'o	struct expand_dir_struct *es = (struct expand_dir_struct *) priv_data;
698e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	blk64_t	new_blk;
699e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	static blk64_t	last_blk = 0;
7003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char		*block;
7013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
7021b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	e2fsck_t	ctx;
7031b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o
7041b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ctx = es->ctx;
705efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
706b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o	if (es->guaranteed_size && blockcnt >= es->guaranteed_size)
707b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o		return BLOCK_ABORT;
708b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o
709b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o	if (blockcnt > 0)
710b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o		es->last_block = blockcnt;
7113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (*blocknr) {
7123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		last_blk = *blocknr;
7133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
7143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
715e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
716e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (blockcnt &&
717e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	    (EXT2FS_B2C(fs, last_blk) == EXT2FS_B2C(fs, last_blk + 1)))
718e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		new_blk = last_blk + 1;
719e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	else {
720e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		last_blk &= ~EXT2FS_CLUSTER_MASK(fs);
721e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		retval = ext2fs_new_block2(fs, last_blk, ctx->block_found_map,
722e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall					  &new_blk);
723e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		if (retval) {
724e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			es->err = retval;
725e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			return BLOCK_ABORT;
726e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		}
727e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		es->newblocks++;
728e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		ext2fs_block_alloc_stats2(fs, new_blk, +1);
7293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
730e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	last_blk = new_blk;
731e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
7323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (blockcnt > 0) {
7333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		retval = ext2fs_new_dir_block(fs, 0, 0, &block);
7343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (retval) {
7353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			es->err = retval;
7363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			return BLOCK_ABORT;
7373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
738b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o		es->num--;
739e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		retval = ext2fs_write_dir_block3(fs, new_blk, block, 0);
7403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	} else {
741c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o		retval = ext2fs_get_mem(fs->blocksize, &block);
74208b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		if (retval) {
74308b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o			es->err = retval;
7443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			return BLOCK_ABORT;
7453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
7463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		memset(block, 0, fs->blocksize);
747e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		retval = io_channel_write_blk64(fs->io, new_blk, 1, block);
748efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o	}
7493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval) {
7503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		es->err = retval;
7513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return BLOCK_ABORT;
7523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
753c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	ext2fs_free_mem(&block);
7543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	*blocknr = new_blk;
755e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ext2fs_mark_block_bitmap2(ctx->block_found_map, new_blk);
756efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
757b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o	if (es->num == 0)
7583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return (BLOCK_CHANGED | BLOCK_ABORT);
7593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	else
7603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return BLOCK_CHANGED;
7613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
7623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
763e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall/*
764e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall * Ensure that all blocks are marked in the block_found_map, since it's
765e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall * possible that the library allocated an extent node block or a block map
766e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall * block during the directory rebuilding; these new allocations are not
767e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall * captured in block_found_map.  This is bad since we could later use
768e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall * block_found_map to allocate more blocks.
769e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall */
770e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic int find_new_blocks_proc(ext2_filsys fs,
771e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				blk64_t	*blocknr,
772e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				e2_blkcnt_t	blockcnt,
773e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				blk64_t ref_block EXT2FS_ATTR((unused)),
774e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				int ref_offset EXT2FS_ATTR((unused)),
775e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				void	*priv_data)
776e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall{
777e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	struct expand_dir_struct *es = (struct expand_dir_struct *) priv_data;
778e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	e2fsck_t	ctx = es->ctx;
779e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
780e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ext2fs_mark_block_bitmap2(ctx->block_found_map, *blocknr);
781e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	return 0;
782e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall}
783e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
784b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'oerrcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
785b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o				  int num, int guaranteed_size)
7863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
7871b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ext2_filsys fs = ctx->fs;
7883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
7893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct expand_dir_struct es;
7903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct ext2_inode	inode;
791e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	blk64_t		sz, before, after;
792efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
7933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (!(fs->flags & EXT2_FLAG_RW))
7943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return EXT2_ET_RO_FILSYS;
7953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
796b8647faa3b0a7dfbb2456a7b37321ee4bbda651cTheodore Ts'o	/*
797b8647faa3b0a7dfbb2456a7b37321ee4bbda651cTheodore Ts'o	 * Read the inode and block bitmaps in; we'll be messing with
798b8647faa3b0a7dfbb2456a7b37321ee4bbda651cTheodore Ts'o	 * them.
799b8647faa3b0a7dfbb2456a7b37321ee4bbda651cTheodore Ts'o	 */
800b8647faa3b0a7dfbb2456a7b37321ee4bbda651cTheodore Ts'o	e2fsck_read_bitmaps(ctx);
801c1faf9cc3a2418c536eee472f054c9604ad3f213Theodore Ts'o
8023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = ext2fs_check_directory(fs, dir);
8033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval)
8043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return retval;
805efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
806b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o	es.num = num;
807b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o	es.guaranteed_size = guaranteed_size;
808b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o	es.last_block = 0;
8093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	es.err = 0;
810c1faf9cc3a2418c536eee472f054c9604ad3f213Theodore Ts'o	es.newblocks = 0;
8111b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	es.ctx = ctx;
812efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
813e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	before = ext2fs_free_blocks_count(fs->super);
814e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_APPEND,
815133a56dc9da52054bc27b4c1a23f03e3405003dbTheodore Ts'o				       0, expand_dir_proc, &es);
8163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
8173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (es.err)
8183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return es.err;
819e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	after = ext2fs_free_blocks_count(fs->super);
820e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
821e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	/*
822e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	 * If the free block count has dropped by more than the blocks we
823e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	 * allocated ourselves, then we must've allocated some extent/map
824e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	 * blocks.  Therefore, we must iterate this dir's blocks again to
825e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	 * ensure that all newly allocated blocks are captured in
826e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	 * block_found_map.
827e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	 */
828e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if ((before - after) > es.newblocks) {
829e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_READ_ONLY,
830e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall					       0, find_new_blocks_proc, &es);
831e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		if (es.err)
832e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			return es.err;
833e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
8343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
8353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
8363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Update the size and block count fields in the inode.
8373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
8383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = ext2fs_read_inode(fs, dir, &inode);
8393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval)
8403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return retval;
841efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
842e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	sz = (es.last_block + 1) * fs->blocksize;
843e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	inode.i_size = sz;
844e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	inode.i_size_high = sz >> 32;
8451ca1059fd0126fd2c065f272a566c18f14bab16dTheodore Ts'o	ext2fs_iblk_add_blocks(fs, &inode, es.newblocks);
846e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	quota_data_add(ctx->qctx, &inode, dir, es.newblocks * fs->blocksize);
8473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
84808b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o	e2fsck_write_inode(ctx, dir, &inode, "expand_directory");
8493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
8503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
8513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
852b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o
853