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 #ifdef HAVE_ERRNO_H 38 #include <errno.h> 39 #endif 40 41 #include "e2fsck.h" 42 #include "problem.h" 43 44 static void check_root(e2fsck_t ctx); 45 static int check_directory(e2fsck_t ctx, ext2_ino_t ino, 46 struct problem_context *pctx); 47 static void fix_dotdot(e2fsck_t ctx, ext2_ino_t ino, ext2_ino_t parent); 48 49 static ext2fs_inode_bitmap inode_loop_detect = 0; 50 static ext2fs_inode_bitmap inode_done_map = 0; 51 52 void e2fsck_pass3(e2fsck_t ctx) 53 { 54 ext2_filsys fs = ctx->fs; 55 struct dir_info_iter *iter; 56 #ifdef RESOURCE_TRACK 57 struct resource_track rtrack; 58 #endif 59 struct problem_context pctx; 60 struct dir_info *dir; 61 unsigned long maxdirs, count; 62 63 #ifdef RESOURCE_TRACK 64 init_resource_track(&rtrack); 65 #endif 66 67 clear_problem_context(&pctx); 68 69 #ifdef MTRACE 70 mtrace_print("Pass 3"); 71 #endif 72 73 if (!(ctx->options & E2F_OPT_PREEN)) 74 fix_problem(ctx, PR_3_PASS_HEADER, &pctx); 75 76 /* 77 * Allocate some bitmaps to do loop detection. 78 */ 79 pctx.errcode = ext2fs_allocate_inode_bitmap(fs, _("inode done bitmap"), 80 &inode_done_map); 81 if (pctx.errcode) { 82 pctx.num = 2; 83 fix_problem(ctx, PR_3_ALLOCATE_IBITMAP_ERROR, &pctx); 84 ctx->flags |= E2F_FLAG_ABORT; 85 goto abort_exit; 86 } 87 #ifdef RESOURCE_TRACK 88 if (ctx->options & E2F_OPT_TIME) { 89 e2fsck_clear_progbar(ctx); 90 print_resource_track(_("Peak memory"), &ctx->global_rtrack); 91 } 92 #endif 93 94 check_root(ctx); 95 if (ctx->flags & E2F_FLAG_SIGNAL_MASK) 96 goto abort_exit; 97 98 ext2fs_mark_inode_bitmap(inode_done_map, EXT2_ROOT_INO); 99 100 maxdirs = e2fsck_get_num_dirinfo(ctx); 101 count = 1; 102 103 if (ctx->progress) 104 if ((ctx->progress)(ctx, 3, 0, maxdirs)) 105 goto abort_exit; 106 107 iter = e2fsck_dir_info_iter_begin(ctx); 108 while ((dir = e2fsck_dir_info_iter(ctx, iter)) != 0) { 109 if (ctx->flags & E2F_FLAG_SIGNAL_MASK) 110 goto abort_exit; 111 if (ctx->progress && (ctx->progress)(ctx, 3, count++, maxdirs)) 112 goto abort_exit; 113 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, dir->ino)) 114 if (check_directory(ctx, dir->ino, &pctx)) 115 goto abort_exit; 116 } 117 e2fsck_dir_info_iter_end(ctx, iter); 118 119 /* 120 * Force the creation of /lost+found if not present 121 */ 122 if ((ctx->flags & E2F_OPT_READONLY) == 0) 123 e2fsck_get_lost_and_found(ctx, 1); 124 125 /* 126 * If there are any directories that need to be indexed or 127 * optimized, do it here. 128 */ 129 e2fsck_rehash_directories(ctx); 130 131 abort_exit: 132 e2fsck_free_dir_info(ctx); 133 if (inode_loop_detect) { 134 ext2fs_free_inode_bitmap(inode_loop_detect); 135 inode_loop_detect = 0; 136 } 137 if (inode_done_map) { 138 ext2fs_free_inode_bitmap(inode_done_map); 139 inode_done_map = 0; 140 } 141 142 #ifdef RESOURCE_TRACK 143 if (ctx->options & E2F_OPT_TIME2) { 144 e2fsck_clear_progbar(ctx); 145 print_resource_track(_("Pass 3"), &rtrack); 146 } 147 #endif 148 } 149 150 /* 151 * This makes sure the root inode is present; if not, we ask if the 152 * user wants us to create it. Not creating it is a fatal error. 153 */ 154 static void check_root(e2fsck_t ctx) 155 { 156 ext2_filsys fs = ctx->fs; 157 blk_t blk; 158 struct ext2_inode inode; 159 char * block; 160 struct problem_context pctx; 161 162 clear_problem_context(&pctx); 163 164 if (ext2fs_test_inode_bitmap(ctx->inode_used_map, EXT2_ROOT_INO)) { 165 /* 166 * If the root inode is not a directory, die here. The 167 * user must have answered 'no' in pass1 when we 168 * offered to clear it. 169 */ 170 if (!(ext2fs_test_inode_bitmap(ctx->inode_dir_map, 171 EXT2_ROOT_INO))) { 172 fix_problem(ctx, PR_3_ROOT_NOT_DIR_ABORT, &pctx); 173 ctx->flags |= E2F_FLAG_ABORT; 174 } 175 return; 176 } 177 178 if (!fix_problem(ctx, PR_3_NO_ROOT_INODE, &pctx)) { 179 fix_problem(ctx, PR_3_NO_ROOT_INODE_ABORT, &pctx); 180 ctx->flags |= E2F_FLAG_ABORT; 181 return; 182 } 183 184 e2fsck_read_bitmaps(ctx); 185 186 /* 187 * First, find a free block 188 */ 189 pctx.errcode = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk); 190 if (pctx.errcode) { 191 pctx.str = "ext2fs_new_block"; 192 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx); 193 ctx->flags |= E2F_FLAG_ABORT; 194 return; 195 } 196 ext2fs_mark_block_bitmap(ctx->block_found_map, blk); 197 ext2fs_mark_block_bitmap(fs->block_map, blk); 198 ext2fs_mark_bb_dirty(fs); 199 200 /* 201 * Now let's create the actual data block for the inode 202 */ 203 pctx.errcode = ext2fs_new_dir_block(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, 204 &block); 205 if (pctx.errcode) { 206 pctx.str = "ext2fs_new_dir_block"; 207 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx); 208 ctx->flags |= E2F_FLAG_ABORT; 209 return; 210 } 211 212 pctx.errcode = ext2fs_write_dir_block(fs, blk, block); 213 if (pctx.errcode) { 214 pctx.str = "ext2fs_write_dir_block"; 215 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx); 216 ctx->flags |= E2F_FLAG_ABORT; 217 return; 218 } 219 ext2fs_free_mem(&block); 220 221 /* 222 * Set up the inode structure 223 */ 224 memset(&inode, 0, sizeof(inode)); 225 inode.i_mode = 040755; 226 inode.i_size = fs->blocksize; 227 inode.i_atime = inode.i_ctime = inode.i_mtime = ctx->now; 228 inode.i_links_count = 2; 229 inode.i_blocks = fs->blocksize / 512; 230 inode.i_block[0] = blk; 231 232 /* 233 * Write out the inode. 234 */ 235 pctx.errcode = ext2fs_write_new_inode(fs, EXT2_ROOT_INO, &inode); 236 if (pctx.errcode) { 237 pctx.str = "ext2fs_write_inode"; 238 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx); 239 ctx->flags |= E2F_FLAG_ABORT; 240 return; 241 } 242 243 /* 244 * Miscellaneous bookkeeping... 245 */ 246 e2fsck_add_dir_info(ctx, EXT2_ROOT_INO, EXT2_ROOT_INO); 247 ext2fs_icount_store(ctx->inode_count, EXT2_ROOT_INO, 2); 248 ext2fs_icount_store(ctx->inode_link_info, EXT2_ROOT_INO, 2); 249 250 ext2fs_mark_inode_bitmap(ctx->inode_used_map, EXT2_ROOT_INO); 251 ext2fs_mark_inode_bitmap(ctx->inode_dir_map, EXT2_ROOT_INO); 252 ext2fs_mark_inode_bitmap(fs->inode_map, EXT2_ROOT_INO); 253 ext2fs_mark_ib_dirty(fs); 254 } 255 256 /* 257 * This subroutine is responsible for making sure that a particular 258 * directory is connected to the root; if it isn't we trace it up as 259 * far as we can go, and then offer to connect the resulting parent to 260 * the lost+found. We have to do loop detection; if we ever discover 261 * a loop, we treat that as a disconnected directory and offer to 262 * reparent it to lost+found. 263 * 264 * However, loop detection is expensive, because for very large 265 * filesystems, the inode_loop_detect bitmap is huge, and clearing it 266 * is non-trivial. Loops in filesystems are also a rare error case, 267 * and we shouldn't optimize for error cases. So we try two passes of 268 * the algorithm. The first time, we ignore loop detection and merely 269 * increment a counter; if the counter exceeds some extreme threshold, 270 * then we try again with the loop detection bitmap enabled. 271 */ 272 static int check_directory(e2fsck_t ctx, ext2_ino_t dir, 273 struct problem_context *pctx) 274 { 275 ext2_filsys fs = ctx->fs; 276 ext2_ino_t ino = dir, parent; 277 int loop_pass = 0, parent_count = 0; 278 279 while (1) { 280 /* 281 * Mark this inode as being "done"; by the time we 282 * return from this function, the inode we either be 283 * verified as being connected to the directory tree, 284 * or we will have offered to reconnect this to 285 * lost+found. 286 * 287 * If it was marked done already, then we've reached a 288 * parent we've already checked. 289 */ 290 if (ext2fs_mark_inode_bitmap(inode_done_map, ino)) 291 break; 292 293 if (e2fsck_dir_info_get_parent(ctx, ino, &parent)) { 294 fix_problem(ctx, PR_3_NO_DIRINFO, pctx); 295 return 0; 296 } 297 298 /* 299 * If this directory doesn't have a parent, or we've 300 * seen the parent once already, then offer to 301 * reparent it to lost+found 302 */ 303 if (!parent || 304 (loop_pass && 305 (ext2fs_test_inode_bitmap(inode_loop_detect, 306 parent)))) { 307 pctx->ino = ino; 308 if (fix_problem(ctx, PR_3_UNCONNECTED_DIR, pctx)) { 309 if (e2fsck_reconnect_file(ctx, pctx->ino)) 310 ext2fs_unmark_valid(fs); 311 else { 312 fix_dotdot(ctx, pctx->ino, 313 ctx->lost_and_found); 314 parent = ctx->lost_and_found; 315 } 316 } 317 break; 318 } 319 ino = parent; 320 if (loop_pass) { 321 ext2fs_mark_inode_bitmap(inode_loop_detect, ino); 322 } else if (parent_count++ > 2048) { 323 /* 324 * If we've run into a path depth that's 325 * greater than 2048, try again with the inode 326 * loop bitmap turned on and start from the 327 * top. 328 */ 329 loop_pass = 1; 330 if (inode_loop_detect) 331 ext2fs_clear_inode_bitmap(inode_loop_detect); 332 else { 333 pctx->errcode = ext2fs_allocate_inode_bitmap(fs, _("inode loop detection bitmap"), &inode_loop_detect); 334 if (pctx->errcode) { 335 pctx->num = 1; 336 fix_problem(ctx, 337 PR_3_ALLOCATE_IBITMAP_ERROR, pctx); 338 ctx->flags |= E2F_FLAG_ABORT; 339 return -1; 340 } 341 } 342 ino = dir; 343 } 344 } 345 346 /* 347 * Make sure that .. and the parent directory are the same; 348 * offer to fix it if not. 349 */ 350 pctx->ino = dir; 351 if (e2fsck_dir_info_get_dotdot(ctx, dir, &pctx->ino2) || 352 e2fsck_dir_info_get_parent(ctx, dir, &pctx->dir)) { 353 fix_problem(ctx, PR_3_NO_DIRINFO, pctx); 354 return 0; 355 } 356 if (pctx->ino2 != pctx->dir) { 357 if (fix_problem(ctx, PR_3_BAD_DOT_DOT, pctx)) 358 fix_dotdot(ctx, dir, pctx->dir); 359 } 360 return 0; 361 } 362 363 /* 364 * This routine gets the lost_and_found inode, making it a directory 365 * if necessary 366 */ 367 ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix) 368 { 369 ext2_filsys fs = ctx->fs; 370 ext2_ino_t ino; 371 blk_t blk; 372 errcode_t retval; 373 struct ext2_inode inode; 374 char * block; 375 static const char name[] = "lost+found"; 376 struct problem_context pctx; 377 378 if (ctx->lost_and_found) 379 return ctx->lost_and_found; 380 381 clear_problem_context(&pctx); 382 383 retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name, 384 sizeof(name)-1, 0, &ino); 385 if (retval && !fix) 386 return 0; 387 if (!retval) { 388 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, ino)) { 389 ctx->lost_and_found = ino; 390 return ino; 391 } 392 393 /* Lost+found isn't a directory! */ 394 if (!fix) 395 return 0; 396 pctx.ino = ino; 397 if (!fix_problem(ctx, PR_3_LPF_NOTDIR, &pctx)) 398 return 0; 399 400 /* OK, unlink the old /lost+found file. */ 401 pctx.errcode = ext2fs_unlink(fs, EXT2_ROOT_INO, name, ino, 0); 402 if (pctx.errcode) { 403 pctx.str = "ext2fs_unlink"; 404 fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); 405 return 0; 406 } 407 (void) e2fsck_dir_info_set_parent(ctx, ino, 0); 408 e2fsck_adjust_inode_count(ctx, ino, -1); 409 } else if (retval != EXT2_ET_FILE_NOT_FOUND) { 410 pctx.errcode = retval; 411 fix_problem(ctx, PR_3_ERR_FIND_LPF, &pctx); 412 } 413 if (!fix_problem(ctx, PR_3_NO_LF_DIR, 0)) 414 return 0; 415 416 /* 417 * Read the inode and block bitmaps in; we'll be messing with 418 * them. 419 */ 420 e2fsck_read_bitmaps(ctx); 421 422 /* 423 * First, find a free block 424 */ 425 retval = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk); 426 if (retval) { 427 pctx.errcode = retval; 428 fix_problem(ctx, PR_3_ERR_LPF_NEW_BLOCK, &pctx); 429 return 0; 430 } 431 ext2fs_mark_block_bitmap(ctx->block_found_map, blk); 432 ext2fs_block_alloc_stats(fs, blk, +1); 433 434 /* 435 * Next find a free inode. 436 */ 437 retval = ext2fs_new_inode(fs, EXT2_ROOT_INO, 040700, 438 ctx->inode_used_map, &ino); 439 if (retval) { 440 pctx.errcode = retval; 441 fix_problem(ctx, PR_3_ERR_LPF_NEW_INODE, &pctx); 442 return 0; 443 } 444 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino); 445 ext2fs_mark_inode_bitmap(ctx->inode_dir_map, ino); 446 ext2fs_inode_alloc_stats2(fs, ino, +1, 1); 447 448 /* 449 * Now let's create the actual data block for the inode 450 */ 451 retval = ext2fs_new_dir_block(fs, ino, EXT2_ROOT_INO, &block); 452 if (retval) { 453 pctx.errcode = retval; 454 fix_problem(ctx, PR_3_ERR_LPF_NEW_DIR_BLOCK, &pctx); 455 return 0; 456 } 457 458 retval = ext2fs_write_dir_block(fs, blk, block); 459 ext2fs_free_mem(&block); 460 if (retval) { 461 pctx.errcode = retval; 462 fix_problem(ctx, PR_3_ERR_LPF_WRITE_BLOCK, &pctx); 463 return 0; 464 } 465 466 /* 467 * Set up the inode structure 468 */ 469 memset(&inode, 0, sizeof(inode)); 470 inode.i_mode = 040700; 471 inode.i_size = fs->blocksize; 472 inode.i_atime = inode.i_ctime = inode.i_mtime = ctx->now; 473 inode.i_links_count = 2; 474 inode.i_blocks = fs->blocksize / 512; 475 inode.i_block[0] = blk; 476 477 /* 478 * Next, write out the inode. 479 */ 480 pctx.errcode = ext2fs_write_new_inode(fs, ino, &inode); 481 if (pctx.errcode) { 482 pctx.str = "ext2fs_write_inode"; 483 fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); 484 return 0; 485 } 486 /* 487 * Finally, create the directory link 488 */ 489 pctx.errcode = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, EXT2_FT_DIR); 490 if (pctx.errcode) { 491 pctx.str = "ext2fs_link"; 492 fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); 493 return 0; 494 } 495 496 /* 497 * Miscellaneous bookkeeping that needs to be kept straight. 498 */ 499 e2fsck_add_dir_info(ctx, ino, EXT2_ROOT_INO); 500 e2fsck_adjust_inode_count(ctx, EXT2_ROOT_INO, 1); 501 ext2fs_icount_store(ctx->inode_count, ino, 2); 502 ext2fs_icount_store(ctx->inode_link_info, ino, 2); 503 ctx->lost_and_found = ino; 504 #if 0 505 printf("/lost+found created; inode #%lu\n", ino); 506 #endif 507 return ino; 508 } 509 510 /* 511 * This routine will connect a file to lost+found 512 */ 513 int e2fsck_reconnect_file(e2fsck_t ctx, ext2_ino_t ino) 514 { 515 ext2_filsys fs = ctx->fs; 516 errcode_t retval; 517 char name[80]; 518 struct problem_context pctx; 519 struct ext2_inode inode; 520 int file_type = 0; 521 522 clear_problem_context(&pctx); 523 pctx.ino = ino; 524 525 if (!ctx->bad_lost_and_found && !ctx->lost_and_found) { 526 if (e2fsck_get_lost_and_found(ctx, 1) == 0) 527 ctx->bad_lost_and_found++; 528 } 529 if (ctx->bad_lost_and_found) { 530 fix_problem(ctx, PR_3_NO_LPF, &pctx); 531 return 1; 532 } 533 534 sprintf(name, "#%u", ino); 535 if (ext2fs_read_inode(fs, ino, &inode) == 0) 536 file_type = ext2_file_type(inode.i_mode); 537 retval = ext2fs_link(fs, ctx->lost_and_found, name, ino, file_type); 538 if (retval == EXT2_ET_DIR_NO_SPACE) { 539 if (!fix_problem(ctx, PR_3_EXPAND_LF_DIR, &pctx)) 540 return 1; 541 retval = e2fsck_expand_directory(ctx, ctx->lost_and_found, 542 1, 0); 543 if (retval) { 544 pctx.errcode = retval; 545 fix_problem(ctx, PR_3_CANT_EXPAND_LPF, &pctx); 546 return 1; 547 } 548 retval = ext2fs_link(fs, ctx->lost_and_found, name, 549 ino, file_type); 550 } 551 if (retval) { 552 pctx.errcode = retval; 553 fix_problem(ctx, PR_3_CANT_RECONNECT, &pctx); 554 return 1; 555 } 556 e2fsck_adjust_inode_count(ctx, ino, 1); 557 558 return 0; 559 } 560 561 /* 562 * Utility routine to adjust the inode counts on an inode. 563 */ 564 errcode_t e2fsck_adjust_inode_count(e2fsck_t ctx, ext2_ino_t ino, int adj) 565 { 566 ext2_filsys fs = ctx->fs; 567 errcode_t retval; 568 struct ext2_inode inode; 569 570 if (!ino) 571 return 0; 572 573 retval = ext2fs_read_inode(fs, ino, &inode); 574 if (retval) 575 return retval; 576 577 #if 0 578 printf("Adjusting link count for inode %lu by %d (from %d)\n", ino, adj, 579 inode.i_links_count); 580 #endif 581 582 if (adj == 1) { 583 ext2fs_icount_increment(ctx->inode_count, ino, 0); 584 if (inode.i_links_count == (__u16) ~0) 585 return 0; 586 ext2fs_icount_increment(ctx->inode_link_info, ino, 0); 587 inode.i_links_count++; 588 } else if (adj == -1) { 589 ext2fs_icount_decrement(ctx->inode_count, ino, 0); 590 if (inode.i_links_count == 0) 591 return 0; 592 ext2fs_icount_decrement(ctx->inode_link_info, ino, 0); 593 inode.i_links_count--; 594 } 595 596 retval = ext2fs_write_inode(fs, ino, &inode); 597 if (retval) 598 return retval; 599 600 return 0; 601 } 602 603 /* 604 * Fix parent --- this routine fixes up the parent of a directory. 605 */ 606 struct fix_dotdot_struct { 607 ext2_filsys fs; 608 ext2_ino_t parent; 609 int done; 610 e2fsck_t ctx; 611 }; 612 613 static int fix_dotdot_proc(struct ext2_dir_entry *dirent, 614 int offset EXT2FS_ATTR((unused)), 615 int blocksize EXT2FS_ATTR((unused)), 616 char *buf EXT2FS_ATTR((unused)), 617 void *priv_data) 618 { 619 struct fix_dotdot_struct *fp = (struct fix_dotdot_struct *) priv_data; 620 errcode_t retval; 621 struct problem_context pctx; 622 623 if ((dirent->name_len & 0xFF) != 2) 624 return 0; 625 if (strncmp(dirent->name, "..", 2)) 626 return 0; 627 628 clear_problem_context(&pctx); 629 630 retval = e2fsck_adjust_inode_count(fp->ctx, dirent->inode, -1); 631 if (retval) { 632 pctx.errcode = retval; 633 fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx); 634 } 635 retval = e2fsck_adjust_inode_count(fp->ctx, fp->parent, 1); 636 if (retval) { 637 pctx.errcode = retval; 638 fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx); 639 } 640 dirent->inode = fp->parent; 641 if (fp->ctx->fs->super->s_feature_incompat & 642 EXT2_FEATURE_INCOMPAT_FILETYPE) 643 dirent->name_len = (dirent->name_len & 0xFF) | 644 (EXT2_FT_DIR << 8); 645 else 646 dirent->name_len = dirent->name_len & 0xFF; 647 648 fp->done++; 649 return DIRENT_ABORT | DIRENT_CHANGED; 650 } 651 652 static void fix_dotdot(e2fsck_t ctx, ext2_ino_t ino, ext2_ino_t parent) 653 { 654 ext2_filsys fs = ctx->fs; 655 errcode_t retval; 656 struct fix_dotdot_struct fp; 657 struct problem_context pctx; 658 659 fp.fs = fs; 660 fp.parent = parent; 661 fp.done = 0; 662 fp.ctx = ctx; 663 664 #if 0 665 printf("Fixing '..' of inode %lu to be %lu...\n", ino, parent); 666 #endif 667 668 clear_problem_context(&pctx); 669 pctx.ino = ino; 670 retval = ext2fs_dir_iterate(fs, ino, DIRENT_FLAG_INCLUDE_EMPTY, 671 0, fix_dotdot_proc, &fp); 672 if (retval || !fp.done) { 673 pctx.errcode = retval; 674 fix_problem(ctx, retval ? PR_3_FIX_PARENT_ERR : 675 PR_3_FIX_PARENT_NOFIND, &pctx); 676 ext2fs_unmark_valid(fs); 677 } 678 (void) e2fsck_dir_info_set_dotdot(ctx, ino, parent); 679 if (e2fsck_dir_info_set_parent(ctx, ino, ctx->lost_and_found)) 680 fix_problem(ctx, PR_3_NO_DIRINFO, &pctx); 681 682 return; 683 } 684 685 /* 686 * These routines are responsible for expanding a /lost+found if it is 687 * too small. 688 */ 689 690 struct expand_dir_struct { 691 int num; 692 int guaranteed_size; 693 int newblocks; 694 int last_block; 695 errcode_t err; 696 e2fsck_t ctx; 697 }; 698 699 static int expand_dir_proc(ext2_filsys fs, 700 blk_t *blocknr, 701 e2_blkcnt_t blockcnt, 702 blk_t ref_block EXT2FS_ATTR((unused)), 703 int ref_offset EXT2FS_ATTR((unused)), 704 void *priv_data) 705 { 706 struct expand_dir_struct *es = (struct expand_dir_struct *) priv_data; 707 blk_t new_blk; 708 static blk_t last_blk = 0; 709 char *block; 710 errcode_t retval; 711 e2fsck_t ctx; 712 713 ctx = es->ctx; 714 715 if (es->guaranteed_size && blockcnt >= es->guaranteed_size) 716 return BLOCK_ABORT; 717 718 if (blockcnt > 0) 719 es->last_block = blockcnt; 720 if (*blocknr) { 721 last_blk = *blocknr; 722 return 0; 723 } 724 retval = ext2fs_new_block(fs, last_blk, ctx->block_found_map, 725 &new_blk); 726 if (retval) { 727 es->err = retval; 728 return BLOCK_ABORT; 729 } 730 if (blockcnt > 0) { 731 retval = ext2fs_new_dir_block(fs, 0, 0, &block); 732 if (retval) { 733 es->err = retval; 734 return BLOCK_ABORT; 735 } 736 es->num--; 737 retval = ext2fs_write_dir_block(fs, new_blk, block); 738 } else { 739 retval = ext2fs_get_mem(fs->blocksize, &block); 740 if (retval) { 741 es->err = retval; 742 return BLOCK_ABORT; 743 } 744 memset(block, 0, fs->blocksize); 745 retval = io_channel_write_blk(fs->io, new_blk, 1, block); 746 } 747 if (retval) { 748 es->err = retval; 749 return BLOCK_ABORT; 750 } 751 ext2fs_free_mem(&block); 752 *blocknr = new_blk; 753 ext2fs_mark_block_bitmap(ctx->block_found_map, new_blk); 754 ext2fs_block_alloc_stats(fs, new_blk, +1); 755 es->newblocks++; 756 757 if (es->num == 0) 758 return (BLOCK_CHANGED | BLOCK_ABORT); 759 else 760 return BLOCK_CHANGED; 761 } 762 763 errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir, 764 int num, int guaranteed_size) 765 { 766 ext2_filsys fs = ctx->fs; 767 errcode_t retval; 768 struct expand_dir_struct es; 769 struct ext2_inode inode; 770 771 if (!(fs->flags & EXT2_FLAG_RW)) 772 return EXT2_ET_RO_FILSYS; 773 774 /* 775 * Read the inode and block bitmaps in; we'll be messing with 776 * them. 777 */ 778 e2fsck_read_bitmaps(ctx); 779 780 retval = ext2fs_check_directory(fs, dir); 781 if (retval) 782 return retval; 783 784 es.num = num; 785 es.guaranteed_size = guaranteed_size; 786 es.last_block = 0; 787 es.err = 0; 788 es.newblocks = 0; 789 es.ctx = ctx; 790 791 retval = ext2fs_block_iterate2(fs, dir, BLOCK_FLAG_APPEND, 792 0, expand_dir_proc, &es); 793 794 if (es.err) 795 return es.err; 796 797 /* 798 * Update the size and block count fields in the inode. 799 */ 800 retval = ext2fs_read_inode(fs, dir, &inode); 801 if (retval) 802 return retval; 803 804 inode.i_size = (es.last_block + 1) * fs->blocksize; 805 inode.i_blocks += (fs->blocksize / 512) * es.newblocks; 806 807 e2fsck_write_inode(ctx, dir, &inode, "expand_directory"); 808 809 return 0; 810 } 811 812