pass3.c revision 0047255f602ae725a37f24c9b3214a1400459a20
1/* 2 * pass3.c -- pass #3 of e2fsck: Check for directory connectivity 3 * 4 * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999 Theodore Ts'o. 5 * 6 * %Begin-Header% 7 * This file may be redistributed under the terms of the GNU Public 8 * License. 9 * %End-Header% 10 * 11 * Pass #3 assures that all directories are connected to the 12 * filesystem tree, using the following algorithm: 13 * 14 * First, the root directory is checked to make sure it exists; if 15 * not, e2fsck will offer to create a new one. It is then marked as 16 * "done". 17 * 18 * Then, pass3 interates over all directory inodes; for each directory 19 * it attempts to trace up the filesystem tree, using dirinfo.parent 20 * until it reaches a directory which has been marked "done". If it 21 * can not do so, then the directory must be disconnected, and e2fsck 22 * will offer to reconnect it to /lost+found. While it is chasing 23 * parent pointers up the filesystem tree, if pass3 sees a directory 24 * twice, then it has detected a filesystem loop, and it will again 25 * offer to reconnect the directory to /lost+found in to break the 26 * filesystem loop. 27 * 28 * Pass 3 also contains the subroutine, e2fsck_reconnect_file() to 29 * reconnect inodes to /lost+found; this subroutine is also used by 30 * pass 4. e2fsck_reconnect_file() calls get_lost_and_found(), which 31 * is responsible for creating /lost+found if it does not exist. 32 * 33 * Pass 3 frees the following data structures: 34 * - The dirinfo directory information cache. 35 */ 36 37#include "config.h" 38#ifdef HAVE_ERRNO_H 39#include <errno.h> 40#endif 41 42#include "e2fsck.h" 43#include "problem.h" 44 45static void check_root(e2fsck_t ctx); 46static int check_directory(e2fsck_t ctx, ext2_ino_t ino, 47 struct problem_context *pctx); 48static void fix_dotdot(e2fsck_t ctx, ext2_ino_t ino, ext2_ino_t parent); 49 50static ext2fs_inode_bitmap inode_loop_detect = 0; 51static ext2fs_inode_bitmap inode_done_map = 0; 52 53void e2fsck_pass3(e2fsck_t ctx) 54{ 55 ext2_filsys fs = ctx->fs; 56 struct dir_info_iter *iter = NULL; 57#ifdef RESOURCE_TRACK 58 struct resource_track rtrack; 59#endif 60 struct problem_context pctx; 61 struct dir_info *dir; 62 unsigned long maxdirs, count; 63 64 init_resource_track(&rtrack, ctx->fs->io); 65 clear_problem_context(&pctx); 66 67#ifdef MTRACE 68 mtrace_print("Pass 3"); 69#endif 70 71 if (!(ctx->options & E2F_OPT_PREEN)) 72 fix_problem(ctx, PR_3_PASS_HEADER, &pctx); 73 74 /* 75 * Allocate some bitmaps to do loop detection. 76 */ 77 pctx.errcode = e2fsck_allocate_inode_bitmap(fs, _("inode done bitmap"), 78 EXT2FS_BMAP64_AUTODIR, 79 "inode_done_map", &inode_done_map); 80 if (pctx.errcode) { 81 pctx.num = 2; 82 fix_problem(ctx, PR_3_ALLOCATE_IBITMAP_ERROR, &pctx); 83 ctx->flags |= E2F_FLAG_ABORT; 84 goto abort_exit; 85 } 86 print_resource_track(ctx, _("Peak memory"), &ctx->global_rtrack, NULL); 87 88 check_root(ctx); 89 if (ctx->flags & E2F_FLAG_SIGNAL_MASK) 90 goto abort_exit; 91 92 ext2fs_mark_inode_bitmap2(inode_done_map, EXT2_ROOT_INO); 93 94 maxdirs = e2fsck_get_num_dirinfo(ctx); 95 count = 1; 96 97 if (ctx->progress) 98 if ((ctx->progress)(ctx, 3, 0, maxdirs)) 99 goto abort_exit; 100 101 iter = e2fsck_dir_info_iter_begin(ctx); 102 while ((dir = e2fsck_dir_info_iter(ctx, iter)) != 0) { 103 if (ctx->flags & E2F_FLAG_SIGNAL_MASK) 104 goto abort_exit; 105 if (ctx->progress && (ctx->progress)(ctx, 3, count++, maxdirs)) 106 goto abort_exit; 107 if (ext2fs_test_inode_bitmap2(ctx->inode_dir_map, dir->ino)) 108 if (check_directory(ctx, dir->ino, &pctx)) 109 goto abort_exit; 110 } 111 112 /* 113 * Force the creation of /lost+found if not present 114 */ 115 if ((ctx->flags & E2F_OPT_READONLY) == 0) 116 e2fsck_get_lost_and_found(ctx, 1); 117 118 /* 119 * If there are any directories that need to be indexed or 120 * optimized, do it here. 121 */ 122 e2fsck_rehash_directories(ctx); 123 124abort_exit: 125 if (iter) 126 e2fsck_dir_info_iter_end(ctx, iter); 127 e2fsck_free_dir_info(ctx); 128 if (inode_loop_detect) { 129 ext2fs_free_inode_bitmap(inode_loop_detect); 130 inode_loop_detect = 0; 131 } 132 if (inode_done_map) { 133 ext2fs_free_inode_bitmap(inode_done_map); 134 inode_done_map = 0; 135 } 136 137 print_resource_track(ctx, _("Pass 3"), &rtrack, ctx->fs->io); 138} 139 140/* 141 * This makes sure the root inode is present; if not, we ask if the 142 * user wants us to create it. Not creating it is a fatal error. 143 */ 144static void check_root(e2fsck_t ctx) 145{ 146 ext2_filsys fs = ctx->fs; 147 blk64_t blk; 148 struct ext2_inode inode; 149 char * block; 150 struct problem_context pctx; 151 152 clear_problem_context(&pctx); 153 154 if (ext2fs_test_inode_bitmap2(ctx->inode_used_map, EXT2_ROOT_INO)) { 155 /* 156 * If the root inode is not a directory, die here. The 157 * user must have answered 'no' in pass1 when we 158 * offered to clear it. 159 */ 160 if (!(ext2fs_test_inode_bitmap2(ctx->inode_dir_map, 161 EXT2_ROOT_INO))) { 162 fix_problem(ctx, PR_3_ROOT_NOT_DIR_ABORT, &pctx); 163 ctx->flags |= E2F_FLAG_ABORT; 164 } 165 return; 166 } 167 168 if (!fix_problem(ctx, PR_3_NO_ROOT_INODE, &pctx)) { 169 fix_problem(ctx, PR_3_NO_ROOT_INODE_ABORT, &pctx); 170 ctx->flags |= E2F_FLAG_ABORT; 171 return; 172 } 173 174 e2fsck_read_bitmaps(ctx); 175 176 /* 177 * First, find a free block 178 */ 179 pctx.errcode = ext2fs_new_block2(fs, 0, ctx->block_found_map, &blk); 180 if (pctx.errcode) { 181 pctx.str = "ext2fs_new_block"; 182 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx); 183 ctx->flags |= E2F_FLAG_ABORT; 184 return; 185 } 186 ext2fs_mark_block_bitmap2(ctx->block_found_map, blk); 187 ext2fs_mark_block_bitmap2(fs->block_map, blk); 188 ext2fs_mark_bb_dirty(fs); 189 190 /* 191 * Now let's create the actual data block for the inode 192 */ 193 pctx.errcode = ext2fs_new_dir_block(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, 194 &block); 195 if (pctx.errcode) { 196 pctx.str = "ext2fs_new_dir_block"; 197 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx); 198 ctx->flags |= E2F_FLAG_ABORT; 199 return; 200 } 201 202 pctx.errcode = ext2fs_write_dir_block3(fs, blk, block, 0); 203 if (pctx.errcode) { 204 pctx.str = "ext2fs_write_dir_block3"; 205 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx); 206 ctx->flags |= E2F_FLAG_ABORT; 207 return; 208 } 209 ext2fs_free_mem(&block); 210 211 /* 212 * Set up the inode structure 213 */ 214 memset(&inode, 0, sizeof(inode)); 215 inode.i_mode = 040755; 216 inode.i_size = fs->blocksize; 217 inode.i_atime = inode.i_ctime = inode.i_mtime = ctx->now; 218 inode.i_links_count = 2; 219 ext2fs_iblk_set(fs, &inode, 1); 220 inode.i_block[0] = blk; 221 222 /* 223 * Write out the inode. 224 */ 225 pctx.errcode = ext2fs_write_new_inode(fs, EXT2_ROOT_INO, &inode); 226 if (pctx.errcode) { 227 pctx.str = "ext2fs_write_inode"; 228 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx); 229 ctx->flags |= E2F_FLAG_ABORT; 230 return; 231 } 232 233 /* 234 * Miscellaneous bookkeeping... 235 */ 236 e2fsck_add_dir_info(ctx, EXT2_ROOT_INO, EXT2_ROOT_INO); 237 ext2fs_icount_store(ctx->inode_count, EXT2_ROOT_INO, 2); 238 ext2fs_icount_store(ctx->inode_link_info, EXT2_ROOT_INO, 2); 239 240 ext2fs_mark_inode_bitmap2(ctx->inode_used_map, EXT2_ROOT_INO); 241 ext2fs_mark_inode_bitmap2(ctx->inode_dir_map, EXT2_ROOT_INO); 242 ext2fs_mark_inode_bitmap2(fs->inode_map, EXT2_ROOT_INO); 243 ext2fs_mark_ib_dirty(fs); 244} 245 246/* 247 * This subroutine is responsible for making sure that a particular 248 * directory is connected to the root; if it isn't we trace it up as 249 * far as we can go, and then offer to connect the resulting parent to 250 * the lost+found. We have to do loop detection; if we ever discover 251 * a loop, we treat that as a disconnected directory and offer to 252 * reparent it to lost+found. 253 * 254 * However, loop detection is expensive, because for very large 255 * filesystems, the inode_loop_detect bitmap is huge, and clearing it 256 * is non-trivial. Loops in filesystems are also a rare error case, 257 * and we shouldn't optimize for error cases. So we try two passes of 258 * the algorithm. The first time, we ignore loop detection and merely 259 * increment a counter; if the counter exceeds some extreme threshold, 260 * then we try again with the loop detection bitmap enabled. 261 */ 262static int check_directory(e2fsck_t ctx, ext2_ino_t dir, 263 struct problem_context *pctx) 264{ 265 ext2_filsys fs = ctx->fs; 266 ext2_ino_t ino = dir, parent; 267 int loop_pass = 0, parent_count = 0; 268 269 while (1) { 270 /* 271 * Mark this inode as being "done"; by the time we 272 * return from this function, the inode we either be 273 * verified as being connected to the directory tree, 274 * or we will have offered to reconnect this to 275 * lost+found. 276 * 277 * If it was marked done already, then we've reached a 278 * parent we've already checked. 279 */ 280 if (ext2fs_mark_inode_bitmap2(inode_done_map, ino)) 281 break; 282 283 if (e2fsck_dir_info_get_parent(ctx, ino, &parent)) { 284 fix_problem(ctx, PR_3_NO_DIRINFO, pctx); 285 return 0; 286 } 287 288 /* 289 * If this directory doesn't have a parent, or we've 290 * seen the parent once already, then offer to 291 * reparent it to lost+found 292 */ 293 if (!parent || 294 (loop_pass && 295 (ext2fs_test_inode_bitmap2(inode_loop_detect, 296 parent)))) { 297 pctx->ino = ino; 298 if (fix_problem(ctx, PR_3_UNCONNECTED_DIR, pctx)) { 299 if (e2fsck_reconnect_file(ctx, pctx->ino)) 300 ext2fs_unmark_valid(fs); 301 else { 302 fix_dotdot(ctx, pctx->ino, 303 ctx->lost_and_found); 304 parent = ctx->lost_and_found; 305 } 306 } 307 break; 308 } 309 ino = parent; 310 if (loop_pass) { 311 ext2fs_mark_inode_bitmap2(inode_loop_detect, ino); 312 } else if (parent_count++ > 2048) { 313 /* 314 * If we've run into a path depth that's 315 * greater than 2048, try again with the inode 316 * loop bitmap turned on and start from the 317 * top. 318 */ 319 loop_pass = 1; 320 if (inode_loop_detect) 321 ext2fs_clear_inode_bitmap(inode_loop_detect); 322 else { 323 pctx->errcode = e2fsck_allocate_inode_bitmap(fs, _("inode loop detection bitmap"), EXT2FS_BMAP64_AUTODIR, "inode_loop_detect", &inode_loop_detect); 324 if (pctx->errcode) { 325 pctx->num = 1; 326 fix_problem(ctx, 327 PR_3_ALLOCATE_IBITMAP_ERROR, pctx); 328 ctx->flags |= E2F_FLAG_ABORT; 329 return -1; 330 } 331 } 332 ino = dir; 333 } 334 } 335 336 /* 337 * Make sure that .. and the parent directory are the same; 338 * offer to fix it if not. 339 */ 340 pctx->ino = dir; 341 if (e2fsck_dir_info_get_dotdot(ctx, dir, &pctx->ino2) || 342 e2fsck_dir_info_get_parent(ctx, dir, &pctx->dir)) { 343 fix_problem(ctx, PR_3_NO_DIRINFO, pctx); 344 return 0; 345 } 346 if (pctx->ino2 != pctx->dir) { 347 if (fix_problem(ctx, PR_3_BAD_DOT_DOT, pctx)) 348 fix_dotdot(ctx, dir, pctx->dir); 349 } 350 return 0; 351} 352 353/* 354 * This routine gets the lost_and_found inode, making it a directory 355 * if necessary 356 */ 357ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix) 358{ 359 ext2_filsys fs = ctx->fs; 360 ext2_ino_t ino; 361 blk64_t blk; 362 errcode_t retval; 363 struct ext2_inode inode; 364 char * block; 365 static const char name[] = "lost+found"; 366 struct problem_context pctx; 367 368 if (ctx->lost_and_found) 369 return ctx->lost_and_found; 370 371 clear_problem_context(&pctx); 372 373 retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name, 374 sizeof(name)-1, 0, &ino); 375 if (retval && !fix) 376 return 0; 377 if (!retval) { 378 if (ext2fs_test_inode_bitmap2(ctx->inode_dir_map, ino)) { 379 ctx->lost_and_found = ino; 380 return ino; 381 } 382 383 /* Lost+found isn't a directory! */ 384 if (!fix) 385 return 0; 386 pctx.ino = ino; 387 if (!fix_problem(ctx, PR_3_LPF_NOTDIR, &pctx)) 388 return 0; 389 390 /* OK, unlink the old /lost+found file. */ 391 pctx.errcode = ext2fs_unlink(fs, EXT2_ROOT_INO, name, ino, 0); 392 if (pctx.errcode) { 393 pctx.str = "ext2fs_unlink"; 394 fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); 395 return 0; 396 } 397 (void) e2fsck_dir_info_set_parent(ctx, ino, 0); 398 e2fsck_adjust_inode_count(ctx, ino, -1); 399 } else if (retval != EXT2_ET_FILE_NOT_FOUND) { 400 pctx.errcode = retval; 401 fix_problem(ctx, PR_3_ERR_FIND_LPF, &pctx); 402 } 403 if (!fix_problem(ctx, PR_3_NO_LF_DIR, 0)) 404 return 0; 405 406 /* 407 * Read the inode and block bitmaps in; we'll be messing with 408 * them. 409 */ 410 e2fsck_read_bitmaps(ctx); 411 412 /* 413 * First, find a free block 414 */ 415 retval = ext2fs_new_block2(fs, 0, ctx->block_found_map, &blk); 416 if (retval) { 417 pctx.errcode = retval; 418 fix_problem(ctx, PR_3_ERR_LPF_NEW_BLOCK, &pctx); 419 return 0; 420 } 421 ext2fs_mark_block_bitmap2(ctx->block_found_map, blk); 422 ext2fs_block_alloc_stats2(fs, blk, +1); 423 424 /* 425 * Next find a free inode. 426 */ 427 retval = ext2fs_new_inode(fs, EXT2_ROOT_INO, 040700, 428 ctx->inode_used_map, &ino); 429 if (retval) { 430 pctx.errcode = retval; 431 fix_problem(ctx, PR_3_ERR_LPF_NEW_INODE, &pctx); 432 return 0; 433 } 434 ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino); 435 ext2fs_mark_inode_bitmap2(ctx->inode_dir_map, ino); 436 ext2fs_inode_alloc_stats2(fs, ino, +1, 1); 437 438 /* 439 * Now let's create the actual data block for the inode 440 */ 441 retval = ext2fs_new_dir_block(fs, ino, EXT2_ROOT_INO, &block); 442 if (retval) { 443 pctx.errcode = retval; 444 fix_problem(ctx, PR_3_ERR_LPF_NEW_DIR_BLOCK, &pctx); 445 return 0; 446 } 447 448 retval = ext2fs_write_dir_block3(fs, blk, block, 0); 449 ext2fs_free_mem(&block); 450 if (retval) { 451 pctx.errcode = retval; 452 fix_problem(ctx, PR_3_ERR_LPF_WRITE_BLOCK, &pctx); 453 return 0; 454 } 455 456 /* 457 * Set up the inode structure 458 */ 459 memset(&inode, 0, sizeof(inode)); 460 inode.i_mode = 040700; 461 inode.i_size = fs->blocksize; 462 inode.i_atime = inode.i_ctime = inode.i_mtime = ctx->now; 463 inode.i_links_count = 2; 464 ext2fs_iblk_set(fs, &inode, 1); 465 inode.i_block[0] = blk; 466 467 /* 468 * Next, write out the inode. 469 */ 470 pctx.errcode = ext2fs_write_new_inode(fs, ino, &inode); 471 if (pctx.errcode) { 472 pctx.str = "ext2fs_write_inode"; 473 fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); 474 return 0; 475 } 476 /* 477 * Finally, create the directory link 478 */ 479 pctx.errcode = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, EXT2_FT_DIR); 480 if (pctx.errcode) { 481 pctx.str = "ext2fs_link"; 482 fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); 483 return 0; 484 } 485 486 /* 487 * Miscellaneous bookkeeping that needs to be kept straight. 488 */ 489 e2fsck_add_dir_info(ctx, ino, EXT2_ROOT_INO); 490 e2fsck_adjust_inode_count(ctx, EXT2_ROOT_INO, 1); 491 ext2fs_icount_store(ctx->inode_count, ino, 2); 492 ext2fs_icount_store(ctx->inode_link_info, ino, 2); 493 ctx->lost_and_found = ino; 494 quota_data_add(ctx->qctx, &inode, ino, fs->blocksize); 495 quota_data_inodes(ctx->qctx, &inode, ino, +1); 496#if 0 497 printf("/lost+found created; inode #%lu\n", ino); 498#endif 499 return ino; 500} 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