pass3.c revision 7bef6d52125ef3f1ef07d9da71a13546f6843c56
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; 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 e2fsck_dir_info_iter_end(ctx, iter); 112 113 /* 114 * Force the creation of /lost+found if not present 115 */ 116 if ((ctx->flags & E2F_OPT_READONLY) == 0) 117 e2fsck_get_lost_and_found(ctx, 1); 118 119 /* 120 * If there are any directories that need to be indexed or 121 * optimized, do it here. 122 */ 123 e2fsck_rehash_directories(ctx); 124 125abort_exit: 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 */ 143static 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 */ 261static 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 */ 356ext2_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 */ 504int 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 */ 555errcode_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 */ 597struct fix_dotdot_struct { 598 ext2_filsys fs; 599 ext2_ino_t parent; 600 int done; 601 e2fsck_t ctx; 602}; 603 604static 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 643static 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 681struct 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 690static 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 retval = ext2fs_new_block2(fs, last_blk, ctx->block_found_map, 716 &new_blk); 717 if (retval) { 718 es->err = retval; 719 return BLOCK_ABORT; 720 } 721 if (blockcnt > 0) { 722 retval = ext2fs_new_dir_block(fs, 0, 0, &block); 723 if (retval) { 724 es->err = retval; 725 return BLOCK_ABORT; 726 } 727 es->num--; 728 retval = ext2fs_write_dir_block3(fs, new_blk, block, 0); 729 } else { 730 retval = ext2fs_get_mem(fs->blocksize, &block); 731 if (retval) { 732 es->err = retval; 733 return BLOCK_ABORT; 734 } 735 memset(block, 0, fs->blocksize); 736 retval = io_channel_write_blk64(fs->io, new_blk, 1, block); 737 } 738 if (retval) { 739 es->err = retval; 740 return BLOCK_ABORT; 741 } 742 ext2fs_free_mem(&block); 743 *blocknr = new_blk; 744 ext2fs_mark_block_bitmap2(ctx->block_found_map, new_blk); 745 ext2fs_block_alloc_stats2(fs, new_blk, +1); 746 es->newblocks++; 747 748 if (es->num == 0) 749 return (BLOCK_CHANGED | BLOCK_ABORT); 750 else 751 return BLOCK_CHANGED; 752} 753 754errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir, 755 int num, int guaranteed_size) 756{ 757 ext2_filsys fs = ctx->fs; 758 errcode_t retval; 759 struct expand_dir_struct es; 760 struct ext2_inode inode; 761 blk64_t sz; 762 763 if (!(fs->flags & EXT2_FLAG_RW)) 764 return EXT2_ET_RO_FILSYS; 765 766 /* 767 * Read the inode and block bitmaps in; we'll be messing with 768 * them. 769 */ 770 e2fsck_read_bitmaps(ctx); 771 772 retval = ext2fs_check_directory(fs, dir); 773 if (retval) 774 return retval; 775 776 es.num = num; 777 es.guaranteed_size = guaranteed_size; 778 es.last_block = 0; 779 es.err = 0; 780 es.newblocks = 0; 781 es.ctx = ctx; 782 783 retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_APPEND, 784 0, expand_dir_proc, &es); 785 786 if (es.err) 787 return es.err; 788 789 /* 790 * Update the size and block count fields in the inode. 791 */ 792 retval = ext2fs_read_inode(fs, dir, &inode); 793 if (retval) 794 return retval; 795 796 sz = (es.last_block + 1) * fs->blocksize; 797 inode.i_size = sz; 798 inode.i_size_high = sz >> 32; 799 ext2fs_iblk_add_blocks(fs, &inode, es.newblocks); 800 quota_data_add(ctx->qctx, &inode, dir, es.newblocks * fs->blocksize); 801 802 e2fsck_write_inode(ctx, dir, &inode, "expand_directory"); 803 804 return 0; 805} 806 807