pass3.c revision e9a8c0c2d46a46c01c6a6daa5db14df72a7ad6aa
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * pass3.c -- pass #3 of e2fsck: Check for directory connectivity 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999 Theodore Ts'o. 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * %Begin-Header% 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * This file may be redistributed under the terms of the GNU Public 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * License. 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * %End-Header% 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Pass #3 assures that all directories are connected to the 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * filesystem tree, using the following algorithm: 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * First, the root directory is checked to make sure it exists; if 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * not, e2fsck will offer to create a new one. It is then marked as 162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * "done". 177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch * 187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch * Then, pass3 interates over all directory inodes; for each directory 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * it attempts to trace up the filesystem tree, using dirinfo.parent 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * until it reaches a directory which has been marked "done". If it 21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * can not do so, then the directory must be disconnected, and e2fsck 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * will offer to reconnect it to /lost+found. While it is chasing 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * parent pointers up the filesystem tree, if pass3 sees a directory 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * twice, then it has detected a filesystem loop, and it will again 2558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) * offer to reconnect the directory to /lost+found in to break the 26424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) * filesystem loop. 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Pass 3 also contains the subroutine, e2fsck_reconnect_file() to 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * reconnect inodes to /lost+found; this subroutine is also used by 30868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * pass 4. e2fsck_reconnect_file() calls get_lost_and_found(), which 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * is responsible for creating /lost+found if it does not exist. 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Pass 3 frees the following data structures: 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * - The dirinfo directory information cache. 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "config.h" 38eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#ifdef HAVE_ERRNO_H 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <errno.h> 40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif 41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "e2fsck.h" 43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "problem.h" 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void check_root(e2fsck_t ctx); 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int check_directory(e2fsck_t ctx, ext2_ino_t ino, 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct problem_context *pctx); 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void fix_dotdot(e2fsck_t ctx, ext2_ino_t ino, ext2_ino_t parent); 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static ext2fs_inode_bitmap inode_loop_detect = 0; 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static ext2fs_inode_bitmap inode_done_map = 0; 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void e2fsck_pass3(e2fsck_t ctx) 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles){ 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ext2_filsys fs = ctx->fs; 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) struct dir_info_iter *iter = NULL; 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#ifdef RESOURCE_TRACK 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) struct resource_track rtrack; 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) struct problem_context pctx; 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) struct dir_info *dir; 62ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch unsigned long maxdirs, count; 63ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 64ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch init_resource_track(&rtrack, ctx->fs->io); 65ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch clear_problem_context(&pctx); 66ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 67ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#ifdef MTRACE 68ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch mtrace_print("Pass 3"); 69ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#endif 70ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 71ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch if (!(ctx->options & E2F_OPT_PREEN)) 72ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch fix_problem(ctx, PR_3_PASS_HEADER, &pctx); 73ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 74ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch /* 75ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch * Allocate some bitmaps to do loop detection. 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pctx.errcode = e2fsck_allocate_inode_bitmap(fs, _("inode done bitmap"), 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) EXT2FS_BMAP64_AUTODIR, 79ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch "inode_done_map", &inode_done_map); 80ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch if (pctx.errcode) { 81ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch pctx.num = 2; 82ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch fix_problem(ctx, PR_3_ALLOCATE_IBITMAP_ERROR, &pctx); 83ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch ctx->flags |= E2F_FLAG_ABORT; 84ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch goto abort_exit; 85ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch } 86ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch print_resource_track(ctx, _("Peak memory"), &ctx->global_rtrack, NULL); 87ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) check_root(ctx); 892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (ctx->flags & E2F_FLAG_SIGNAL_MASK) 90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) goto abort_exit; 91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ext2fs_mark_inode_bitmap2(inode_done_map, EXT2_ROOT_INO); 93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) maxdirs = e2fsck_get_num_dirinfo(ctx); 9590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) count = 1; 9690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (ctx->progress) 98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if ((ctx->progress)(ctx, 3, 0, maxdirs)) 99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) goto abort_exit; 100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) iter = e2fsck_dir_info_iter_begin(ctx); 102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) while ((dir = e2fsck_dir_info_iter(ctx, iter)) != 0) { 103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (ctx->flags & E2F_FLAG_SIGNAL_MASK) 104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) goto abort_exit; 105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (ctx->progress && (ctx->progress)(ctx, 3, count++, maxdirs)) 106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) goto abort_exit; 107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (ext2fs_test_inode_bitmap2(ctx->inode_dir_map, dir->ino)) 108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (check_directory(ctx, dir->ino, &pctx)) 109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) goto abort_exit; 110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Force the creation of /lost+found if not present 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((ctx->options & E2F_OPT_READONLY) == 0) 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) e2fsck_get_lost_and_found(ctx, 1); 117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) /* 119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * If there are any directories that need to be indexed or 120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * optimized, do it here. 121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */ 122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) e2fsck_rehash_directories(ctx); 123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)abort_exit: 125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (iter) 126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) e2fsck_dir_info_iter_end(ctx, iter); 127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) e2fsck_free_dir_info(ctx); 128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (inode_loop_detect) { 129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ext2fs_free_inode_bitmap(inode_loop_detect); 130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) inode_loop_detect = 0; 1317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch } 1327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if (inode_done_map) { 1337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch ext2fs_free_inode_bitmap(inode_done_map); 1347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch inode_done_map = 0; 1357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch } 1367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 137868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) print_resource_track(ctx, _("Pass 3"), &rtrack, ctx->fs->io); 138868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 139868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 140868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)/* 141868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * This makes sure the root inode is present; if not, we ask if the 142868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * user wants us to create it. Not creating it is a fatal error. 143868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) */ 144868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)static void check_root(e2fsck_t ctx) 145868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles){ 146868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ext2_filsys fs = ctx->fs; 147868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) blk64_t blk; 148868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) struct ext2_inode inode; 149868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) char * block; 1507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch struct problem_context pctx; 1517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 1527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch clear_problem_context(&pctx); 1537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 1547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if (ext2fs_test_inode_bitmap2(ctx->inode_used_map, EXT2_ROOT_INO)) { 1557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch /* 1567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch * If the root inode is not a directory, die here. The 1577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch * user must have answered 'no' in pass1 when we 1587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch * offered to clear it. 1597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch */ 1607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if (!(ext2fs_test_inode_bitmap2(ctx->inode_dir_map, 1617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch EXT2_ROOT_INO))) { 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fix_problem(ctx, PR_3_ROOT_NOT_DIR_ABORT, &pctx); 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctx->flags |= E2F_FLAG_ABORT; 1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1687d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (!fix_problem(ctx, PR_3_NO_ROOT_INODE, &pctx)) { 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fix_problem(ctx, PR_3_NO_ROOT_INODE_ABORT, &pctx); 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctx->flags |= E2F_FLAG_ABORT; 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 174c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) e2fsck_read_bitmaps(ctx); 175c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) /* 1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * First, find a free block 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1797d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) pctx.errcode = ext2fs_new_block2(fs, 0, ctx->block_found_map, &blk); 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pctx.errcode) { 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pctx.str = "ext2fs_new_block"; 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx); 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctx->flags |= E2F_FLAG_ABORT; 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ext2fs_mark_block_bitmap2(ctx->block_found_map, blk); 1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ext2fs_mark_block_bitmap2(fs->block_map, blk); 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ext2fs_mark_bb_dirty(fs); 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) /* 19158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) * Now let's create the actual data block for the inode 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pctx.errcode = ext2fs_new_dir_block(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, 1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) &block); 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pctx.errcode) { 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pctx.str = "ext2fs_new_dir_block"; 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx); 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctx->flags |= E2F_FLAG_ABORT; 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pctx.errcode = ext2fs_write_dir_block3(fs, blk, block, 0); 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pctx.errcode) { 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pctx.str = "ext2fs_write_dir_block3"; 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx); 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctx->flags |= E2F_FLAG_ABORT; 207ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch return; 208ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch } 209ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch ext2fs_free_mem(&block); 210ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 211558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch /* 212558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch * Set up the inode structure 213ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch */ 2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) memset(&inode, 0, sizeof(inode)); 2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) inode.i_mode = 040755; 2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) inode.i_size = fs->blocksize; 2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) inode.i_atime = inode.i_ctime = inode.i_mtime = ctx->now; 2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) inode.i_links_count = 2; 2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ext2fs_iblk_set(fs, &inode, 1); 2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) inode.i_block[0] = blk; 2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) /* 2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Write out the inode. 2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pctx.errcode = ext2fs_write_new_inode(fs, EXT2_ROOT_INO, &inode); 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pctx.errcode) { 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pctx.str = "ext2fs_write_inode"; 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx); 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctx->flags |= E2F_FLAG_ABORT; 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Miscellaneous bookkeeping... 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) e2fsck_add_dir_info(ctx, EXT2_ROOT_INO, EXT2_ROOT_INO); 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ext2fs_icount_store(ctx->inode_count, EXT2_ROOT_INO, 2); 238c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ext2fs_icount_store(ctx->inode_link_info, EXT2_ROOT_INO, 2); 239c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 240c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ext2fs_mark_inode_bitmap2(ctx->inode_used_map, EXT2_ROOT_INO); 241c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ext2fs_mark_inode_bitmap2(ctx->inode_dir_map, EXT2_ROOT_INO); 242c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ext2fs_mark_inode_bitmap2(fs->inode_map, EXT2_ROOT_INO); 243c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ext2fs_mark_ib_dirty(fs); 244c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 245c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 246c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)/* 2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * This subroutine is responsible for making sure that a particular 2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * directory is connected to the root; if it isn't we trace it up as 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * far as we can go, and then offer to connect the resulting parent to 2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * the lost+found. We have to do loop detection; if we ever discover 2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * a loop, we treat that as a disconnected directory and offer to 2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * reparent it to lost+found. 2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * 2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * However, loop detection is expensive, because for very large 2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * filesystems, the inode_loop_detect bitmap is huge, and clearing it 256c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * is non-trivial. Loops in filesystems are also a rare error case, 257c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * and we shouldn't optimize for error cases. So we try two passes of 258c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * the algorithm. The first time, we ignore loop detection and merely 259c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * increment a counter; if the counter exceeds some extreme threshold, 260c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * then we try again with the loop detection bitmap enabled. 261c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */ 2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static int check_directory(e2fsck_t ctx, ext2_ino_t dir, 263c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) struct problem_context *pctx) 264c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles){ 265c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ext2_filsys fs = ctx->fs; 266c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ext2_ino_t ino = dir, parent; 2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int loop_pass = 0, parent_count = 0; 2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) while (1) { 2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) /* 2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Mark this inode as being "done"; by the time we 2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * return from this function, the inode we either be 2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * verified as being connected to the directory tree, 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * or we will have offered to reconnect this to 2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * lost+found. 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * If it was marked done already, then we've reached a 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * parent we've already checked. 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ext2fs_mark_inode_bitmap2(inode_done_map, ino)) 2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (e2fsck_dir_info_get_parent(ctx, ino, &parent)) { 2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) fix_problem(ctx, PR_3_NO_DIRINFO, pctx); 2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return 0; 2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) /* 2897dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch * If this directory doesn't have a parent, or we've 2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * seen the parent once already, then offer to 2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * reparent it to lost+found 2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!parent || 2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) (loop_pass && 2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) (ext2fs_test_inode_bitmap2(inode_loop_detect, 2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) parent)))) { 2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pctx->ino = ino; 2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (fix_problem(ctx, PR_3_UNCONNECTED_DIR, pctx)) { 299c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (e2fsck_reconnect_file(ctx, pctx->ino)) 3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ext2fs_unmark_valid(fs); 3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) else { 3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) fix_dotdot(ctx, pctx->ino, 303b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) ctx->lost_and_found); 304b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) parent = ctx->lost_and_found; 305b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) } 3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 307b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) break; 3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ino = parent; 3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (loop_pass) { 3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ext2fs_mark_inode_bitmap2(inode_loop_detect, ino); 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (parent_count++ > 2048) { 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* 3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * If we've run into a path depth that's 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * greater than 2048, try again with the inode 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * loop bitmap turned on and start from the 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * top. 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) loop_pass = 1; 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (inode_loop_detect) 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ext2fs_clear_inode_bitmap(inode_loop_detect); 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else { 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pctx->errcode = e2fsck_allocate_inode_bitmap(fs, _("inode loop detection bitmap"), EXT2FS_BMAP64_AUTODIR, "inode_loop_detect", &inode_loop_detect); 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pctx->errcode) { 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pctx->num = 1; 326868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) fix_problem(ctx, 327868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) PR_3_ALLOCATE_IBITMAP_ERROR, pctx); 328868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ctx->flags |= E2F_FLAG_ABORT; 329868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return -1; 330868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 331868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 332868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ino = dir; 333868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 334868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Make sure that .. and the parent directory are the same; 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * offer to fix it if not. 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pctx->ino = dir; 341868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (e2fsck_dir_info_get_dotdot(ctx, dir, &pctx->ino2) || 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) e2fsck_dir_info_get_parent(ctx, dir, &pctx->dir)) { 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fix_problem(ctx, PR_3_NO_DIRINFO, pctx); 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 346868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (pctx->ino2 != pctx->dir) { 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (fix_problem(ctx, PR_3_BAD_DOT_DOT, pctx)) 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fix_dotdot(ctx, dir, pctx->dir); 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3527d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 3537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)/* 3547d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) * This routine gets the lost_and_found inode, making it a directory 3557d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) * if necessary 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix) 358868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles){ 359868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ext2_filsys fs = ctx->fs; 360868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ext2_ino_t ino; 361868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) blk64_t blk; 362868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) errcode_t retval; 363868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) struct ext2_inode inode; 364868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) char * block; 3657d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) static const char name[] = "lost+found"; 3667d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) struct problem_context pctx; 3677d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 3687d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (ctx->lost_and_found) 3697d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return ctx->lost_and_found; 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) clear_problem_context(&pctx); 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name, 3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) sizeof(name)-1, 0, &ino); 375868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (retval && !fix) 376868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return 0; 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!retval) { 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ext2fs_test_inode_bitmap2(ctx->inode_dir_map, ino)) { 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctx->lost_and_found = ino; 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ino; 3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) /* Lost+found isn't a directory! */ 3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!fix) 3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return 0; 3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pctx.ino = ino; 3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!fix_problem(ctx, PR_3_LPF_NOTDIR, &pctx)) 388c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return 0; 3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) /* OK, unlink the old /lost+found file. */ 3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pctx.errcode = ext2fs_unlink(fs, EXT2_ROOT_INO, name, ino, 0); 3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (pctx.errcode) { 3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pctx.str = "ext2fs_unlink"; 3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); 3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return 0; 3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) (void) e2fsck_dir_info_set_parent(ctx, ino, 0); 3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) e2fsck_adjust_inode_count(ctx, ino, -1); 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (retval != EXT2_ET_FILE_NOT_FOUND) { 4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pctx.errcode = retval; 4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) fix_problem(ctx, PR_3_ERR_FIND_LPF, &pctx); 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!fix_problem(ctx, PR_3_NO_LF_DIR, 0)) 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Read the inode and block bitmaps in; we'll be messing with 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * them. 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) e2fsck_read_bitmaps(ctx); 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch /* 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * First, find a free block 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) retval = ext2fs_new_block2(fs, 0, ctx->block_found_map, &blk); 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (retval) { 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pctx.errcode = retval; 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fix_problem(ctx, PR_3_ERR_LPF_NEW_BLOCK, &pctx); 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ext2fs_mark_block_bitmap2(ctx->block_found_map, blk); 422868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ext2fs_block_alloc_stats2(fs, blk, +1); 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* 425c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * Next find a free inode. 426c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */ 427c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) retval = ext2fs_new_inode(fs, EXT2_ROOT_INO, 040700, 428c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ctx->inode_used_map, &ino); 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (retval) { 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pctx.errcode = retval; 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fix_problem(ctx, PR_3_ERR_LPF_NEW_INODE, &pctx); 4327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch return 0; 4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino); 4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ext2fs_mark_inode_bitmap2(ctx->inode_dir_map, ino); 4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ext2fs_inode_alloc_stats2(fs, ino, +1, 1); 4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* 43958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) * Now let's create the actual data block for the inode 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) retval = ext2fs_new_dir_block(fs, ino, EXT2_ROOT_INO, &block); 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (retval) { 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pctx.errcode = retval; 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fix_problem(ctx, PR_3_ERR_LPF_NEW_DIR_BLOCK, &pctx); 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) retval = ext2fs_write_dir_block3(fs, blk, block, 0); 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ext2fs_free_mem(&block); 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (retval) { 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pctx.errcode = retval; 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fix_problem(ctx, PR_3_ERR_LPF_WRITE_BLOCK, &pctx); 4537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch return 0; 4547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch } 4557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 4567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch /* 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Set up the inode structure 4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) memset(&inode, 0, sizeof(inode)); 4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) inode.i_mode = 040700; 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inode.i_size = fs->blocksize; 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inode.i_atime = inode.i_ctime = inode.i_mtime = ctx->now; 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inode.i_links_count = 2; 46458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) ext2fs_iblk_set(fs, &inode, 1); 4657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch inode.i_block[0] = blk; 4667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 4677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch /* 4687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch * Next, write out the inode. 4692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 4707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch pctx.errcode = ext2fs_write_new_inode(fs, ino, &inode); 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pctx.errcode) { 4727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch pctx.str = "ext2fs_write_inode"; 4737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); 4742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return 0; 4752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* 4777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch * Finally, create the directory link 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 4797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch pctx.errcode = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, EXT2_FT_DIR); 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pctx.errcode) { 4817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch pctx.str = "ext2fs_link"; 4827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); 4837dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch return 0; 4847dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch } 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Miscellaneous bookkeeping that needs to be kept straight. 4887dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch */ 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) e2fsck_add_dir_info(ctx, ino, EXT2_ROOT_INO); 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) e2fsck_adjust_inode_count(ctx, EXT2_ROOT_INO, 1); 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ext2fs_icount_store(ctx->inode_count, ino, 2); 4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ext2fs_icount_store(ctx->inode_link_info, ino, 2); 4932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ctx->lost_and_found = ino; 4942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) quota_data_add(ctx->qctx, &inode, ino, fs->blocksize); 4952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) quota_data_inodes(ctx->qctx, &inode, ino, +1); 4962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if 0 4972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) printf("/lost+found created; inode #%lu\n", ino); 4982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif 4992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return ino; 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 501 502/* 503 * This routine will connect a file to lost+found 504 */ 505int e2fsck_reconnect_file(e2fsck_t ctx, ext2_ino_t ino) 506{ 507 ext2_filsys fs = ctx->fs; 508 errcode_t retval; 509 char name[80]; 510 struct problem_context pctx; 511 struct ext2_inode inode; 512 int file_type = 0; 513 514 clear_problem_context(&pctx); 515 pctx.ino = ino; 516 517 if (!ctx->bad_lost_and_found && !ctx->lost_and_found) { 518 if (e2fsck_get_lost_and_found(ctx, 1) == 0) 519 ctx->bad_lost_and_found++; 520 } 521 if (ctx->bad_lost_and_found) { 522 fix_problem(ctx, PR_3_NO_LPF, &pctx); 523 return 1; 524 } 525 526 sprintf(name, "#%u", ino); 527 if (ext2fs_read_inode(fs, ino, &inode) == 0) 528 file_type = ext2_file_type(inode.i_mode); 529 retval = ext2fs_link(fs, ctx->lost_and_found, name, ino, file_type); 530 if (retval == EXT2_ET_DIR_NO_SPACE) { 531 if (!fix_problem(ctx, PR_3_EXPAND_LF_DIR, &pctx)) 532 return 1; 533 retval = e2fsck_expand_directory(ctx, ctx->lost_and_found, 534 1, 0); 535 if (retval) { 536 pctx.errcode = retval; 537 fix_problem(ctx, PR_3_CANT_EXPAND_LPF, &pctx); 538 return 1; 539 } 540 retval = ext2fs_link(fs, ctx->lost_and_found, name, 541 ino, file_type); 542 } 543 if (retval) { 544 pctx.errcode = retval; 545 fix_problem(ctx, PR_3_CANT_RECONNECT, &pctx); 546 return 1; 547 } 548 e2fsck_adjust_inode_count(ctx, ino, 1); 549 550 return 0; 551} 552 553/* 554 * Utility routine to adjust the inode counts on an inode. 555 */ 556errcode_t e2fsck_adjust_inode_count(e2fsck_t ctx, ext2_ino_t ino, int adj) 557{ 558 ext2_filsys fs = ctx->fs; 559 errcode_t retval; 560 struct ext2_inode inode; 561 562 if (!ino) 563 return 0; 564 565 retval = ext2fs_read_inode(fs, ino, &inode); 566 if (retval) 567 return retval; 568 569#if 0 570 printf("Adjusting link count for inode %lu by %d (from %d)\n", ino, adj, 571 inode.i_links_count); 572#endif 573 574 if (adj == 1) { 575 ext2fs_icount_increment(ctx->inode_count, ino, 0); 576 if (inode.i_links_count == (__u16) ~0) 577 return 0; 578 ext2fs_icount_increment(ctx->inode_link_info, ino, 0); 579 inode.i_links_count++; 580 } else if (adj == -1) { 581 ext2fs_icount_decrement(ctx->inode_count, ino, 0); 582 if (inode.i_links_count == 0) 583 return 0; 584 ext2fs_icount_decrement(ctx->inode_link_info, ino, 0); 585 inode.i_links_count--; 586 } 587 588 retval = ext2fs_write_inode(fs, ino, &inode); 589 if (retval) 590 return retval; 591 592 return 0; 593} 594 595/* 596 * Fix parent --- this routine fixes up the parent of a directory. 597 */ 598struct fix_dotdot_struct { 599 ext2_filsys fs; 600 ext2_ino_t parent; 601 int done; 602 e2fsck_t ctx; 603}; 604 605static int fix_dotdot_proc(struct ext2_dir_entry *dirent, 606 int offset EXT2FS_ATTR((unused)), 607 int blocksize EXT2FS_ATTR((unused)), 608 char *buf EXT2FS_ATTR((unused)), 609 void *priv_data) 610{ 611 struct fix_dotdot_struct *fp = (struct fix_dotdot_struct *) priv_data; 612 errcode_t retval; 613 struct problem_context pctx; 614 615 if ((dirent->name_len & 0xFF) != 2) 616 return 0; 617 if (strncmp(dirent->name, "..", 2)) 618 return 0; 619 620 clear_problem_context(&pctx); 621 622 retval = e2fsck_adjust_inode_count(fp->ctx, dirent->inode, -1); 623 if (retval) { 624 pctx.errcode = retval; 625 fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx); 626 } 627 retval = e2fsck_adjust_inode_count(fp->ctx, fp->parent, 1); 628 if (retval) { 629 pctx.errcode = retval; 630 fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx); 631 } 632 dirent->inode = fp->parent; 633 if (fp->ctx->fs->super->s_feature_incompat & 634 EXT2_FEATURE_INCOMPAT_FILETYPE) 635 dirent->name_len = (dirent->name_len & 0xFF) | 636 (EXT2_FT_DIR << 8); 637 else 638 dirent->name_len = dirent->name_len & 0xFF; 639 640 fp->done++; 641 return DIRENT_ABORT | DIRENT_CHANGED; 642} 643 644static void fix_dotdot(e2fsck_t ctx, ext2_ino_t ino, ext2_ino_t parent) 645{ 646 ext2_filsys fs = ctx->fs; 647 errcode_t retval; 648 struct fix_dotdot_struct fp; 649 struct problem_context pctx; 650 651 fp.fs = fs; 652 fp.parent = parent; 653 fp.done = 0; 654 fp.ctx = ctx; 655 656#if 0 657 printf("Fixing '..' of inode %lu to be %lu...\n", ino, parent); 658#endif 659 660 clear_problem_context(&pctx); 661 pctx.ino = ino; 662 retval = ext2fs_dir_iterate(fs, ino, DIRENT_FLAG_INCLUDE_EMPTY, 663 0, fix_dotdot_proc, &fp); 664 if (retval || !fp.done) { 665 pctx.errcode = retval; 666 fix_problem(ctx, retval ? PR_3_FIX_PARENT_ERR : 667 PR_3_FIX_PARENT_NOFIND, &pctx); 668 ext2fs_unmark_valid(fs); 669 } 670 (void) e2fsck_dir_info_set_dotdot(ctx, ino, parent); 671 if (e2fsck_dir_info_set_parent(ctx, ino, ctx->lost_and_found)) 672 fix_problem(ctx, PR_3_NO_DIRINFO, &pctx); 673 674 return; 675} 676 677/* 678 * These routines are responsible for expanding a /lost+found if it is 679 * too small. 680 */ 681 682struct expand_dir_struct { 683 blk64_t num; 684 e2_blkcnt_t guaranteed_size; 685 blk64_t newblocks; 686 blk64_t last_block; 687 errcode_t err; 688 e2fsck_t ctx; 689}; 690 691static int expand_dir_proc(ext2_filsys fs, 692 blk64_t *blocknr, 693 e2_blkcnt_t blockcnt, 694 blk64_t ref_block EXT2FS_ATTR((unused)), 695 int ref_offset EXT2FS_ATTR((unused)), 696 void *priv_data) 697{ 698 struct expand_dir_struct *es = (struct expand_dir_struct *) priv_data; 699 blk64_t new_blk; 700 static blk64_t last_blk = 0; 701 char *block; 702 errcode_t retval; 703 e2fsck_t ctx; 704 705 ctx = es->ctx; 706 707 if (es->guaranteed_size && blockcnt >= es->guaranteed_size) 708 return BLOCK_ABORT; 709 710 if (blockcnt > 0) 711 es->last_block = blockcnt; 712 if (*blocknr) { 713 last_blk = *blocknr; 714 return 0; 715 } 716 717 if (blockcnt && 718 (EXT2FS_B2C(fs, last_blk) == EXT2FS_B2C(fs, last_blk + 1))) 719 new_blk = last_blk + 1; 720 else { 721 last_blk &= ~EXT2FS_CLUSTER_MASK(fs); 722 retval = ext2fs_new_block2(fs, last_blk, ctx->block_found_map, 723 &new_blk); 724 if (retval) { 725 es->err = retval; 726 return BLOCK_ABORT; 727 } 728 es->newblocks++; 729 ext2fs_block_alloc_stats2(fs, new_blk, +1); 730 } 731 last_blk = new_blk; 732 733 if (blockcnt > 0) { 734 retval = ext2fs_new_dir_block(fs, 0, 0, &block); 735 if (retval) { 736 es->err = retval; 737 return BLOCK_ABORT; 738 } 739 es->num--; 740 retval = ext2fs_write_dir_block3(fs, new_blk, block, 0); 741 } else { 742 retval = ext2fs_get_mem(fs->blocksize, &block); 743 if (retval) { 744 es->err = retval; 745 return BLOCK_ABORT; 746 } 747 memset(block, 0, fs->blocksize); 748 retval = io_channel_write_blk64(fs->io, new_blk, 1, block); 749 } 750 if (retval) { 751 es->err = retval; 752 return BLOCK_ABORT; 753 } 754 ext2fs_free_mem(&block); 755 *blocknr = new_blk; 756 ext2fs_mark_block_bitmap2(ctx->block_found_map, new_blk); 757 758 if (es->num == 0) 759 return (BLOCK_CHANGED | BLOCK_ABORT); 760 else 761 return BLOCK_CHANGED; 762} 763 764/* 765 * Ensure that all blocks are marked in the block_found_map, since it's 766 * possible that the library allocated an extent node block or a block map 767 * block during the directory rebuilding; these new allocations are not 768 * captured in block_found_map. This is bad since we could later use 769 * block_found_map to allocate more blocks. 770 */ 771static int find_new_blocks_proc(ext2_filsys fs, 772 blk64_t *blocknr, 773 e2_blkcnt_t blockcnt, 774 blk64_t ref_block EXT2FS_ATTR((unused)), 775 int ref_offset EXT2FS_ATTR((unused)), 776 void *priv_data) 777{ 778 struct expand_dir_struct *es = (struct expand_dir_struct *) priv_data; 779 e2fsck_t ctx = es->ctx; 780 781 ext2fs_mark_block_bitmap2(ctx->block_found_map, *blocknr); 782 return 0; 783} 784 785errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir, 786 int num, int guaranteed_size) 787{ 788 ext2_filsys fs = ctx->fs; 789 errcode_t retval; 790 struct expand_dir_struct es; 791 struct ext2_inode inode; 792 blk64_t sz, before, after; 793 794 if (!(fs->flags & EXT2_FLAG_RW)) 795 return EXT2_ET_RO_FILSYS; 796 797 /* 798 * Read the inode and block bitmaps in; we'll be messing with 799 * them. 800 */ 801 e2fsck_read_bitmaps(ctx); 802 803 retval = ext2fs_check_directory(fs, dir); 804 if (retval) 805 return retval; 806 807 es.num = num; 808 es.guaranteed_size = guaranteed_size; 809 es.last_block = 0; 810 es.err = 0; 811 es.newblocks = 0; 812 es.ctx = ctx; 813 814 before = ext2fs_free_blocks_count(fs->super); 815 retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_APPEND, 816 0, expand_dir_proc, &es); 817 818 if (es.err) 819 return es.err; 820 after = ext2fs_free_blocks_count(fs->super); 821 822 /* 823 * If the free block count has dropped by more than the blocks we 824 * allocated ourselves, then we must've allocated some extent/map 825 * blocks. Therefore, we must iterate this dir's blocks again to 826 * ensure that all newly allocated blocks are captured in 827 * block_found_map. 828 */ 829 if ((before - after) > es.newblocks) { 830 retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_READ_ONLY, 831 0, find_new_blocks_proc, &es); 832 if (es.err) 833 return es.err; 834 } 835 836 /* 837 * Update the size and block count fields in the inode. 838 */ 839 retval = ext2fs_read_inode(fs, dir, &inode); 840 if (retval) 841 return retval; 842 843 sz = (es.last_block + 1) * fs->blocksize; 844 inode.i_size = sz; 845 inode.i_size_high = sz >> 32; 846 ext2fs_iblk_add_blocks(fs, &inode, es.newblocks); 847 quota_data_add(ctx->qctx, &inode, dir, es.newblocks * fs->blocksize); 848 849 e2fsck_write_inode(ctx, dir, &inode, "expand_directory"); 850 851 return 0; 852} 853 854