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