pass3.c revision 030970ed750b6a169c32ffb8b19bce3150198629
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% 103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Pass #3 assures that all directories are connected to the 123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * filesystem tree, using the following algorithm: 133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * First, the root directory is checked to make sure it exists; if 153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * not, e2fsck will offer to create a new one. It is then marked as 163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * "done". 173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Then, pass3 interates over all directory inodes; for each directory 193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * it attempts to trace up the filesystem tree, using dirinfo.parent 203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * until it reaches a directory which has been marked "done". If it 213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * can not do so, then the directory must be disconnected, and e2fsck 223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * will offer to reconnect it to /lost+found. While it is chasing 233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * parent pointers up the filesystem tree, if pass3 sees a directory 243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * twice, then it has detected a filesystem loop, and it will again 253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * offer to reconnect the directory to /lost+found in to break the 263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * filesystem loop. 273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 2808b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o * Pass 3 also contains the subroutine, e2fsck_reconnect_file() to 2908b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o * reconnect inodes to /lost+found; this subroutine is also used by 3008b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o * pass 4. e2fsck_reconnect_file() calls get_lost_and_found(), which 3108b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o * is responsible for creating /lost+found if it does not exist. 323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Pass 3 frees the following data structures: 343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * - The dirinfo directory information cache. 353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 3750e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o#ifdef HAVE_ERRNO_H 3850e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o#include <errno.h> 3950e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o#endif 403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include "e2fsck.h" 4221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o#include "problem.h" 433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 441b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'ostatic void check_root(e2fsck_t ctx); 4528ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'ostatic int check_directory(e2fsck_t ctx, struct dir_info *dir, 4628ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o struct problem_context *pctx); 4786c627ec1136446409a0170d439e60c148e6eb48Theodore Ts'ostatic void fix_dotdot(e2fsck_t ctx, struct dir_info *dir, 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; 513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 5208b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'ovoid e2fsck_pass3(e2fsck_t ctx) 533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 541b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ext2_filsys fs = ctx->fs; 553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int i; 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 638bf191e8660939687ef35c013066d2082cb16722Theodore Ts'o#ifdef RESOURCE_TRACK 643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o init_resource_track(&rtrack); 658bf191e8660939687ef35c013066d2082cb16722Theodore Ts'o#endif 663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 671b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o clear_problem_context(&pctx); 681b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o 693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#ifdef MTRACE 703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o mtrace_print("Pass 3"); 713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#endif 723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 731b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (!(ctx->options & E2F_OPT_PREEN)) 741b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o fix_problem(ctx, PR_3_PASS_HEADER, &pctx); 753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Allocate some bitmaps to do loop detection. 783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 790c4a07264e55b42c6e30230e66b1dea7d4b94ea9Theodore Ts'o pctx.errcode = ext2fs_allocate_inode_bitmap(fs, _("inode done bitmap"), 801b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o &inode_done_map); 811b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (pctx.errcode) { 821b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o pctx.num = 2; 831b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o fix_problem(ctx, PR_3_ALLOCATE_IBITMAP_ERROR, &pctx); 8408b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o ctx->flags |= E2F_FLAG_ABORT; 85a02ce9df5ff5db2982462aec7162f7142dc18131Theodore Ts'o goto abort_exit; 863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 878bf191e8660939687ef35c013066d2082cb16722Theodore Ts'o#ifdef RESOURCE_TRACK 885596defa1e212242c1bf1b028139143fbb7777a0Theodore Ts'o if (ctx->options & E2F_OPT_TIME) { 895596defa1e212242c1bf1b028139143fbb7777a0Theodore Ts'o e2fsck_clear_progbar(ctx); 900c4a07264e55b42c6e30230e66b1dea7d4b94ea9Theodore Ts'o print_resource_track(_("Peak memory"), &ctx->global_rtrack); 915596defa1e212242c1bf1b028139143fbb7777a0Theodore Ts'o } 928bf191e8660939687ef35c013066d2082cb16722Theodore Ts'o#endif 933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 941b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o check_root(ctx); 95a02ce9df5ff5db2982462aec7162f7142dc18131Theodore Ts'o if (ctx->flags & E2F_FLAG_SIGNAL_MASK) 96a02ce9df5ff5db2982462aec7162f7142dc18131Theodore Ts'o goto abort_exit; 9708b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o 98f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o ext2fs_mark_inode_bitmap(inode_done_map, EXT2_ROOT_INO); 993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 1007f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o maxdirs = e2fsck_get_num_dirinfo(ctx); 101f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o count = 1; 102f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o 103f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o if (ctx->progress) 1047f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o if ((ctx->progress)(ctx, 3, 0, maxdirs)) 105f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o goto abort_exit; 106f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o 10708b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o for (i=0; (dir = e2fsck_dir_info_iter(ctx, &i)) != 0;) { 1084cae04529eda0e482ceaa86b48e532f9c8d35f24Theodore Ts'o if (ctx->flags & E2F_FLAG_SIGNAL_MASK) 1094cae04529eda0e482ceaa86b48e532f9c8d35f24Theodore Ts'o goto abort_exit; 1104cae04529eda0e482ceaa86b48e532f9c8d35f24Theodore Ts'o if (ctx->progress && (ctx->progress)(ctx, 3, count++, maxdirs)) 1114cae04529eda0e482ceaa86b48e532f9c8d35f24Theodore Ts'o goto abort_exit; 1121b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, dir->ino)) 11328ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o if (check_directory(ctx, dir, &pctx)) 11428ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o goto abort_exit; 1153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 116a02ce9df5ff5db2982462aec7162f7142dc18131Theodore Ts'o 1175a679c8fb15540f86fc2eae3117412adc6ecbb33Theodore Ts'o /* 1185a679c8fb15540f86fc2eae3117412adc6ecbb33Theodore Ts'o * Force the creation of /lost+found if not present 1195a679c8fb15540f86fc2eae3117412adc6ecbb33Theodore Ts'o */ 1205a679c8fb15540f86fc2eae3117412adc6ecbb33Theodore Ts'o if ((ctx->flags & E2F_OPT_READONLY) == 0) 121850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o e2fsck_get_lost_and_found(ctx, 1); 1225a679c8fb15540f86fc2eae3117412adc6ecbb33Theodore Ts'o 123850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o /* 124850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o * If there are any directories that need to be indexed or 125850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o * optimized, do it here. 126850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o */ 127850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o e2fsck_rehash_directories(ctx); 128850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o 129a02ce9df5ff5db2982462aec7162f7142dc18131Theodore Ts'oabort_exit: 13008b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o e2fsck_free_dir_info(ctx); 13128ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o if (inode_loop_detect) { 132a02ce9df5ff5db2982462aec7162f7142dc18131Theodore Ts'o ext2fs_free_inode_bitmap(inode_loop_detect); 13328ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o inode_loop_detect = 0; 13428ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o } 13528ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o if (inode_done_map) { 136a02ce9df5ff5db2982462aec7162f7142dc18131Theodore Ts'o ext2fs_free_inode_bitmap(inode_done_map); 13728ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o inode_done_map = 0; 13828ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o } 139b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o 1408bf191e8660939687ef35c013066d2082cb16722Theodore Ts'o#ifdef RESOURCE_TRACK 1415596defa1e212242c1bf1b028139143fbb7777a0Theodore Ts'o if (ctx->options & E2F_OPT_TIME2) { 1425596defa1e212242c1bf1b028139143fbb7777a0Theodore Ts'o e2fsck_clear_progbar(ctx); 1430c4a07264e55b42c6e30230e66b1dea7d4b94ea9Theodore Ts'o print_resource_track(_("Pass 3"), &rtrack); 1445596defa1e212242c1bf1b028139143fbb7777a0Theodore Ts'o } 1458bf191e8660939687ef35c013066d2082cb16722Theodore Ts'o#endif 1463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 1473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 1483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/* 1493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * This makes sure the root inode is present; if not, we ask if the 1503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * user wants us to create it. Not creating it is a fatal error. 1513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 1521b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'ostatic void check_root(e2fsck_t ctx) 1533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 1541b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ext2_filsys fs = ctx->fs; 1553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o blk_t blk; 1563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct ext2_inode inode; 1573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o char * block; 1581b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o struct problem_context pctx; 1593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 1601b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o clear_problem_context(&pctx); 1611b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o 1621b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (ext2fs_test_inode_bitmap(ctx->inode_used_map, EXT2_ROOT_INO)) { 1633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 16408b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o * If the root inode is not a directory, die here. The 1653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * user must have answered 'no' in pass1 when we 1663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * offered to clear it. 1673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 1681b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (!(ext2fs_test_inode_bitmap(ctx->inode_dir_map, 169f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o EXT2_ROOT_INO))) { 170f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o fix_problem(ctx, PR_3_ROOT_NOT_DIR_ABORT, &pctx); 171f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o ctx->flags |= E2F_FLAG_ABORT; 172f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o } 1733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return; 1743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 1753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 176f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o if (!fix_problem(ctx, PR_3_NO_ROOT_INODE, &pctx)) { 177f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o fix_problem(ctx, PR_3_NO_ROOT_INODE_ABORT, &pctx); 178f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o ctx->flags |= E2F_FLAG_ABORT; 179f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o return; 180f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o } 1813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 182f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o e2fsck_read_bitmaps(ctx); 1833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 1843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 1853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * First, find a free block 1863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 1871b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o pctx.errcode = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk); 1881b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (pctx.errcode) { 1891b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o pctx.str = "ext2fs_new_block"; 1901b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx); 19108b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o ctx->flags |= E2F_FLAG_ABORT; 19208b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o return; 1933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 1941b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ext2fs_mark_block_bitmap(ctx->block_found_map, blk); 195f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o ext2fs_mark_block_bitmap(fs->block_map, blk); 1963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o ext2fs_mark_bb_dirty(fs); 1973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 1983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 1993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Now let's create the actual data block for the inode 2003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 2011b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o pctx.errcode = ext2fs_new_dir_block(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, 2021b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o &block); 2031b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (pctx.errcode) { 2041b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o pctx.str = "ext2fs_new_dir_block"; 2051b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx); 20608b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o ctx->flags |= E2F_FLAG_ABORT; 20708b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o return; 2083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 2093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 2101b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o pctx.errcode = ext2fs_write_dir_block(fs, blk, block); 2111b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (pctx.errcode) { 2121b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o pctx.str = "ext2fs_write_dir_block"; 2131b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx); 21408b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o ctx->flags |= E2F_FLAG_ABORT; 21508b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o return; 2163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 217c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o ext2fs_free_mem(&block); 2183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 2193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 2203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Set up the inode structure 2213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 2223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o memset(&inode, 0, sizeof(inode)); 2233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o inode.i_mode = 040755; 2243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o inode.i_size = fs->blocksize; 2253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o inode.i_atime = inode.i_ctime = inode.i_mtime = time(0); 2263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o inode.i_links_count = 2; 2273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o inode.i_blocks = fs->blocksize / 512; 2283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o inode.i_block[0] = blk; 2293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 2303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 2313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Write out the inode. 2323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 233030970ed750b6a169c32ffb8b19bce3150198629Theodore Ts'o pctx.errcode = ext2fs_write_new_inode(fs, EXT2_ROOT_INO, &inode); 2341b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (pctx.errcode) { 2351b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o pctx.str = "ext2fs_write_inode"; 2361b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx); 23708b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o ctx->flags |= E2F_FLAG_ABORT; 23808b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o return; 2393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 2403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 2413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 2423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Miscellaneous bookkeeping... 2433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 24408b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o e2fsck_add_dir_info(ctx, EXT2_ROOT_INO, EXT2_ROOT_INO); 2451b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ext2fs_icount_store(ctx->inode_count, EXT2_ROOT_INO, 2); 2461b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ext2fs_icount_store(ctx->inode_link_info, EXT2_ROOT_INO, 2); 2473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 2481b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ext2fs_mark_inode_bitmap(ctx->inode_used_map, EXT2_ROOT_INO); 2491b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ext2fs_mark_inode_bitmap(ctx->inode_dir_map, EXT2_ROOT_INO); 250f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o ext2fs_mark_inode_bitmap(fs->inode_map, EXT2_ROOT_INO); 2513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o ext2fs_mark_ib_dirty(fs); 2523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 2533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 2543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/* 2553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * This subroutine is responsible for making sure that a particular 2563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * directory is connected to the root; if it isn't we trace it up as 2573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * far as we can go, and then offer to connect the resulting parent to 2583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * the lost+found. We have to do loop detection; if we ever discover 2593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * a loop, we treat that as a disconnected directory and offer to 2603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * reparent it to lost+found. 26128ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o * 26228ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o * However, loop detection is expensive, because for very large 26328ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o * filesystems, the inode_loop_detect bitmap is huge, and clearing it 26428ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o * is non-trivial. Loops in filesystems are also a rare error case, 26528ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o * and we shouldn't optimize for error cases. So we try two passes of 26628ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o * the algorithm. The first time, we ignore loop detection and merely 26728ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o * increment a counter; if the counter exceeds some extreme threshold, 26828ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o * then we try again with the loop detection bitmap enabled. 2693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 27028ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'ostatic int check_directory(e2fsck_t ctx, struct dir_info *dir, 27128ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o struct problem_context *pctx) 2723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 27328ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o ext2_filsys fs = ctx->fs; 27421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o struct dir_info *p = dir; 27528ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o int loop_pass = 0, parent_count = 0; 2763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 2777f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o if (!p) 27828ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o return 0; 2797f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o 28028ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o while (1) { 2813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 2823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Mark this inode as being "done"; by the time we 2833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * return from this function, the inode we either be 2843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * verified as being connected to the directory tree, 2853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * or we will have offered to reconnect this to 2863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * lost+found. 28728ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o * 28828ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o * If it was marked done already, then we've reached a 28928ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o * parent we've already checked. 2903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 29128ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o if (ext2fs_mark_inode_bitmap(inode_done_map, p->ino)) 29228ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o break; 2937f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o 2943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 2953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * If this directory doesn't have a parent, or we've 2963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * seen the parent once already, then offer to 2973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * reparent it to lost+found 2983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 2993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (!p->parent || 30028ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o (loop_pass && 30128ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o (ext2fs_test_inode_bitmap(inode_loop_detect, 30228ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o p->parent)))) { 3037f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o pctx->ino = p->ino; 3047f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o if (fix_problem(ctx, PR_3_UNCONNECTED_DIR, pctx)) { 3052e5fcce05ea583c480b28bf3b1f2aa427a3dcc07Theodore Ts'o if (e2fsck_reconnect_file(ctx, pctx->ino)) 3067f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o ext2fs_unmark_valid(fs); 3077f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o else { 3082e5fcce05ea583c480b28bf3b1f2aa427a3dcc07Theodore Ts'o p = e2fsck_get_dir_info(ctx, pctx->ino); 309850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o p->parent = ctx->lost_and_found; 310850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o fix_dotdot(ctx, p, ctx->lost_and_found); 3117f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o } 3127f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o } 3133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o break; 3147f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o } 31508b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o p = e2fsck_get_dir_info(ctx, p->parent); 3167f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o if (!p) { 3177f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o fix_problem(ctx, PR_3_NO_DIRINFO, pctx); 31828ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o return 0; 31928ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o } 32028ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o if (loop_pass) { 32128ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o ext2fs_mark_inode_bitmap(inode_loop_detect, 32228ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o p->ino); 32328ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o } else if (parent_count++ > 2048) { 32428ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o /* 32528ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o * If we've run into a path depth that's 32628ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o * greater than 2048, try again with the inode 32728ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o * loop bitmap turned on and start from the 32828ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o * top. 32928ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o */ 33028ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o loop_pass = 1; 33128ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o if (inode_loop_detect) 33228ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o ext2fs_clear_inode_bitmap(inode_loop_detect); 33328ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o else { 33428ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o pctx->errcode = ext2fs_allocate_inode_bitmap(fs, _("inode loop detection bitmap"), &inode_loop_detect); 33528ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o if (pctx->errcode) { 33628ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o pctx->num = 1; 33728ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o fix_problem(ctx, 33828ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o PR_3_ALLOCATE_IBITMAP_ERROR, pctx); 33928ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o ctx->flags |= E2F_FLAG_ABORT; 34028ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o return -1; 34128ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o } 34228ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o } 34328ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o p = dir; 3443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 34521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o } 3463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 3473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 3483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Make sure that .. and the parent directory are the same; 3493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * offer to fix it if not. 3503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 3513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (dir->parent != dir->dotdot) { 35221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o pctx->ino = dir->ino; 35321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o pctx->ino2 = dir->dotdot; 35421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o pctx->dir = dir->parent; 3551b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (fix_problem(ctx, PR_3_BAD_DOT_DOT, pctx)) 3561b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o fix_dotdot(ctx, dir, dir->parent); 3573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 35828ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o return 0; 359b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o} 3603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 3613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/* 3623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * This routine gets the lost_and_found inode, making it a directory 3633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * if necessary 3643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 365850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'oext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix) 3663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 3671b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ext2_filsys fs = ctx->fs; 36886c627ec1136446409a0170d439e60c148e6eb48Theodore Ts'o ext2_ino_t ino; 3693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o blk_t blk; 3703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval; 3713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct ext2_inode inode; 3723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o char * block; 37353ef44c40a3e425d2c700d8fd77a6b655aa121feTheodore Ts'o static const char name[] = "lost+found"; 3741b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o struct problem_context pctx; 3754a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o struct dir_info *dirinfo; 3763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 377850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o if (ctx->lost_and_found) 378850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o return ctx->lost_and_found; 379850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o 3801b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o clear_problem_context(&pctx); 3811b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o 38221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name, 38321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o sizeof(name)-1, 0, &ino); 384850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o if (retval && !fix) 385850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o return 0; 3864a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o if (!retval) { 387850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, ino)) { 388850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o ctx->lost_and_found = ino; 3894a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o return ino; 390850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o } 391850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o 3924a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o /* Lost+found isn't a directory! */ 393850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o if (!fix) 394850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o return 0; 3954a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o pctx.ino = ino; 3964a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o if (!fix_problem(ctx, PR_3_LPF_NOTDIR, &pctx)) 3974a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o return 0; 3984a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o 399c54b3c3c99a5d3011f6f60934e90dae7f60b3b00Theodore Ts'o /* OK, unlink the old /lost+found file. */ 4004a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o pctx.errcode = ext2fs_unlink(fs, EXT2_ROOT_INO, name, ino, 0); 4014a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o if (pctx.errcode) { 4024a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o pctx.str = "ext2fs_unlink"; 4034a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); 4044a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o return 0; 4054a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o } 4064a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o dirinfo = e2fsck_get_dir_info(ctx, ino); 4074a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o if (dirinfo) 4084a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o dirinfo->parent = 0; 409b0700a1b6083f2f0c19c349f07ca80e70ec456beTheodore Ts'o e2fsck_adjust_inode_count(ctx, ino, -1); 4104a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o } else if (retval != EXT2_ET_FILE_NOT_FOUND) { 4111b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o pctx.errcode = retval; 4121b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o fix_problem(ctx, PR_3_ERR_FIND_LPF, &pctx); 4131b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o } 4141b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (!fix_problem(ctx, PR_3_NO_LF_DIR, 0)) 4153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 4163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 4183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Read the inode and block bitmaps in; we'll be messing with 4193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * them. 4203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 421f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o e2fsck_read_bitmaps(ctx); 4223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 4243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * First, find a free block 4253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 4261b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o retval = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk); 4273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) { 4281b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o pctx.errcode = retval; 4291b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o fix_problem(ctx, PR_3_ERR_LPF_NEW_BLOCK, &pctx); 4303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 4313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 4321b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ext2fs_mark_block_bitmap(ctx->block_found_map, blk); 4330684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o ext2fs_block_alloc_stats(fs, blk, +1); 4343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 4363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Next find a free inode. 4373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 438b0700a1b6083f2f0c19c349f07ca80e70ec456beTheodore Ts'o retval = ext2fs_new_inode(fs, EXT2_ROOT_INO, 040700, 4391b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ctx->inode_used_map, &ino); 4403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) { 4411b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o pctx.errcode = retval; 4421b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o fix_problem(ctx, PR_3_ERR_LPF_NEW_INODE, &pctx); 4433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 4443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 4451b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino); 4461b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ext2fs_mark_inode_bitmap(ctx->inode_dir_map, ino); 4470684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o ext2fs_inode_alloc_stats2(fs, ino, +1, 1); 4483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 4503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Now let's create the actual data block for the inode 4513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 4523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = ext2fs_new_dir_block(fs, ino, EXT2_ROOT_INO, &block); 4533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) { 4541b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o pctx.errcode = retval; 4551b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o fix_problem(ctx, PR_3_ERR_LPF_NEW_DIR_BLOCK, &pctx); 4563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 4573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 4583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 45950e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o retval = ext2fs_write_dir_block(fs, blk, block); 460c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o ext2fs_free_mem(&block); 4613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) { 4621b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o pctx.errcode = retval; 4631b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o fix_problem(ctx, PR_3_ERR_LPF_WRITE_BLOCK, &pctx); 4643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 4653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 4663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 4683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Set up the inode structure 4693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 4703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o memset(&inode, 0, sizeof(inode)); 47164aecc4dd35b48f66f452f06c49587c838990d39Theodore Ts'o inode.i_mode = 040700; 4723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o inode.i_size = fs->blocksize; 4733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o inode.i_atime = inode.i_ctime = inode.i_mtime = time(0); 4743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o inode.i_links_count = 2; 4753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o inode.i_blocks = fs->blocksize / 512; 4763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o inode.i_block[0] = blk; 4773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 4793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Next, write out the inode. 4803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 481030970ed750b6a169c32ffb8b19bce3150198629Theodore Ts'o pctx.errcode = ext2fs_write_new_inode(fs, ino, &inode); 4821b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (pctx.errcode) { 4831b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o pctx.str = "ext2fs_write_inode"; 4841b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); 4853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 4863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 4873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 4883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Finally, create the directory link 4893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 4906fdc7a325c8bff67fc3a0489d0858bc7c48dc1a3Theodore Ts'o pctx.errcode = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, EXT2_FT_DIR); 4911b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (pctx.errcode) { 4921b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o pctx.str = "ext2fs_link"; 4931b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); 4943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 4953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 4963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 4983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Miscellaneous bookkeeping that needs to be kept straight. 4993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 50008b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o e2fsck_add_dir_info(ctx, ino, EXT2_ROOT_INO); 501b0700a1b6083f2f0c19c349f07ca80e70ec456beTheodore Ts'o e2fsck_adjust_inode_count(ctx, EXT2_ROOT_INO, 1); 5021b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ext2fs_icount_store(ctx->inode_count, ino, 2); 5031b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ext2fs_icount_store(ctx->inode_link_info, ino, 2); 504850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o ctx->lost_and_found = ino; 5053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#if 0 506f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o printf("/lost+found created; inode #%lu\n", ino); 5073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#endif 5083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return ino; 5093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 5103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 5113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/* 5123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * This routine will connect a file to lost+found 5133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 51486c627ec1136446409a0170d439e60c148e6eb48Theodore Ts'oint e2fsck_reconnect_file(e2fsck_t ctx, ext2_ino_t ino) 5153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 5161b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ext2_filsys fs = ctx->fs; 5173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval; 5183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o char name[80]; 5191b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o struct problem_context pctx; 5206fdc7a325c8bff67fc3a0489d0858bc7c48dc1a3Theodore Ts'o struct ext2_inode inode; 5216fdc7a325c8bff67fc3a0489d0858bc7c48dc1a3Theodore Ts'o int file_type = 0; 5221b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o 5231b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o clear_problem_context(&pctx); 5246fdc7a325c8bff67fc3a0489d0858bc7c48dc1a3Theodore Ts'o pctx.ino = ino; 5251b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o 526850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o if (!ctx->bad_lost_and_found && !ctx->lost_and_found) { 527850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o if (e2fsck_get_lost_and_found(ctx, 1) == 0) 528850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o ctx->bad_lost_and_found++; 5291b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o } 530850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o if (ctx->bad_lost_and_found) { 5311b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o fix_problem(ctx, PR_3_NO_LPF, &pctx); 5323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 1; 5333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 5341b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o 53586c627ec1136446409a0170d439e60c148e6eb48Theodore Ts'o sprintf(name, "#%u", ino); 5366fdc7a325c8bff67fc3a0489d0858bc7c48dc1a3Theodore Ts'o if (ext2fs_read_inode(fs, ino, &inode) == 0) 5376fdc7a325c8bff67fc3a0489d0858bc7c48dc1a3Theodore Ts'o file_type = ext2_file_type(inode.i_mode); 538850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o retval = ext2fs_link(fs, ctx->lost_and_found, name, ino, file_type); 5393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval == EXT2_ET_DIR_NO_SPACE) { 5401b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (!fix_problem(ctx, PR_3_EXPAND_LF_DIR, &pctx)) 5413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 1; 542850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o retval = e2fsck_expand_directory(ctx, ctx->lost_and_found, 543850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o 1, 0); 5443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) { 5451b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o pctx.errcode = retval; 5461b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o fix_problem(ctx, PR_3_CANT_EXPAND_LPF, &pctx); 5473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 1; 5483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 549850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o retval = ext2fs_link(fs, ctx->lost_and_found, name, 550850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o ino, file_type); 5513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 5523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) { 5531b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o pctx.errcode = retval; 5541b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o fix_problem(ctx, PR_3_CANT_RECONNECT, &pctx); 5553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 1; 5563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 557b0700a1b6083f2f0c19c349f07ca80e70ec456beTheodore Ts'o e2fsck_adjust_inode_count(ctx, ino, 1); 5583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 5593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 5603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 5613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 5623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/* 5633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Utility routine to adjust the inode counts on an inode. 5643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 565b0700a1b6083f2f0c19c349f07ca80e70ec456beTheodore Ts'oerrcode_t e2fsck_adjust_inode_count(e2fsck_t ctx, ext2_ino_t ino, int adj) 5663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 5671b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ext2_filsys fs = ctx->fs; 5683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval; 5693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct ext2_inode inode; 5703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 5713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (!ino) 5723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 5733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 5743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = ext2fs_read_inode(fs, ino, &inode); 5753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) 5763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return retval; 5773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 5783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#if 0 579f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o printf("Adjusting link count for inode %lu by %d (from %d)\n", ino, adj, 5803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o inode.i_links_count); 5813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#endif 5823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 58321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o if (adj == 1) { 5841b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ext2fs_icount_increment(ctx->inode_count, ino, 0); 585c1faf9cc3a2418c536eee472f054c9604ad3f213Theodore Ts'o if (inode.i_links_count == (__u16) ~0) 586c1faf9cc3a2418c536eee472f054c9604ad3f213Theodore Ts'o return 0; 5871b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ext2fs_icount_increment(ctx->inode_link_info, ino, 0); 588c1faf9cc3a2418c536eee472f054c9604ad3f213Theodore Ts'o inode.i_links_count++; 589c1faf9cc3a2418c536eee472f054c9604ad3f213Theodore Ts'o } else if (adj == -1) { 5901b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ext2fs_icount_decrement(ctx->inode_count, ino, 0); 591c1faf9cc3a2418c536eee472f054c9604ad3f213Theodore Ts'o if (inode.i_links_count == 0) 592c1faf9cc3a2418c536eee472f054c9604ad3f213Theodore Ts'o return 0; 5931b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ext2fs_icount_decrement(ctx->inode_link_info, ino, 0); 594c1faf9cc3a2418c536eee472f054c9604ad3f213Theodore Ts'o inode.i_links_count--; 59521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o } 59621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o 5973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = ext2fs_write_inode(fs, ino, &inode); 5983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) 5993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return retval; 6003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 6013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 6023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 6033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 6043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/* 6053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Fix parent --- this routine fixes up the parent of a directory. 6063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 6073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostruct fix_dotdot_struct { 6083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o ext2_filsys fs; 60986c627ec1136446409a0170d439e60c148e6eb48Theodore Ts'o ext2_ino_t parent; 6103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int done; 6111b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o e2fsck_t ctx; 6123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}; 6133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 6143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic int fix_dotdot_proc(struct ext2_dir_entry *dirent, 615544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o int offset EXT2FS_ATTR((unused)), 616544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o int blocksize EXT2FS_ATTR((unused)), 617544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o char *buf EXT2FS_ATTR((unused)), 61854dc7ca2869897ae8cb81a9ab9880ebff11680bcTheodore Ts'o void *priv_data) 6193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 62054dc7ca2869897ae8cb81a9ab9880ebff11680bcTheodore Ts'o struct fix_dotdot_struct *fp = (struct fix_dotdot_struct *) priv_data; 6213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval; 6221b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o struct problem_context pctx; 6233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 624b6f7983197fe217cf20862c93d72620be3b0fcecTheodore Ts'o if ((dirent->name_len & 0xFF) != 2) 6253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 6263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (strncmp(dirent->name, "..", 2)) 6273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 6283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 6291b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o clear_problem_context(&pctx); 6301b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o 631b0700a1b6083f2f0c19c349f07ca80e70ec456beTheodore Ts'o retval = e2fsck_adjust_inode_count(fp->ctx, dirent->inode, -1); 6321b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (retval) { 6331b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o pctx.errcode = retval; 6341b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx); 6351b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o } 636b0700a1b6083f2f0c19c349f07ca80e70ec456beTheodore Ts'o retval = e2fsck_adjust_inode_count(fp->ctx, fp->parent, 1); 6371b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (retval) { 6381b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o pctx.errcode = retval; 6391b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx); 6401b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o } 6413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o dirent->inode = fp->parent; 6423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 6433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o fp->done++; 6443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return DIRENT_ABORT | DIRENT_CHANGED; 6453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 6463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 64786c627ec1136446409a0170d439e60c148e6eb48Theodore Ts'ostatic void fix_dotdot(e2fsck_t ctx, struct dir_info *dir, ext2_ino_t parent) 6483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 6491b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ext2_filsys fs = ctx->fs; 6503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval; 6513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct fix_dotdot_struct fp; 6521b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o struct problem_context pctx; 6533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 6543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o fp.fs = fs; 6553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o fp.parent = parent; 6563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o fp.done = 0; 6571b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o fp.ctx = ctx; 6583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 6593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#if 0 660f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o printf("Fixing '..' of inode %lu to be %lu...\n", dir->ino, parent); 6613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#endif 6623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 6633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = ext2fs_dir_iterate(fs, dir->ino, DIRENT_FLAG_INCLUDE_EMPTY, 6643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 0, fix_dotdot_proc, &fp); 6653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval || !fp.done) { 6661b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o clear_problem_context(&pctx); 6671b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o pctx.ino = dir->ino; 6681b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o pctx.errcode = retval; 6691b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o fix_problem(ctx, retval ? PR_3_FIX_PARENT_ERR : 6701b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o PR_3_FIX_PARENT_NOFIND, &pctx); 6713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o ext2fs_unmark_valid(fs); 6723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 6733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o dir->dotdot = parent; 6743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 6753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return; 6763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 6773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 6783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/* 6793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * These routines are responsible for expanding a /lost+found if it is 6803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * too small. 6813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 6823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 6833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostruct expand_dir_struct { 684b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o int num; 685b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o int guaranteed_size; 686c1faf9cc3a2418c536eee472f054c9604ad3f213Theodore Ts'o int newblocks; 687b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o int last_block; 688c1faf9cc3a2418c536eee472f054c9604ad3f213Theodore Ts'o errcode_t err; 689c1faf9cc3a2418c536eee472f054c9604ad3f213Theodore Ts'o e2fsck_t ctx; 6903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}; 6913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 6923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic int expand_dir_proc(ext2_filsys fs, 6933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o blk_t *blocknr, 694133a56dc9da52054bc27b4c1a23f03e3405003dbTheodore Ts'o e2_blkcnt_t blockcnt, 695544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o blk_t ref_block EXT2FS_ATTR((unused)), 696544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o int ref_offset EXT2FS_ATTR((unused)), 69754dc7ca2869897ae8cb81a9ab9880ebff11680bcTheodore Ts'o void *priv_data) 6983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 69954dc7ca2869897ae8cb81a9ab9880ebff11680bcTheodore Ts'o struct expand_dir_struct *es = (struct expand_dir_struct *) priv_data; 7003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o blk_t new_blk; 7013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o static blk_t last_blk = 0; 7023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o char *block; 7033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval; 7041b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o e2fsck_t ctx; 7051b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o 7061b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ctx = es->ctx; 7073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 708b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o if (es->guaranteed_size && blockcnt >= es->guaranteed_size) 709b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o return BLOCK_ABORT; 710b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o 711b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o if (blockcnt > 0) 712b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o es->last_block = blockcnt; 7133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (*blocknr) { 7143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o last_blk = *blocknr; 7153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 7163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 7171b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o retval = ext2fs_new_block(fs, last_blk, ctx->block_found_map, 7181b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o &new_blk); 7193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) { 7203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o es->err = retval; 7213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return BLOCK_ABORT; 7223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 7233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (blockcnt > 0) { 7243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = ext2fs_new_dir_block(fs, 0, 0, &block); 7253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) { 7263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o es->err = retval; 7273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return BLOCK_ABORT; 7283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 729b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o es->num--; 730b8647faa3b0a7dfbb2456a7b37321ee4bbda651cTheodore Ts'o retval = ext2fs_write_dir_block(fs, new_blk, block); 7313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } else { 732c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o retval = ext2fs_get_mem(fs->blocksize, &block); 73308b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o if (retval) { 73408b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o es->err = retval; 7353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return BLOCK_ABORT; 7363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 7373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o memset(block, 0, fs->blocksize); 738b8647faa3b0a7dfbb2456a7b37321ee4bbda651cTheodore Ts'o retval = io_channel_write_blk(fs->io, new_blk, 1, block); 7393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 7403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) { 7413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o es->err = retval; 7423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return BLOCK_ABORT; 7433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 744c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o ext2fs_free_mem(&block); 7453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *blocknr = new_blk; 7461b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ext2fs_mark_block_bitmap(ctx->block_found_map, new_blk); 747b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o ext2fs_block_alloc_stats(fs, new_blk, +1); 748c1faf9cc3a2418c536eee472f054c9604ad3f213Theodore Ts'o es->newblocks++; 749c1faf9cc3a2418c536eee472f054c9604ad3f213Theodore Ts'o 750b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o if (es->num == 0) 7513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return (BLOCK_CHANGED | BLOCK_ABORT); 7523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o else 7533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return BLOCK_CHANGED; 7543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 7553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 756b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'oerrcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir, 757b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o int num, int guaranteed_size) 7583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 7591b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ext2_filsys fs = ctx->fs; 7603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval; 7613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct expand_dir_struct es; 7623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct ext2_inode inode; 7633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 7643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (!(fs->flags & EXT2_FLAG_RW)) 7653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return EXT2_ET_RO_FILSYS; 7663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 767b8647faa3b0a7dfbb2456a7b37321ee4bbda651cTheodore Ts'o /* 768b8647faa3b0a7dfbb2456a7b37321ee4bbda651cTheodore Ts'o * Read the inode and block bitmaps in; we'll be messing with 769b8647faa3b0a7dfbb2456a7b37321ee4bbda651cTheodore Ts'o * them. 770b8647faa3b0a7dfbb2456a7b37321ee4bbda651cTheodore Ts'o */ 771b8647faa3b0a7dfbb2456a7b37321ee4bbda651cTheodore Ts'o e2fsck_read_bitmaps(ctx); 772c1faf9cc3a2418c536eee472f054c9604ad3f213Theodore Ts'o 7733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = ext2fs_check_directory(fs, dir); 7743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) 7753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return retval; 7763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 777b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o es.num = num; 778b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o es.guaranteed_size = guaranteed_size; 779b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o es.last_block = 0; 7803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o es.err = 0; 781c1faf9cc3a2418c536eee472f054c9604ad3f213Theodore Ts'o es.newblocks = 0; 7821b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o es.ctx = ctx; 7833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 784133a56dc9da52054bc27b4c1a23f03e3405003dbTheodore Ts'o retval = ext2fs_block_iterate2(fs, dir, BLOCK_FLAG_APPEND, 785133a56dc9da52054bc27b4c1a23f03e3405003dbTheodore Ts'o 0, expand_dir_proc, &es); 7863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 7873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (es.err) 7883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return es.err; 7893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 7903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 7913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Update the size and block count fields in the inode. 7923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 7933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = ext2fs_read_inode(fs, dir, &inode); 7943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) 7953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return retval; 7963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 797b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o inode.i_size = (es.last_block + 1) * fs->blocksize; 798c1faf9cc3a2418c536eee472f054c9604ad3f213Theodore Ts'o inode.i_blocks += (fs->blocksize / 512) * es.newblocks; 7993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 80008b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o e2fsck_write_inode(ctx, dir, &inode, "expand_directory"); 8013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 8023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 8033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 804b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o 805