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