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