pass3.c revision 21c84b71e205b5ab13f14343da5645dcc985856d
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 *
283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Pass 3 also contains the subroutine, reconnect_file() to reconnect
293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * inodes to /lost+found; this subroutine is also used by pass 4.
303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * reconnect_file() calls get_lost_and_found(), which is responsible
313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 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#include "et/com_err.h"
413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include "e2fsck.h"
4321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o#include "problem.h"
443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'ostatic void check_root(ext2_filsys fs);
4621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'ostatic void check_directory(ext2_filsys fs, struct dir_info *dir,
4721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			    struct problem_context *pctx);
483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic ino_t get_lost_and_found(ext2_filsys fs);
493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic void fix_dotdot(ext2_filsys fs, struct dir_info *dir, ino_t parent);
50f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'ostatic errcode_t adjust_inode_count(ext2_filsys fs, ino_t ino, int adj);
513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t expand_directory(ext2_filsys fs, ino_t dir);
523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic ino_t lost_and_found = 0;
543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic int bad_lost_and_found = 0;
553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
56f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'ostatic ext2fs_inode_bitmap inode_loop_detect;
57f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'ostatic ext2fs_inode_bitmap inode_done_map;
583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ovoid pass3(ext2_filsys fs)
603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int		i;
623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct resource_track	rtrack;
6421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	struct problem_context	pctx;
6521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	struct dir_info	*dir;
663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	init_resource_track(&rtrack);
683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#ifdef MTRACE
703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	mtrace_print("Pass 3");
713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#endif
723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (!preen)
743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		printf("Pass 3: Checking directory connectivity\n");
753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Allocate some bitmaps to do loop detection.
783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
79f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	retval = ext2fs_allocate_inode_bitmap(fs,
80f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o					      "inode loop detection bitmap",
81f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o					      &inode_loop_detect);
823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval) {
833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		com_err("ext2fs_allocate_inode_bitmap", retval,
843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			"while allocating inode_loop_detect");
853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		fatal_error(0);
863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
87f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	retval = ext2fs_allocate_inode_bitmap(fs, "inode done bitmap",
88f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o					      &inode_done_map);
893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval) {
903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		com_err("ext2fs_allocate_inode_bitmap", retval,
913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			"while allocating inode_done_map");
923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		fatal_error(0);
933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (tflag) {
953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		printf("Peak memory: ");
963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		print_resource_track(&global_rtrack);
973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
9921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	check_root(fs);
100f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	ext2fs_mark_inode_bitmap(inode_done_map, EXT2_ROOT_INO);
1013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
10221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	clear_problem_context(&pctx);
10321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	for (i=0; (dir = dir_info_iter(&i)) != 0;) {
10421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		if (ext2fs_test_inode_bitmap(inode_dir_map, dir->ino))
10521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			check_directory(fs, dir, &pctx);
1063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
1073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
10821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o
1093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	free_dir_info(fs);
110f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	ext2fs_free_inode_bitmap(inode_loop_detect);
111f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	ext2fs_free_inode_bitmap(inode_done_map);
1123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (tflag > 1) {
1133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		printf("Pass 3: ");
1143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		print_resource_track(&rtrack);
1153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
1163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
1173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
1193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * This makes sure the root inode is present; if not, we ask if the
1203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * user wants us to create it.  Not creating it is a fatal error.
1213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
12221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'ostatic void check_root(ext2_filsys fs)
1233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
1243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	blk_t			blk;
1253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t		retval;
1263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct ext2_inode	inode;
1273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char *			block;
1283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
12921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	if (ext2fs_test_inode_bitmap(inode_used_map, EXT2_ROOT_INO)) {
1303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		/*
1313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * If the root inode is a directory, die here.  The
1323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * user must have answered 'no' in pass1 when we
1333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * offered to clear it.
1343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 */
13521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		if (!(ext2fs_test_inode_bitmap(inode_dir_map, EXT2_ROOT_INO)))
1363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			fatal_error("Root inode not directory");
1373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return;
1383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
1393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
14021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	if (!fix_problem(fs, PR_3_NO_ROOT_INODE, 0))
1413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		fatal_error("Cannot proceed without a root inode.");
1423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	read_bitmaps(fs);
1443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
1463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * First, find a free block
1473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
1483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = ext2fs_new_block(fs, 0, block_found_map, &blk);
1493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval) {
1503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		com_err("ext2fs_new_block", retval,
1513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			"while trying to create root directory");
1523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		fatal_error(0);
1533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
154f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	ext2fs_mark_block_bitmap(block_found_map, blk);
155f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	ext2fs_mark_block_bitmap(fs->block_map, blk);
1563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	ext2fs_mark_bb_dirty(fs);
1573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
1593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Now let's create the actual data block for the inode
1603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
1613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = ext2fs_new_dir_block(fs, EXT2_ROOT_INO, EXT2_ROOT_INO,
1623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				      &block);
1633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval) {
1643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		com_err("ext2fs_new_dir_block", retval,
1653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			"while creating new root directory");
1663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		fatal_error(0);
1673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
1683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
16950e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	retval = ext2fs_write_dir_block(fs, blk, block);
1703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval) {
17150e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o		com_err("ext2fs_write_dir_block", retval,
1723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			"while writing the root directory block");
1733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		fatal_error(0);
1743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
1753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	free(block);
1763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
1783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Set up the inode structure
1793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
1803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	memset(&inode, 0, sizeof(inode));
1813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_mode = 040755;
1823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_size = fs->blocksize;
1833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_atime = inode.i_ctime = inode.i_mtime = time(0);
1843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_links_count = 2;
1853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_blocks = fs->blocksize / 512;
1863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_block[0] = blk;
1873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
1893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Write out the inode.
1903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
1913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = ext2fs_write_inode(fs, EXT2_ROOT_INO, &inode);
1923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval) {
1933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		com_err("ext2fs_write_inode", retval,
1943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			"While trying to create /lost+found");
1953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		fatal_error(0);
1963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
1973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
1993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Miscellaneous bookkeeping...
2003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
20121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	add_dir_info(fs, EXT2_ROOT_INO, EXT2_ROOT_INO);
20221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	ext2fs_icount_store(inode_count, EXT2_ROOT_INO, 2);
20321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	ext2fs_icount_store(inode_link_info, EXT2_ROOT_INO, 2);
2043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
205f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	ext2fs_mark_inode_bitmap(inode_used_map, EXT2_ROOT_INO);
206f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	ext2fs_mark_inode_bitmap(inode_dir_map, EXT2_ROOT_INO);
207f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	ext2fs_mark_inode_bitmap(fs->inode_map, EXT2_ROOT_INO);
2083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	ext2fs_mark_ib_dirty(fs);
2093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
2103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
2113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
2123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * This subroutine is responsible for making sure that a particular
2133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * directory is connected to the root; if it isn't we trace it up as
2143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * far as we can go, and then offer to connect the resulting parent to
2153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * the lost+found.  We have to do loop detection; if we ever discover
2163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * a loop, we treat that as a disconnected directory and offer to
2173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * reparent it to lost+found.
2183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
21921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'ostatic void check_directory(ext2_filsys fs, struct dir_info *dir,
22021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			    struct problem_context *pctx)
2213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
22221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	struct dir_info *p = dir;
2233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
224f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	ext2fs_clear_inode_bitmap(inode_loop_detect);
2253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	while (p) {
2263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		/*
2273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * If we find a parent which we've already checked,
2283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * then stop; we know it's either already connected to
2293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * the directory tree, or it isn't but the user has
2303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * already told us he doesn't want us to reconnect the
2313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * disconnected subtree.
2323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 */
233f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		if (ext2fs_test_inode_bitmap(inode_done_map, p->ino))
2343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			goto check_dot_dot;
2353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		/*
2363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * Mark this inode as being "done"; by the time we
2373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * return from this function, the inode we either be
2383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * verified as being connected to the directory tree,
2393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * or we will have offered to reconnect this to
2403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * lost+found.
2413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 */
242f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		ext2fs_mark_inode_bitmap(inode_done_map, p->ino);
2433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		/*
2443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * If this directory doesn't have a parent, or we've
2453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * seen the parent once already, then offer to
2463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * reparent it to lost+found
2473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 */
2483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (!p->parent ||
249f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		    (ext2fs_test_inode_bitmap(inode_loop_detect,
2503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o					      p->parent)))
2513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			break;
252f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		ext2fs_mark_inode_bitmap(inode_loop_detect,
2533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o					 p->parent);
2543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		p = get_dir_info(p->parent);
2553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
2563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
2573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * If we've reached here, we've hit a detached directory
2583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * inode; offer to reconnect it to lost+found.
2593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
26021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	pctx->ino = p->ino;
26121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	if (fix_problem(fs, PR_3_UNCONNECTED_DIR, pctx)) {
2623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (reconnect_file(fs, p->ino))
2633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			ext2fs_unmark_valid(fs);
2643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		else {
2653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			p->parent = lost_and_found;
2663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			fix_dotdot(fs, p, lost_and_found);
2673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
26821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	}
2693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
2703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
2713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Make sure that .. and the parent directory are the same;
2723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * offer to fix it if not.
2733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
2743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ocheck_dot_dot:
2753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (dir->parent != dir->dotdot) {
27621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		pctx->ino = dir->ino;
27721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		pctx->ino2 = dir->dotdot;
27821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		pctx->dir = dir->parent;
27921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		if (fix_problem(fs, PR_3_BAD_DOT_DOT, pctx))
2803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			fix_dotdot(fs, dir, dir->parent);
2813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
2823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
2833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
2843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
2853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * This routine gets the lost_and_found inode, making it a directory
2863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * if necessary
2873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
2883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'oino_t get_lost_and_found(ext2_filsys fs)
2893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
2903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	ino_t			ino;
2913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	blk_t			blk;
2923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t		retval;
2933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct ext2_inode	inode;
2943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char *			block;
29521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	const char 		name[] = "lost+found";
2963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
29721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name,
29821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			       sizeof(name)-1, 0, &ino);
2993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (!retval)
3003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return ino;
3013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval != ENOENT)
3023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		printf("Error while trying to find /lost+found: %s",
3033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		       error_message(retval));
30421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	if (!fix_problem(fs, PR_3_NO_LF_DIR, 0))
3053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
3063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
3073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
3083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Read the inode and block bitmaps in; we'll be messing with
3093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * them.
3103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
3113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	read_bitmaps(fs);
3123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
3133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
3143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * First, find a free block
3153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
3163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = ext2fs_new_block(fs, 0, block_found_map, &blk);
3173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval) {
3183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		com_err("ext2fs_new_block", retval,
3193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			"while trying to create /lost+found directory");
3203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
3213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
322f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	ext2fs_mark_block_bitmap(block_found_map, blk);
323f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	ext2fs_mark_block_bitmap(fs->block_map, blk);
3243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	ext2fs_mark_bb_dirty(fs);
3253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
3263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
3273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Next find a free inode.
3283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
3293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = ext2fs_new_inode(fs, EXT2_ROOT_INO, 040755, inode_used_map,
3303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				  &ino);
3313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval) {
3323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		com_err("ext2fs_new_inode", retval,
3333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			"while trying to create /lost+found directory");
3343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
3353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
336f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	ext2fs_mark_inode_bitmap(inode_used_map, ino);
337f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	ext2fs_mark_inode_bitmap(inode_dir_map, ino);
338f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	ext2fs_mark_inode_bitmap(fs->inode_map, ino);
3393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	ext2fs_mark_ib_dirty(fs);
3403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
3413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
3423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Now let's create the actual data block for the inode
3433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
3443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = ext2fs_new_dir_block(fs, ino, EXT2_ROOT_INO, &block);
3453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval) {
3463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		com_err("ext2fs_new_dir_block", retval,
3473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			"while creating new directory block");
3483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
3493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
3503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
35150e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	retval = ext2fs_write_dir_block(fs, blk, block);
35250e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	free(block);
3533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval) {
35450e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o		com_err("ext2fs_write_dir_block", retval,
3553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			"while writing the directory block for /lost+found");
3563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
3573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
3583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
3593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
3603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Set up the inode structure
3613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
3623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	memset(&inode, 0, sizeof(inode));
3633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_mode = 040755;
3643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_size = fs->blocksize;
3653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_atime = inode.i_ctime = inode.i_mtime = time(0);
3663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_links_count = 2;
3673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_blocks = fs->blocksize / 512;
3683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_block[0] = blk;
3693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
3703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
3713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Next, write out the inode.
3723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
3733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = ext2fs_write_inode(fs, ino, &inode);
3743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval) {
3753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		com_err("ext2fs_write_inode", retval,
3763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			"While trying to create /lost+found");
3773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
3783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
3793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
3803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Finally, create the directory link
3813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
3823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, 0);
3833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval) {
3843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		com_err("ext2fs_link", retval, "While creating /lost+found");
3853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
3863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
3873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
3883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
3893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Miscellaneous bookkeeping that needs to be kept straight.
3903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
39121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	add_dir_info(fs, ino, EXT2_ROOT_INO);
3923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	adjust_inode_count(fs, EXT2_ROOT_INO, +1);
39321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	ext2fs_icount_store(inode_count, ino, 2);
39421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	ext2fs_icount_store(inode_link_info, ino, 2);
3953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#if 0
396f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	printf("/lost+found created; inode #%lu\n", ino);
3973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#endif
3983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return ino;
3993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
4003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
4023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * This routine will connect a file to lost+found
4033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
4043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'oint reconnect_file(ext2_filsys fs, ino_t inode)
4053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
4063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
4073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char		name[80];
4083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (bad_lost_and_found) {
4103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		printf("Bad or nonexistent /lost+found.  Cannot reconnect.\n");
4113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 1;
4123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
4133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (!lost_and_found) {
4143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		lost_and_found = get_lost_and_found(fs);
4153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (!lost_and_found) {
4163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			printf("Bad or nonexistent /lost+found.  Cannot reconnect.\n");
4173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			bad_lost_and_found++;
4183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			return 1;
4193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
4203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
4213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
422f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	sprintf(name, "#%lu", inode);
4233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = ext2fs_link(fs, lost_and_found, name, inode, 0);
4243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval == EXT2_ET_DIR_NO_SPACE) {
42521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		if (!fix_problem(fs, PR_3_EXPAND_LF_DIR, 0))
4263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			return 1;
4273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		retval = expand_directory(fs, lost_and_found);
4283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (retval) {
4293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			printf("Could not expand /lost+found: %s\n",
4303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			       error_message(retval));
4313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			return 1;
4323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
4333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		retval = ext2fs_link(fs, lost_and_found, name, inode, 0);
4343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
4353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval) {
436f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		printf("Could not reconnect %lu: %s\n", inode,
4373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		       error_message(retval));
4383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 1;
4393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
4403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	adjust_inode_count(fs, inode, +1);
4423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
4443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
4453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
4473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Utility routine to adjust the inode counts on an inode.
4483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
449f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'ostatic errcode_t adjust_inode_count(ext2_filsys fs, ino_t ino, int adj)
4503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
4513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t		retval;
4523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct ext2_inode 	inode;
4533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (!ino)
4553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
4563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = ext2fs_read_inode(fs, ino, &inode);
4583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval)
4593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return retval;
4603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#if 0
462f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	printf("Adjusting link count for inode %lu by %d (from %d)\n", ino, adj,
4633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	       inode.i_links_count);
4643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#endif
4653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_links_count += adj;
46721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	if (adj == 1) {
46821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		ext2fs_icount_increment(inode_count, ino, 0);
46921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		ext2fs_icount_increment(inode_link_info, ino, 0);
47021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	} else {
47121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		ext2fs_icount_decrement(inode_count, ino, 0);
47221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		ext2fs_icount_decrement(inode_link_info, ino, 0);
47321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	}
47421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o
4753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = ext2fs_write_inode(fs, ino, &inode);
4773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval)
4783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return retval;
4793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
4813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
4823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
4843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Fix parent --- this routine fixes up the parent of a directory.
4853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
4863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostruct fix_dotdot_struct {
4873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	ext2_filsys	fs;
4883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	ino_t		parent;
4893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int		done;
4903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o};
4913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic int fix_dotdot_proc(struct ext2_dir_entry *dirent,
4933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			   int	offset,
4943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			   int	blocksize,
4953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			   char	*buf,
4963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			   void	*private)
4973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
4983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct fix_dotdot_struct *fp = (struct fix_dotdot_struct *) private;
4993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
5003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (dirent->name_len != 2)
5023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
5033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (strncmp(dirent->name, "..", 2))
5043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
5053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = adjust_inode_count(fp->fs, dirent->inode, -1);
5073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval)
50850e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o		printf("Error while adjusting inode count on inode %u\n",
5093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		       dirent->inode);
5103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = adjust_inode_count(fp->fs, fp->parent, 1);
5113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval)
512f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		printf("Error while adjusting inode count on inode %lu\n",
5133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		       fp->parent);
5143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	dirent->inode = fp->parent;
5163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	fp->done++;
5183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return DIRENT_ABORT | DIRENT_CHANGED;
5193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
5203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic void fix_dotdot(ext2_filsys fs, struct dir_info *dir, ino_t parent)
5223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
5233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
5243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct fix_dotdot_struct fp;
5253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	fp.fs = fs;
5273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	fp.parent = parent;
5283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	fp.done = 0;
5293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#if 0
531f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	printf("Fixing '..' of inode %lu to be %lu...\n", dir->ino, parent);
5323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#endif
5333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = ext2fs_dir_iterate(fs, dir->ino, DIRENT_FLAG_INCLUDE_EMPTY,
5353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				    0, fix_dotdot_proc, &fp);
5363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval || !fp.done) {
537f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		printf("Couldn't fix parent of inode %lu: %s\n\n",
5383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		       dir->ino, retval ? error_message(retval) :
5393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		       "Couldn't find parent direntory entry");
5403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		ext2fs_unmark_valid(fs);
5413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
5423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	dir->dotdot = parent;
5433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return;
5453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
5463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
5483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * These routines are responsible for expanding a /lost+found if it is
5493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * too small.
5503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
5513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostruct expand_dir_struct {
5533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int	done;
5543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	err;
5553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o};
5563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic int expand_dir_proc(ext2_filsys fs,
5583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			   blk_t	*blocknr,
5593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			   int	blockcnt,
5603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			   void	*private)
5613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
5623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct expand_dir_struct *es = (struct expand_dir_struct *) private;
5633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	blk_t	new_blk;
5643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	static blk_t	last_blk = 0;
5653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char		*block;
5663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
5673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (*blocknr) {
5693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		last_blk = *blocknr;
5703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
5713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
5723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = ext2fs_new_block(fs, last_blk, block_found_map, &new_blk);
5733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval) {
5743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		es->err = retval;
5753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return BLOCK_ABORT;
5763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
5773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (blockcnt > 0) {
5783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		retval = ext2fs_new_dir_block(fs, 0, 0, &block);
5793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (retval) {
5803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			es->err = retval;
5813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			return BLOCK_ABORT;
5823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
5833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		es->done = 1;
5843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	} else {
5853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		block = malloc(fs->blocksize);
5863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (!block) {
5873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			es->err = ENOMEM;
5883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			return BLOCK_ABORT;
5893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
5903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		memset(block, 0, fs->blocksize);
5913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
59250e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	retval = ext2fs_write_dir_block(fs, new_blk, block);
5933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval) {
5943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		es->err = retval;
5953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return BLOCK_ABORT;
5963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
5973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	free(block);
5983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	*blocknr = new_blk;
599f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	ext2fs_mark_block_bitmap(block_found_map, new_blk);
600f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	ext2fs_mark_block_bitmap(fs->block_map, new_blk);
6013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	ext2fs_mark_bb_dirty(fs);
6023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (es->done)
6033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return (BLOCK_CHANGED | BLOCK_ABORT);
6043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	else
6053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return BLOCK_CHANGED;
6063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
6073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
6083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t expand_directory(ext2_filsys fs, ino_t dir)
6093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
6103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
6113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct expand_dir_struct es;
6123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct ext2_inode	inode;
6133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
6143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (!(fs->flags & EXT2_FLAG_RW))
6153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return EXT2_ET_RO_FILSYS;
6163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
6173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = ext2fs_check_directory(fs, dir);
6183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval)
6193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return retval;
6203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
6213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	es.done = 0;
6223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	es.err = 0;
6233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
6243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = ext2fs_block_iterate(fs, dir, BLOCK_FLAG_APPEND,
6253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				      0, expand_dir_proc, &es);
6263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
6273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (es.err)
6283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return es.err;
6293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (!es.done)
6303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return EXT2_ET_EXPAND_DIR_ERR;
6313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
6323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
6333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Update the size and block count fields in the inode.
6343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
6353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = ext2fs_read_inode(fs, dir, &inode);
6363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval)
6373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return retval;
6383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
6393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_size += fs->blocksize;
6403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_blocks += fs->blocksize / 512;
6413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
642f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	e2fsck_write_inode(fs, dir, &inode, "expand_directory");
6433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
6443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
6453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
6463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
6473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
6483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
649