pass3.c revision 56c8c592ac48c0fc9772153bb7bdf621b1de0ab9
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; 2251f3ad14a5ad5df3ac4012d41ef5d76411cd8fff3Theodore Ts'o inode.i_atime = inode.i_ctime = inode.i_mtime = ctx->now; 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); 309a4b66fb1339c1f60c2d280dd949754d4206aca0aBrian Behlendorf if (!p) { 310a4b66fb1339c1f60c2d280dd949754d4206aca0aBrian Behlendorf fix_problem(ctx, 311a4b66fb1339c1f60c2d280dd949754d4206aca0aBrian Behlendorf PR_3_NO_DIRINFO, pctx); 312a4b66fb1339c1f60c2d280dd949754d4206aca0aBrian Behlendorf return 0; 313a4b66fb1339c1f60c2d280dd949754d4206aca0aBrian Behlendorf } 314850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o p->parent = ctx->lost_and_found; 315850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o fix_dotdot(ctx, p, ctx->lost_and_found); 3167f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o } 3177f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o } 3183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o break; 3197f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o } 32008b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o p = e2fsck_get_dir_info(ctx, p->parent); 3217f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o if (!p) { 322a4b66fb1339c1f60c2d280dd949754d4206aca0aBrian Behlendorf pctx->ino = p->parent; 3237f813ba33711902f5e557da49f98622532e7556dTheodore Ts'o fix_problem(ctx, PR_3_NO_DIRINFO, pctx); 32428ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o return 0; 32528ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o } 32628ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o if (loop_pass) { 32728ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o ext2fs_mark_inode_bitmap(inode_loop_detect, 32828ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o p->ino); 32928ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o } else if (parent_count++ > 2048) { 33028ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o /* 33128ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o * If we've run into a path depth that's 33228ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o * greater than 2048, try again with the inode 33328ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o * loop bitmap turned on and start from the 33428ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o * top. 33528ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o */ 33628ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o loop_pass = 1; 33728ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o if (inode_loop_detect) 33828ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o ext2fs_clear_inode_bitmap(inode_loop_detect); 33928ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o else { 34028ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o pctx->errcode = ext2fs_allocate_inode_bitmap(fs, _("inode loop detection bitmap"), &inode_loop_detect); 34128ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o if (pctx->errcode) { 34228ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o pctx->num = 1; 34328ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o fix_problem(ctx, 34428ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o PR_3_ALLOCATE_IBITMAP_ERROR, pctx); 34528ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o ctx->flags |= E2F_FLAG_ABORT; 34628ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o return -1; 34728ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o } 34828ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o } 34928ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o p = dir; 3503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 35121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o } 3523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 3533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 3543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Make sure that .. and the parent directory are the same; 3553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * offer to fix it if not. 3563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 3573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (dir->parent != dir->dotdot) { 35821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o pctx->ino = dir->ino; 35921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o pctx->ino2 = dir->dotdot; 36021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o pctx->dir = dir->parent; 3611b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (fix_problem(ctx, PR_3_BAD_DOT_DOT, pctx)) 3621b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o fix_dotdot(ctx, dir, dir->parent); 3633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 36428ffafb09c6fd8a9ebe716c06b02143771a9b17fTheodore Ts'o return 0; 365b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o} 3663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 3673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/* 3683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * This routine gets the lost_and_found inode, making it a directory 3693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * if necessary 3703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 371850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'oext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix) 3723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 3731b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ext2_filsys fs = ctx->fs; 37486c627ec1136446409a0170d439e60c148e6eb48Theodore Ts'o ext2_ino_t ino; 3753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o blk_t blk; 3763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval; 3773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct ext2_inode inode; 3783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o char * block; 37953ef44c40a3e425d2c700d8fd77a6b655aa121feTheodore Ts'o static const char name[] = "lost+found"; 3801b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o struct problem_context pctx; 3814a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o struct dir_info *dirinfo; 3823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 383850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o if (ctx->lost_and_found) 384850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o return ctx->lost_and_found; 385850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o 3861b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o clear_problem_context(&pctx); 3871b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o 38821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name, 38921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o sizeof(name)-1, 0, &ino); 390850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o if (retval && !fix) 391850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o return 0; 3924a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o if (!retval) { 393850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, ino)) { 394850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o ctx->lost_and_found = ino; 3954a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o return ino; 396850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o } 397850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o 3984a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o /* Lost+found isn't a directory! */ 399850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o if (!fix) 400850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o return 0; 4014a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o pctx.ino = ino; 4024a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o if (!fix_problem(ctx, PR_3_LPF_NOTDIR, &pctx)) 4034a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o return 0; 4044a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o 405c54b3c3c99a5d3011f6f60934e90dae7f60b3b00Theodore Ts'o /* OK, unlink the old /lost+found file. */ 4064a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o pctx.errcode = ext2fs_unlink(fs, EXT2_ROOT_INO, name, ino, 0); 4074a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o if (pctx.errcode) { 4084a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o pctx.str = "ext2fs_unlink"; 4094a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); 4104a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o return 0; 4114a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o } 4124a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o dirinfo = e2fsck_get_dir_info(ctx, ino); 4134a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o if (dirinfo) 4144a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o dirinfo->parent = 0; 415b0700a1b6083f2f0c19c349f07ca80e70ec456beTheodore Ts'o e2fsck_adjust_inode_count(ctx, ino, -1); 4164a9f59366b3c5503bde40e9566dc996a0a40626fTheodore Ts'o } else if (retval != EXT2_ET_FILE_NOT_FOUND) { 4171b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o pctx.errcode = retval; 4181b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o fix_problem(ctx, PR_3_ERR_FIND_LPF, &pctx); 4191b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o } 4201b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (!fix_problem(ctx, PR_3_NO_LF_DIR, 0)) 4213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 4223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 4243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Read the inode and block bitmaps in; we'll be messing with 4253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * them. 4263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 427f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o e2fsck_read_bitmaps(ctx); 4283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 4303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * First, find a free block 4313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 4321b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o retval = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk); 4333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) { 4341b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o pctx.errcode = retval; 4351b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o fix_problem(ctx, PR_3_ERR_LPF_NEW_BLOCK, &pctx); 4363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 4373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 4381b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ext2fs_mark_block_bitmap(ctx->block_found_map, blk); 4390684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o ext2fs_block_alloc_stats(fs, blk, +1); 4403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 4423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Next find a free inode. 4433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 444b0700a1b6083f2f0c19c349f07ca80e70ec456beTheodore Ts'o retval = ext2fs_new_inode(fs, EXT2_ROOT_INO, 040700, 4451b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ctx->inode_used_map, &ino); 4463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) { 4471b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o pctx.errcode = retval; 4481b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o fix_problem(ctx, PR_3_ERR_LPF_NEW_INODE, &pctx); 4493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 4503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 4511b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino); 4521b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ext2fs_mark_inode_bitmap(ctx->inode_dir_map, ino); 4530684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o ext2fs_inode_alloc_stats2(fs, ino, +1, 1); 4543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 4563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Now let's create the actual data block for the inode 4573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 4583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = ext2fs_new_dir_block(fs, ino, EXT2_ROOT_INO, &block); 4593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) { 4601b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o pctx.errcode = retval; 4611b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o fix_problem(ctx, PR_3_ERR_LPF_NEW_DIR_BLOCK, &pctx); 4623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 4633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 4643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 46550e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o retval = ext2fs_write_dir_block(fs, blk, block); 466c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o ext2fs_free_mem(&block); 4673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) { 4681b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o pctx.errcode = retval; 4691b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o fix_problem(ctx, PR_3_ERR_LPF_WRITE_BLOCK, &pctx); 4703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 4713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 4723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 4743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Set up the inode structure 4753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 4763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o memset(&inode, 0, sizeof(inode)); 47764aecc4dd35b48f66f452f06c49587c838990d39Theodore Ts'o inode.i_mode = 040700; 4783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o inode.i_size = fs->blocksize; 4791f3ad14a5ad5df3ac4012d41ef5d76411cd8fff3Theodore Ts'o inode.i_atime = inode.i_ctime = inode.i_mtime = ctx->now; 4803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o inode.i_links_count = 2; 4813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o inode.i_blocks = fs->blocksize / 512; 4823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o inode.i_block[0] = blk; 4833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 4853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Next, write out the inode. 4863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 487030970ed750b6a169c32ffb8b19bce3150198629Theodore Ts'o pctx.errcode = ext2fs_write_new_inode(fs, ino, &inode); 4881b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (pctx.errcode) { 4891b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o pctx.str = "ext2fs_write_inode"; 4901b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); 4913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 4923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 4933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 4943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Finally, create the directory link 4953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 4966fdc7a325c8bff67fc3a0489d0858bc7c48dc1a3Theodore Ts'o pctx.errcode = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, EXT2_FT_DIR); 4971b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (pctx.errcode) { 4981b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o pctx.str = "ext2fs_link"; 4991b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); 5003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 5013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 5023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 5033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 5043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Miscellaneous bookkeeping that needs to be kept straight. 5053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 50608b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o e2fsck_add_dir_info(ctx, ino, EXT2_ROOT_INO); 507b0700a1b6083f2f0c19c349f07ca80e70ec456beTheodore Ts'o e2fsck_adjust_inode_count(ctx, EXT2_ROOT_INO, 1); 5081b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ext2fs_icount_store(ctx->inode_count, ino, 2); 5091b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ext2fs_icount_store(ctx->inode_link_info, ino, 2); 510850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o ctx->lost_and_found = ino; 5113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#if 0 512f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o printf("/lost+found created; inode #%lu\n", ino); 5133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#endif 5143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return ino; 5153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 5163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 5173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/* 5183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * This routine will connect a file to lost+found 5193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 52086c627ec1136446409a0170d439e60c148e6eb48Theodore Ts'oint e2fsck_reconnect_file(e2fsck_t ctx, ext2_ino_t ino) 5213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 5221b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ext2_filsys fs = ctx->fs; 5233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval; 5243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o char name[80]; 5251b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o struct problem_context pctx; 5266fdc7a325c8bff67fc3a0489d0858bc7c48dc1a3Theodore Ts'o struct ext2_inode inode; 5276fdc7a325c8bff67fc3a0489d0858bc7c48dc1a3Theodore Ts'o int file_type = 0; 5281b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o 5291b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o clear_problem_context(&pctx); 5306fdc7a325c8bff67fc3a0489d0858bc7c48dc1a3Theodore Ts'o pctx.ino = ino; 5311b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o 532850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o if (!ctx->bad_lost_and_found && !ctx->lost_and_found) { 533850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o if (e2fsck_get_lost_and_found(ctx, 1) == 0) 534850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o ctx->bad_lost_and_found++; 5351b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o } 536850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o if (ctx->bad_lost_and_found) { 5371b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o fix_problem(ctx, PR_3_NO_LPF, &pctx); 5383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 1; 5393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 5401b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o 54186c627ec1136446409a0170d439e60c148e6eb48Theodore Ts'o sprintf(name, "#%u", ino); 5426fdc7a325c8bff67fc3a0489d0858bc7c48dc1a3Theodore Ts'o if (ext2fs_read_inode(fs, ino, &inode) == 0) 5436fdc7a325c8bff67fc3a0489d0858bc7c48dc1a3Theodore Ts'o file_type = ext2_file_type(inode.i_mode); 544850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o retval = ext2fs_link(fs, ctx->lost_and_found, name, ino, file_type); 5453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval == EXT2_ET_DIR_NO_SPACE) { 5461b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (!fix_problem(ctx, PR_3_EXPAND_LF_DIR, &pctx)) 5473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 1; 548850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o retval = e2fsck_expand_directory(ctx, ctx->lost_and_found, 549850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o 1, 0); 5503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) { 5511b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o pctx.errcode = retval; 5521b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o fix_problem(ctx, PR_3_CANT_EXPAND_LPF, &pctx); 5533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 1; 5543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 555850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o retval = ext2fs_link(fs, ctx->lost_and_found, name, 556850d05e9aa405497e57c72090b9561af98b1b661Theodore Ts'o ino, file_type); 5573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 5583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) { 5591b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o pctx.errcode = retval; 5601b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o fix_problem(ctx, PR_3_CANT_RECONNECT, &pctx); 5613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 1; 5623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 563b0700a1b6083f2f0c19c349f07ca80e70ec456beTheodore Ts'o e2fsck_adjust_inode_count(ctx, ino, 1); 5643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 5653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 5663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 5673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 5683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/* 5693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Utility routine to adjust the inode counts on an inode. 5703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 571b0700a1b6083f2f0c19c349f07ca80e70ec456beTheodore Ts'oerrcode_t e2fsck_adjust_inode_count(e2fsck_t ctx, ext2_ino_t ino, int adj) 5723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 5731b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ext2_filsys fs = ctx->fs; 5743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval; 5753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct ext2_inode inode; 5763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 5773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (!ino) 5783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 5793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 5803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = ext2fs_read_inode(fs, ino, &inode); 5813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) 5823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return retval; 5833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 5843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#if 0 585f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o printf("Adjusting link count for inode %lu by %d (from %d)\n", ino, adj, 5863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o inode.i_links_count); 5873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#endif 5883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 58921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o if (adj == 1) { 5901b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ext2fs_icount_increment(ctx->inode_count, ino, 0); 591c1faf9cc3a2418c536eee472f054c9604ad3f213Theodore Ts'o if (inode.i_links_count == (__u16) ~0) 592c1faf9cc3a2418c536eee472f054c9604ad3f213Theodore Ts'o return 0; 5931b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ext2fs_icount_increment(ctx->inode_link_info, ino, 0); 594c1faf9cc3a2418c536eee472f054c9604ad3f213Theodore Ts'o inode.i_links_count++; 595c1faf9cc3a2418c536eee472f054c9604ad3f213Theodore Ts'o } else if (adj == -1) { 5961b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ext2fs_icount_decrement(ctx->inode_count, ino, 0); 597c1faf9cc3a2418c536eee472f054c9604ad3f213Theodore Ts'o if (inode.i_links_count == 0) 598c1faf9cc3a2418c536eee472f054c9604ad3f213Theodore Ts'o return 0; 5991b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ext2fs_icount_decrement(ctx->inode_link_info, ino, 0); 600c1faf9cc3a2418c536eee472f054c9604ad3f213Theodore Ts'o inode.i_links_count--; 60121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o } 60221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o 6033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = ext2fs_write_inode(fs, ino, &inode); 6043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) 6053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return retval; 6063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 6073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 6083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 6093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 6103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/* 6113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Fix parent --- this routine fixes up the parent of a directory. 6123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 6133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostruct fix_dotdot_struct { 6143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o ext2_filsys fs; 61586c627ec1136446409a0170d439e60c148e6eb48Theodore Ts'o ext2_ino_t parent; 6163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int done; 6171b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o e2fsck_t ctx; 6183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}; 6193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 6203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic int fix_dotdot_proc(struct ext2_dir_entry *dirent, 621544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o int offset EXT2FS_ATTR((unused)), 622544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o int blocksize EXT2FS_ATTR((unused)), 623544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o char *buf EXT2FS_ATTR((unused)), 62454dc7ca2869897ae8cb81a9ab9880ebff11680bcTheodore Ts'o void *priv_data) 6253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 62654dc7ca2869897ae8cb81a9ab9880ebff11680bcTheodore Ts'o struct fix_dotdot_struct *fp = (struct fix_dotdot_struct *) priv_data; 6273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval; 6281b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o struct problem_context pctx; 6293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 630b6f7983197fe217cf20862c93d72620be3b0fcecTheodore Ts'o if ((dirent->name_len & 0xFF) != 2) 6313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 6323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (strncmp(dirent->name, "..", 2)) 6333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 6343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 6351b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o clear_problem_context(&pctx); 6361b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o 637b0700a1b6083f2f0c19c349f07ca80e70ec456beTheodore Ts'o retval = e2fsck_adjust_inode_count(fp->ctx, dirent->inode, -1); 6381b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (retval) { 6391b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o pctx.errcode = retval; 6401b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx); 6411b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o } 642b0700a1b6083f2f0c19c349f07ca80e70ec456beTheodore Ts'o retval = e2fsck_adjust_inode_count(fp->ctx, fp->parent, 1); 6431b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (retval) { 6441b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o pctx.errcode = retval; 6451b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx); 6461b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o } 6473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o dirent->inode = fp->parent; 64856c8c592ac48c0fc9772153bb7bdf621b1de0ab9Theodore Ts'o if (fp->ctx->fs->super->s_feature_incompat & 64956c8c592ac48c0fc9772153bb7bdf621b1de0ab9Theodore Ts'o EXT2_FEATURE_INCOMPAT_FILETYPE) 65056c8c592ac48c0fc9772153bb7bdf621b1de0ab9Theodore Ts'o dirent->name_len = (dirent->name_len & 0xFF) | 65156c8c592ac48c0fc9772153bb7bdf621b1de0ab9Theodore Ts'o (EXT2_FT_DIR << 8); 65256c8c592ac48c0fc9772153bb7bdf621b1de0ab9Theodore Ts'o else 65356c8c592ac48c0fc9772153bb7bdf621b1de0ab9Theodore Ts'o dirent->name_len = dirent->name_len & 0xFF; 6543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 6553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o fp->done++; 6563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return DIRENT_ABORT | DIRENT_CHANGED; 6573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 6583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 65986c627ec1136446409a0170d439e60c148e6eb48Theodore Ts'ostatic void fix_dotdot(e2fsck_t ctx, struct dir_info *dir, ext2_ino_t parent) 6603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 6611b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ext2_filsys fs = ctx->fs; 6623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval; 6633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct fix_dotdot_struct fp; 6641b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o struct problem_context pctx; 6653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 6663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o fp.fs = fs; 6673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o fp.parent = parent; 6683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o fp.done = 0; 6691b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o fp.ctx = ctx; 6703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 6713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#if 0 672f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o printf("Fixing '..' of inode %lu to be %lu...\n", dir->ino, parent); 6733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#endif 6743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 6753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = ext2fs_dir_iterate(fs, dir->ino, DIRENT_FLAG_INCLUDE_EMPTY, 6763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 0, fix_dotdot_proc, &fp); 6773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval || !fp.done) { 6781b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o clear_problem_context(&pctx); 6791b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o pctx.ino = dir->ino; 6801b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o pctx.errcode = retval; 6811b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o fix_problem(ctx, retval ? PR_3_FIX_PARENT_ERR : 6821b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o PR_3_FIX_PARENT_NOFIND, &pctx); 6833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o ext2fs_unmark_valid(fs); 6843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 6853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o dir->dotdot = parent; 6863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 6873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return; 6883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 6893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 6903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/* 6913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * These routines are responsible for expanding a /lost+found if it is 6923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * too small. 6933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 6943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 6953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostruct expand_dir_struct { 696b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o int num; 697b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o int guaranteed_size; 698c1faf9cc3a2418c536eee472f054c9604ad3f213Theodore Ts'o int newblocks; 699b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o int last_block; 700c1faf9cc3a2418c536eee472f054c9604ad3f213Theodore Ts'o errcode_t err; 701c1faf9cc3a2418c536eee472f054c9604ad3f213Theodore Ts'o e2fsck_t ctx; 7023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}; 7033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 7043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic int expand_dir_proc(ext2_filsys fs, 7053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o blk_t *blocknr, 706133a56dc9da52054bc27b4c1a23f03e3405003dbTheodore Ts'o e2_blkcnt_t blockcnt, 707544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o blk_t ref_block EXT2FS_ATTR((unused)), 708544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o int ref_offset EXT2FS_ATTR((unused)), 70954dc7ca2869897ae8cb81a9ab9880ebff11680bcTheodore Ts'o void *priv_data) 7103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 71154dc7ca2869897ae8cb81a9ab9880ebff11680bcTheodore Ts'o struct expand_dir_struct *es = (struct expand_dir_struct *) priv_data; 7123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o blk_t new_blk; 7133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o static blk_t last_blk = 0; 7143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o char *block; 7153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval; 7161b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o e2fsck_t ctx; 7171b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o 7181b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ctx = es->ctx; 7193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 720b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o if (es->guaranteed_size && blockcnt >= es->guaranteed_size) 721b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o return BLOCK_ABORT; 722b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o 723b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o if (blockcnt > 0) 724b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o es->last_block = blockcnt; 7253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (*blocknr) { 7263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o last_blk = *blocknr; 7273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 7283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 7291b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o retval = ext2fs_new_block(fs, last_blk, ctx->block_found_map, 7301b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o &new_blk); 7313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) { 7323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o es->err = retval; 7333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return BLOCK_ABORT; 7343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 7353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (blockcnt > 0) { 7363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = ext2fs_new_dir_block(fs, 0, 0, &block); 7373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) { 7383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o es->err = retval; 7393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return BLOCK_ABORT; 7403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 741b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o es->num--; 742b8647faa3b0a7dfbb2456a7b37321ee4bbda651cTheodore Ts'o retval = ext2fs_write_dir_block(fs, new_blk, block); 7433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } else { 744c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o retval = ext2fs_get_mem(fs->blocksize, &block); 74508b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o if (retval) { 74608b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o es->err = retval; 7473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return BLOCK_ABORT; 7483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 7493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o memset(block, 0, fs->blocksize); 750b8647faa3b0a7dfbb2456a7b37321ee4bbda651cTheodore Ts'o retval = io_channel_write_blk(fs->io, new_blk, 1, block); 7513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 7523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) { 7533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o es->err = retval; 7543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return BLOCK_ABORT; 7553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 756c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o ext2fs_free_mem(&block); 7573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *blocknr = new_blk; 7581b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ext2fs_mark_block_bitmap(ctx->block_found_map, new_blk); 759b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o ext2fs_block_alloc_stats(fs, new_blk, +1); 760c1faf9cc3a2418c536eee472f054c9604ad3f213Theodore Ts'o es->newblocks++; 761c1faf9cc3a2418c536eee472f054c9604ad3f213Theodore Ts'o 762b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o if (es->num == 0) 7633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return (BLOCK_CHANGED | BLOCK_ABORT); 7643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o else 7653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return BLOCK_CHANGED; 7663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 7673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 768b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'oerrcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir, 769b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o int num, int guaranteed_size) 7703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 7711b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ext2_filsys fs = ctx->fs; 7723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval; 7733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct expand_dir_struct es; 7743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct ext2_inode inode; 7753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 7763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (!(fs->flags & EXT2_FLAG_RW)) 7773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return EXT2_ET_RO_FILSYS; 7783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 779b8647faa3b0a7dfbb2456a7b37321ee4bbda651cTheodore Ts'o /* 780b8647faa3b0a7dfbb2456a7b37321ee4bbda651cTheodore Ts'o * Read the inode and block bitmaps in; we'll be messing with 781b8647faa3b0a7dfbb2456a7b37321ee4bbda651cTheodore Ts'o * them. 782b8647faa3b0a7dfbb2456a7b37321ee4bbda651cTheodore Ts'o */ 783b8647faa3b0a7dfbb2456a7b37321ee4bbda651cTheodore Ts'o e2fsck_read_bitmaps(ctx); 784c1faf9cc3a2418c536eee472f054c9604ad3f213Theodore Ts'o 7853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = ext2fs_check_directory(fs, dir); 7863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) 7873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return retval; 7883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 789b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o es.num = num; 790b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o es.guaranteed_size = guaranteed_size; 791b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o es.last_block = 0; 7923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o es.err = 0; 793c1faf9cc3a2418c536eee472f054c9604ad3f213Theodore Ts'o es.newblocks = 0; 7941b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o es.ctx = ctx; 7953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 796133a56dc9da52054bc27b4c1a23f03e3405003dbTheodore Ts'o retval = ext2fs_block_iterate2(fs, dir, BLOCK_FLAG_APPEND, 797133a56dc9da52054bc27b4c1a23f03e3405003dbTheodore Ts'o 0, expand_dir_proc, &es); 7983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 7993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (es.err) 8003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return es.err; 8013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 8023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 8033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Update the size and block count fields in the inode. 8043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 8053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = ext2fs_read_inode(fs, dir, &inode); 8063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) 8073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return retval; 8083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 809b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o inode.i_size = (es.last_block + 1) * fs->blocksize; 810c1faf9cc3a2418c536eee472f054c9604ad3f213Theodore Ts'o inode.i_blocks += (fs->blocksize / 512) * es.newblocks; 8113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 81208b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o e2fsck_write_inode(ctx, dir, &inode, "expand_directory"); 8133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 8143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 8153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 816b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o 817