1 /* 2 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 7 /* All Rights Reserved */ 8 9 /* 10 * Copyright (c) 1980, 1986, 1990 The Regents of the University of California. 11 * All rights reserved. 12 * 13 * Redistribution and use in source and binary forms are permitted 14 * provided that: (1) source distributions retain this entire copyright 15 * notice and comment, and (2) distributions including binaries display 16 * the following acknowledgement: ``This product includes software 17 * developed by the University of California, Berkeley and its contributors'' 18 * in the documentation or other materials provided with the distribution 19 * and in all advertising materials mentioning features or use of this 20 * software. Neither the name of the University nor the names of its 21 * contributors may be used to endorse or promote products derived 22 * from this software without specific prior written permission. 23 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 26 */ 27 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <sys/param.h> 31 #include <sys/types.h> 32 #include <sys/sysmacros.h> 33 #include <sys/mntent.h> 34 #include <sys/fs/ufs_fs.h> 35 #include <sys/vnode.h> 36 #include <sys/fs/ufs_inode.h> 37 #define _KERNEL 38 #include <sys/fs/ufs_fsdir.h> 39 #undef _KERNEL 40 #include <string.h> 41 #include "fsck.h" 42 43 #define MINDIRSIZE (sizeof (struct dirtemplate)) 44 45 static int blksort(const void *, const void *); 46 static int pass2check(struct inodesc *); 47 48 void 49 pass2(void) 50 { 51 struct dinode *dp, *dp2, *dpattr; 52 struct inoinfo **inpp, *inp; 53 struct inoinfo **inpend; 54 struct inodesc curino; 55 struct inodesc ldesc; 56 struct dinode dino; 57 char pathbuf[MAXPATHLEN + 1]; 58 int found; 59 int dirtype; 60 caddr_t errmsg; 61 struct shadowclientinfo *sci; 62 63 switch (statemap[UFSROOTINO] & ~INDELAYD) { 64 case USTATE: 65 pfatal("ROOT INODE UNALLOCATED"); 66 if (reply("ALLOCATE") == 0) { 67 errexit("Program terminated."); 68 } 69 if (allocdir(UFSROOTINO, UFSROOTINO, 0755, 0) != UFSROOTINO) 70 errexit("CANNOT ALLOCATE ROOT INODE\n"); 71 break; 72 73 case DCLEAR: 74 pfatal("DUPS/BAD IN ROOT INODE"); 75 if (reply("REALLOCATE") == 1) { 76 freeino(UFSROOTINO, TI_NOPARENT); 77 if (allocdir(UFSROOTINO, UFSROOTINO, 78 0755, 0) != UFSROOTINO) 79 errexit("CANNOT ALLOCATE ROOT INODE\n"); 80 break; 81 } 82 if (reply("CONTINUE") == 0) { 83 errexit("Program terminated."); 84 } 85 break; 86 87 case FSTATE: 88 case FCLEAR: 89 case FZLINK: 90 case SSTATE: 91 case SCLEAR: 92 pfatal("ROOT INODE NOT DIRECTORY"); 93 if (reply("REALLOCATE") == 1) { 94 freeino(UFSROOTINO, TI_NOPARENT); 95 if (allocdir(UFSROOTINO, UFSROOTINO, 0755, 0) != 96 UFSROOTINO) 97 errexit("CANNOT ALLOCATE ROOT INODE\n"); 98 break; 99 } 100 if (reply("FIX") == 0) { 101 ckfini(); 102 errexit("Program terminated."); 103 } 104 dp = ginode(UFSROOTINO); 105 dp->di_mode &= ~IFMT; 106 dp->di_mode |= IFDIR; 107 inodirty(); 108 break; 109 110 case DSTATE: 111 case DZLINK: 112 break; 113 114 default: 115 errexit("BAD STATE 0x%x FOR ROOT INODE\n", 116 statemap[UFSROOTINO]); 117 } 118 statemap[UFSROOTINO] = DFOUND; 119 120 /* 121 * Technically, we do know who the parent is. However, 122 * if this is set, then we'll get confused during the 123 * second-dir-entry-is-dotdot test for the root inode. 124 */ 125 inp = getinoinfo(UFSROOTINO); 126 if (inp != NULL && inp->i_dotdot != 0) 127 inp->i_dotdot = 0; 128 129 /* 130 * Sort the directory list into disk block order. There's no 131 * requirement to do this, but it may help improve our i/o times 132 * somewhat. 133 */ 134 qsort((void *)inpsort, (size_t)inplast, sizeof (*inpsort), blksort); 135 /* 136 * Check the integrity of each directory. In general, we treat 137 * attribute directories just like normal ones. Only the handling 138 * of .. is really different. 139 */ 140 (void) memset(&dino, 0, sizeof (struct dinode)); 141 dino.di_mode = IFDIR; 142 inpend = &inpsort[inplast]; 143 for (inpp = inpsort; inpp < inpend; inpp++) { 144 inp = *inpp; 145 146 if (inp->i_isize == 0) 147 continue; 148 149 /* != DSTATE also covers case of == USTATE */ 150 if (((statemap[inp->i_number] & STMASK) != DSTATE) || 151 ((statemap[inp->i_number] & INCLEAR) == INCLEAR)) 152 continue; 153 154 if (inp->i_isize < (offset_t)MINDIRSIZE) { 155 direrror(inp->i_number, "DIRECTORY TOO SHORT"); 156 inp->i_isize = (offset_t)roundup(MINDIRSIZE, DIRBLKSIZ); 157 if (reply("FIX") == 1) { 158 dp = ginode(inp->i_number); 159 dp->di_size = (u_offset_t)inp->i_isize; 160 inodirty(); 161 } else { 162 iscorrupt = 1; 163 } 164 } 165 if ((inp->i_isize & (offset_t)(DIRBLKSIZ - 1)) != 0) { 166 getpathname(pathbuf, inp->i_number, inp->i_number); 167 pwarn("DIRECTORY %s: LENGTH %lld NOT MULTIPLE OF %d", 168 pathbuf, (longlong_t)inp->i_isize, DIRBLKSIZ); 169 inp->i_isize = roundup(inp->i_isize, 170 (offset_t)DIRBLKSIZ); 171 if (preen || reply("ADJUST") == 1) { 172 dp = ginode(inp->i_number); 173 dp->di_size = 174 (u_offset_t)roundup(inp->i_isize, 175 (offset_t)DIRBLKSIZ); 176 inodirty(); 177 if (preen) 178 (void) printf(" (ADJUSTED)\n"); 179 } else { 180 iscorrupt = 1; 181 } 182 } 183 dp = ginode(inp->i_number); 184 if ((dp->di_mode & IFMT) == IFATTRDIR && 185 (dp->di_cflags & IXATTR) == 0) { 186 pwarn("ATTRIBUTE DIRECTORY I=%d MISSING IXATTR FLAG", 187 inp->i_number); 188 if (preen || reply("CORRECT") == 1) { 189 dp->di_cflags |= IXATTR; 190 inodirty(); 191 if (preen) 192 (void) printf(" (CORRECTED)\n"); 193 } 194 } 195 dp = &dino; 196 dp->di_size = (u_offset_t)inp->i_isize; 197 (void) memmove((void *)&dp->di_db[0], (void *)&inp->i_blks[0], 198 inp->i_blkssize); 199 init_inodesc(&curino); 200 curino.id_type = DATA; 201 curino.id_func = pass2check; 202 curino.id_number = inp->i_number; 203 curino.id_parent = inp->i_parent; 204 curino.id_fix = DONTKNOW; 205 (void) ckinode(dp, &curino, CKI_TRAVERSE); 206 207 /* 208 * Make sure we mark attrdirs as DFOUND, since they won't 209 * be located during normal scan of standard directories. 210 */ 211 if (curino.id_parent == 0) { 212 dpattr = ginode(inp->i_number); 213 if ((dpattr->di_mode & IFMT) == IFATTRDIR) { 214 for (sci = attrclientinfo; sci != NULL; 215 sci = sci->next) { 216 if (sci->shadow == inp->i_number) { 217 curino.id_parent = 218 sci->clients->client[0]; 219 statemap[inp->i_number] = 220 DFOUND; 221 inp->i_parent = 222 curino.id_parent; 223 } 224 } 225 } 226 } 227 } 228 /* 229 * Now that the parents of all directories have been found, 230 * make another pass to verify the value of .. 231 */ 232 for (inpp = inpsort; inpp < inpend; inpp++) { 233 inp = *inpp; 234 if (inp->i_parent == 0 || inp->i_isize == 0) 235 continue; 236 /* 237 * There are only directories in inpsort[], so only 238 * directory-related states need to be checked. There 239 * should never be any flags associated with USTATE. 240 */ 241 if ((statemap[inp->i_number] & (STMASK | INCLEAR)) == DCLEAR || 242 statemap[inp->i_number] == USTATE) { 243 continue; 244 } 245 if (statemap[inp->i_parent] == DFOUND && 246 S_IS_DUNFOUND(statemap[inp->i_number])) { 247 statemap[inp->i_number] = DFOUND | 248 (statemap[inp->i_number] & INCLEAR); 249 } 250 if (inp->i_dotdot == inp->i_parent || 251 inp->i_dotdot == (fsck_ino_t)-1) { 252 continue; 253 } 254 if (inp->i_dotdot == 0) { 255 inp->i_dotdot = inp->i_parent; 256 fileerror(inp->i_parent, inp->i_number, 257 "MISSING '..'"); 258 if (reply("FIX") == 0) { 259 iscorrupt = 1; 260 continue; 261 } 262 dp = ginode(inp->i_number); 263 found = 0; 264 dirtype = (dp->di_mode & IFMT); 265 266 /* 267 * See if this is an attrdir that we located in pass1. 268 * i.e. it was on an i_oeftflag of some other inode. 269 * if it isn't found then we have an orphaned attrdir 270 * that needs to be tossed into lost+found. 271 */ 272 if (dirtype == IFATTRDIR) { 273 for (sci = attrclientinfo; 274 sci != NULL; 275 sci = sci->next) { 276 if (sci->shadow == inp->i_number) { 277 inp->i_parent = 278 sci->clients->client[0]; 279 found = 1; 280 } 281 } 282 } 283 284 /* 285 * We've already proven there's no "..", so this 286 * can't create a duplicate. 287 */ 288 if (makeentry(inp->i_number, inp->i_parent, "..")) { 289 290 /* 291 * is it an orphaned attrdir? 292 */ 293 if (dirtype == IFATTRDIR && found == 0) { 294 /* 295 * Throw it into lost+found 296 */ 297 if (linkup(inp->i_number, lfdir, 298 NULL) == 0) { 299 pwarn( 300 "Unable to move attrdir I=%d to lost+found\n", 301 inp->i_number); 302 iscorrupt = 1; 303 } 304 maybe_convert_attrdir_to_dir( 305 inp->i_number); 306 } 307 if (dirtype == IFDIR) { 308 LINK_RANGE(errmsg, 309 lncntp[inp->i_parent], -1); 310 if (errmsg != NULL) { 311 LINK_CLEAR(errmsg, 312 inp->i_parent, IFDIR, 313 &ldesc); 314 if (statemap[inp->i_parent] != 315 USTATE) { 316 /* 317 * iscorrupt is 318 * already set 319 */ 320 continue; 321 } 322 } 323 TRACK_LNCNTP(inp->i_parent, 324 lncntp[inp->i_parent]--); 325 } 326 327 continue; 328 } 329 pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n"); 330 iscorrupt = 1; 331 inp->i_dotdot = (fsck_ino_t)-1; 332 continue; 333 } 334 335 dp2 = ginode(inp->i_parent); 336 337 if ((dp2->di_mode & IFMT) == IFATTRDIR) { 338 continue; 339 } 340 fileerror(inp->i_parent, inp->i_number, 341 "BAD INODE NUMBER FOR '..'"); 342 if (reply("FIX") == 0) { 343 iscorrupt = 1; 344 continue; 345 } 346 347 LINK_RANGE(errmsg, lncntp[inp->i_dotdot], 1); 348 if (errmsg != NULL) { 349 LINK_CLEAR(errmsg, inp->i_dotdot, IFDIR, &ldesc); 350 if (statemap[inp->i_dotdot] != USTATE) { 351 /* iscorrupt is already set */ 352 continue; 353 } 354 } 355 TRACK_LNCNTP(inp->i_dotdot, lncntp[inp->i_dotdot]++); 356 357 LINK_RANGE(errmsg, lncntp[inp->i_parent], -1); 358 if (errmsg != NULL) { 359 LINK_CLEAR(errmsg, inp->i_parent, IFDIR, &ldesc); 360 if (statemap[inp->i_parent] != USTATE) { 361 /* iscorrupt is already set */ 362 continue; 363 } 364 } 365 TRACK_LNCNTP(inp->i_parent, lncntp[inp->i_parent]--); 366 367 inp->i_dotdot = inp->i_parent; 368 (void) changeino(inp->i_number, "..", inp->i_parent); 369 } 370 /* 371 * Mark all the directories that can be found from the root. 372 */ 373 propagate(); 374 } 375 376 /* 377 * Sanity-check a single directory entry. Which entry is being 378 * examined is tracked via idesc->id_entryno. There are two 379 * special ones, 0 (.) and 1 (..). Those have to exist in order 380 * in the first two locations in the directory, and have the usual 381 * properties. All other entries have to not be for either of 382 * the special two, and the inode they reference has to be 383 * reasonable. 384 * 385 * This is only called from dirscan(), which looks for the 386 * ALTERED flag after each invocation. If it finds it, the 387 * relevant buffer gets pushed out, so we don't have to worry 388 * about it here. 389 */ 390 #define PASS2B_PROMPT "REMOVE DIRECTORY ENTRY FROM I=%d" 391 392 static int 393 pass2check(struct inodesc *idesc) 394 { 395 struct direct *dirp = idesc->id_dirp; 396 struct inodesc ldesc; 397 struct inoinfo *inp; 398 short reclen, entrysize; 399 int ret = 0; 400 int act, update_lncntp; 401 struct dinode *dp, *pdirp, *attrdirp; 402 caddr_t errmsg; 403 struct direct proto; 404 char namebuf[MAXPATHLEN + 1]; 405 char pathbuf[MAXPATHLEN + 1]; 406 int isattr; 407 int pdirtype; 408 int breakout = 0; 409 int dontreconnect; 410 411 if (idesc->id_entryno != 0) 412 goto chk1; 413 /* 414 * check for "." 415 */ 416 if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") == 0) { 417 if (dirp->d_ino != idesc->id_number) { 418 direrror(idesc->id_number, "BAD INODE NUMBER FOR '.'"); 419 dirp->d_ino = idesc->id_number; 420 if (reply("FIX") == 1) { 421 ret |= ALTERED; 422 } else { 423 iscorrupt = 1; 424 } 425 } 426 goto chk1; 427 } 428 /* 429 * Build up a new one, and make sure there's room to put 430 * it where it belongs. 431 */ 432 direrror(idesc->id_number, "MISSING '.'"); 433 proto.d_ino = idesc->id_number; 434 proto.d_namlen = 1; 435 (void) strcpy(proto.d_name, "."); 436 entrysize = DIRSIZ(&proto); 437 if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") != 0) { 438 pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n", 439 dirp->d_name); 440 iscorrupt = 1; 441 } else if ((int)dirp->d_reclen < entrysize) { 442 pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '.'\n"); 443 iscorrupt = 1; 444 } else if ((int)dirp->d_reclen < 2 * entrysize) { 445 /* 446 * No room for another entry after us ("." is the 447 * smallest entry you can have), so just put all 448 * of the old entry's space into the new entry. 449 * 450 * Because we don't touch id_entryno, we end up going 451 * through the chk2 tests as well. 452 */ 453 proto.d_reclen = dirp->d_reclen; 454 (void) memmove((void *)dirp, (void *)&proto, 455 (size_t)entrysize); 456 if (reply("FIX") == 1) { 457 ret |= ALTERED; 458 } else { 459 iscorrupt = 1; 460 } 461 } else { 462 /* 463 * There's enough room for an entire additional entry 464 * after this, so create the "." entry and follow it 465 * with an empty entry that covers the rest of the 466 * space. 467 * 468 * The increment of id_entryno means we'll skip the 469 * "." case of chk1, doing the ".." tests instead. 470 * Since we know that there's not a ".." where it 471 * should be (because we just created an empty entry 472 * there), that's the best way of getting it recreated 473 * as well. 474 */ 475 reclen = dirp->d_reclen - entrysize; 476 proto.d_reclen = entrysize; 477 (void) memmove((void *)dirp, (void *)&proto, 478 (size_t)entrysize); 479 idesc->id_entryno++; 480 /* 481 * Make sure the link count is in range before updating 482 * it. This makes the assumption that the link count 483 * for this inode included one for ".", even though 484 * there wasn't a "." entry. Even if that's not true, 485 * it's a reasonable working hypothesis, and the link 486 * count verification done in pass4 will fix it for 487 * us anyway. 488 */ 489 LINK_RANGE(errmsg, lncntp[dirp->d_ino], -1); 490 if (errmsg != NULL) { 491 LINK_CLEAR(errmsg, dirp->d_ino, IFDIR, &ldesc); 492 if (statemap[dirp->d_ino] == USTATE) { 493 /* 494 * The inode got zapped, so reset the 495 * directory entry. Extend it to also 496 * cover the space we were going to make 497 * into a new entry. 498 */ 499 dirp->d_ino = 0; 500 dirp->d_reclen += reclen; 501 ret |= ALTERED; 502 return (ret); 503 } 504 } 505 506 /* 507 * Create the new empty entry. 508 */ 509 /* LINTED pointer cast alignment (entrysize is valid) */ 510 dirp = (struct direct *)((char *)(dirp) + entrysize); 511 (void) memset((void *)dirp, 0, (size_t)reclen); 512 dirp->d_reclen = reclen; 513 514 /* 515 * Did the user want us to create a new "."? This 516 * query assumes that the direrror(MISSING) was the 517 * last thing printed, so if the LINK_RANGE() check 518 * fails, it can't pass through here. 519 */ 520 if (reply("FIX") == 1) { 521 TRACK_LNCNTP(idesc->id_number, 522 lncntp[idesc->id_number]--); 523 ret |= ALTERED; 524 } else { 525 iscorrupt = 1; 526 } 527 } 528 529 /* 530 * XXX The next few lines are needed whether we're processing "." 531 * or "..". However, there are some extra steps still needed 532 * for the former, hence the big block of code for 533 * id_entryno == 0. Alternatively, there could be a label just 534 * before this comment, and everything through the end of that 535 * block moved there. In some ways, that might make the 536 * control flow more logical (factoring out to separate functions 537 * would be even better). 538 */ 539 540 chk1: 541 if (idesc->id_entryno > 1) 542 goto chk2; 543 inp = getinoinfo(idesc->id_number); 544 if (inp == NULL) { 545 /* 546 * This is a can't-happen, since inodes get cached before 547 * we get called on them. 548 */ 549 errexit("pass2check got NULL from getinoinfo at chk1 I=%d\n", 550 idesc->id_number); 551 } 552 proto.d_ino = inp->i_parent; 553 proto.d_namlen = 2; 554 (void) strcpy(proto.d_name, ".."); 555 entrysize = DIRSIZ(&proto); 556 if (idesc->id_entryno == 0) { 557 /* 558 * We may not actually need to split things up, but if 559 * there's room to do so, we should, as that implies 560 * that the "." entry is larger than it is supposed 561 * to be, and therefore there's something wrong, albeit 562 * possibly harmlessly so. 563 */ 564 reclen = DIRSIZ(dirp); 565 if ((int)dirp->d_reclen < reclen + entrysize) { 566 /* 567 * Not enough room for inserting a ".." after 568 * the "." entry. 569 */ 570 goto chk2; 571 } 572 /* 573 * There's enough room for an entire additional entry 574 * after "."'s, so split it up. There's no reason "." 575 * should be bigger than the minimum, so shrink it to 576 * fit, too. Since by the time we're done with this 577 * part, dirp will be pointing at where ".." should be, 578 * update id_entryno to show that that's the entry 579 * we're on. 580 */ 581 proto.d_reclen = dirp->d_reclen - reclen; 582 dirp->d_reclen = reclen; 583 idesc->id_entryno++; 584 if (dirp->d_ino > 0 && dirp->d_ino <= maxino) { 585 /* 586 * Account for the link to ourselves. 587 */ 588 LINK_RANGE(errmsg, lncntp[dirp->d_ino], -1); 589 if (errmsg != NULL) { 590 LINK_CLEAR(errmsg, dirp->d_ino, IFDIR, &ldesc); 591 if (statemap[dirp->d_ino] == USTATE) { 592 /* 593 * We were going to split the entry 594 * up, but the link count overflowed. 595 * Since we got rid of the inode, 596 * we need to also zap the directory 597 * entry, and restoring the original 598 * state of things is the least-bad 599 * result. 600 */ 601 dirp->d_ino = 0; 602 dirp->d_reclen += proto.d_reclen; 603 ret |= ALTERED; 604 return (ret); 605 } 606 } 607 TRACK_LNCNTP(dirp->d_ino, lncntp[dirp->d_ino]--); 608 /* 609 * Make sure the new entry doesn't get interpreted 610 * as having actual content. 611 */ 612 /* LINTED pointer cast alignment (reclen is valid) */ 613 dirp = (struct direct *)((char *)(dirp) + reclen); 614 (void) memset((void *)dirp, 0, (size_t)proto.d_reclen); 615 dirp->d_reclen = proto.d_reclen; 616 } else { 617 /* 618 * Everything was fine, up until we realized that 619 * the indicated inode was impossible. By clearing 620 * d_ino here, we'll trigger the recreation of it 621 * down below, using i_parent. Unlike the other 622 * half of this if(), we're everything so it shows 623 * that we're still on the "." entry. 624 */ 625 fileerror(idesc->id_number, dirp->d_ino, 626 "I OUT OF RANGE"); 627 dirp->d_ino = 0; 628 if (reply("FIX") == 1) { 629 ret |= ALTERED; 630 } else { 631 iscorrupt = 1; 632 } 633 } 634 } 635 /* 636 * Record this ".." inode, but only if we haven't seen one before. 637 * If this isn't the first, it'll get cleared below, and so we 638 * want to remember the entry that'll still be around later. 639 */ 640 if (dirp->d_ino != 0 && inp->i_dotdot == 0 && 641 strcmp(dirp->d_name, "..") == 0) { 642 inp->i_dotdot = dirp->d_ino; 643 goto chk2; 644 } 645 if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") != 0) { 646 fileerror(inp->i_parent, idesc->id_number, "MISSING '..'"); 647 pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n", 648 dirp->d_name); 649 iscorrupt = 1; 650 inp->i_dotdot = (fsck_ino_t)-1; 651 } else if ((int)dirp->d_reclen < entrysize) { 652 fileerror(inp->i_parent, idesc->id_number, "MISSING '..'"); 653 pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n"); 654 /* XXX Same consideration as immediately above. */ 655 iscorrupt = 1; 656 inp->i_dotdot = (fsck_ino_t)-1; 657 } else if (inp->i_parent != 0) { 658 /* 659 * We know the parent, so fix now. 660 */ 661 proto.d_ino = inp->i_dotdot = inp->i_parent; 662 fileerror(inp->i_parent, idesc->id_number, "MISSING '..'"); 663 /* 664 * Lint won't be quiet about d_reclen being set but not 665 * used. It apparently doesn't understand the implications 666 * of calling memmove(), and won't believe us that it's ok. 667 */ 668 proto.d_reclen = dirp->d_reclen; 669 (void) memmove((void *)dirp, (void *)&proto, 670 (size_t)entrysize); 671 if (reply("FIX") == 1) { 672 ret |= ALTERED; 673 } else { 674 iscorrupt = 1; 675 } 676 } else if (inp->i_number == UFSROOTINO) { 677 /* 678 * Always know parent of root inode, so fix now. 679 */ 680 proto.d_ino = inp->i_dotdot = inp->i_parent = UFSROOTINO; 681 fileerror(inp->i_parent, idesc->id_number, "MISSING '..'"); 682 /* 683 * Lint won't be quiet about d_reclen being set but not 684 * used. It apparently doesn't understand the implications 685 * of calling memmove(), and won't believe us that it's ok. 686 */ 687 proto.d_reclen = dirp->d_reclen; 688 (void) memmove((void *)dirp, (void *)&proto, (size_t)entrysize); 689 if (reply("FIX") == 1) { 690 ret |= ALTERED; 691 } else { 692 iscorrupt = 1; 693 } 694 } 695 idesc->id_entryno++; 696 if (dirp->d_ino != 0) { 697 LINK_RANGE(errmsg, lncntp[dirp->d_ino], -1); 698 if (errmsg != NULL) { 699 LINK_CLEAR(errmsg, dirp->d_ino, IFDIR, &ldesc); 700 if (statemap[dirp->d_ino] == USTATE) { 701 dirp->d_ino = 0; 702 ret |= ALTERED; 703 } 704 } 705 TRACK_LNCNTP(dirp->d_ino, lncntp[dirp->d_ino]--); 706 } 707 return (ret|KEEPON); 708 chk2: 709 if (dirp->d_ino == 0) 710 return (ret|KEEPON); 711 if (dirp->d_namlen <= 2 && 712 dirp->d_name[0] == '.' && 713 idesc->id_entryno >= 2) { 714 if (dirp->d_namlen == 1) { 715 direrror(idesc->id_number, "EXTRA '.' ENTRY"); 716 dirp->d_ino = 0; 717 if (reply("FIX") == 1) { 718 ret |= ALTERED; 719 } else { 720 iscorrupt = 1; 721 } 722 return (KEEPON | ret); 723 } 724 if (dirp->d_name[1] == '.') { 725 direrror(idesc->id_number, "EXTRA '..' ENTRY"); 726 dirp->d_ino = 0; 727 if (reply("FIX") == 1) { 728 ret |= ALTERED; 729 } else { 730 iscorrupt = 1; 731 } 732 return (KEEPON | ret); 733 } 734 } 735 /* 736 * Because of this increment, all tests for skipping . and .. 737 * below are ``> 2'', not ``> 1'' as would logically be expected. 738 */ 739 idesc->id_entryno++; 740 act = -1; 741 /* 742 * The obvious check would be for d_ino < UFSROOTINO. However, 743 * 1 is a valid inode number. Although it isn't currently used, 744 * as it was once the bad block list, there's nothing to prevent 745 * it from acquiring a new purpose in the future. So, don't 746 * arbitrarily disallow it. We don't test for <= zero, because 747 * d_ino is unsigned. 748 */ 749 update_lncntp = 0; 750 if (dirp->d_ino > maxino || dirp->d_ino == 0) { 751 fileerror(idesc->id_number, dirp->d_ino, "I OUT OF RANGE"); 752 act = (reply(PASS2B_PROMPT, idesc->id_number) == 1); 753 } else { 754 again: 755 update_lncntp = 0; 756 switch (statemap[dirp->d_ino] & ~(INDELAYD)) { 757 case USTATE: 758 if (idesc->id_entryno <= 2) 759 break; 760 fileerror(idesc->id_number, dirp->d_ino, "UNALLOCATED"); 761 act = (reply(PASS2B_PROMPT, idesc->id_number) == 1); 762 break; 763 764 case DCLEAR: 765 case FCLEAR: 766 case SCLEAR: 767 if (idesc->id_entryno <= 2) 768 break; 769 dp = ginode(dirp->d_ino); 770 if (statemap[dirp->d_ino] == DCLEAR) { 771 errmsg = ((dp->di_mode & IFMT) == IFATTRDIR) ? 772 "REFERENCE TO ZERO LENGTH ATTRIBUTE DIRECTORY" : 773 "REFERENCE TO ZERO LENGTH DIRECTORY"; 774 inp = getinoinfo(dirp->d_ino); 775 if (inp == NULL) { 776 /* 777 * The inode doesn't exist, as all 778 * should be cached by now. This 779 * gets caught by the range check 780 * above, and so it is a can't-happen 781 * at this point. 782 */ 783 errexit("pass2check found a zero-len " 784 "reference to bad I=%d\n", 785 dirp->d_ino); 786 } 787 if (inp->i_parent != 0) { 788 (void) printf( 789 "Multiple links to I=%d, link counts wrong, rerun fsck\n", 790 inp->i_number); 791 iscorrupt = 1; 792 } 793 } else if (statemap[dirp->d_ino] == SCLEAR) { 794 /* 795 * In theory, this is a can't-happen, 796 * because shadows don't appear in directory 797 * entries. However, an inode might've 798 * been reused without a stale directory 799 * entry having been cleared, so check 800 * for it just in case. We'll check for 801 * the no-dir-entry shadows in pass3b(). 802 */ 803 errmsg = "ZERO LENGTH SHADOW"; 804 } else { 805 errmsg = "DUP/BAD"; 806 } 807 fileerror(idesc->id_number, dirp->d_ino, errmsg); 808 if ((act = reply(PASS2B_PROMPT, idesc->id_number)) == 1) 809 break; 810 /* 811 * Not doing anything about it, so just try 812 * again as whatever the base type was. 813 * 814 * fileerror() invalidated dp. Lint thinks this 815 * is unnecessary, but we know better. 816 */ 817 dp = ginode(dirp->d_ino); 818 statemap[dirp->d_ino] &= STMASK; 819 TRACK_LNCNTP(dirp->d_ino, lncntp[dirp->d_ino] = 0); 820 goto again; 821 822 case DSTATE: 823 case DZLINK: 824 if (statemap[idesc->id_number] == DFOUND) { 825 statemap[dirp->d_ino] = DFOUND; 826 } 827 /* FALLTHROUGH */ 828 829 case DFOUND: 830 /* 831 * This is encouraging the best-practice of not 832 * hard-linking directories. It's legal (see POSIX), 833 * but not a good idea. So, don't consider it an 834 * instance of corruption, but offer to nuke it. 835 */ 836 inp = getinoinfo(dirp->d_ino); 837 if (inp == NULL) { 838 /* 839 * Same can't-happen argument as in the 840 * zero-len case above. 841 */ 842 errexit("pass2check found bad reference to " 843 "hard-linked directory I=%d\n", 844 dirp->d_ino); 845 } 846 dp = ginode(idesc->id_number); 847 if (inp->i_parent != 0 && idesc->id_entryno > 2 && 848 ((dp->di_mode & IFMT) != IFATTRDIR)) { 849 /* 850 * XXX For nested dirs, this can report 851 * the same name for both paths. 852 */ 853 getpathname(pathbuf, idesc->id_number, 854 dirp->d_ino); 855 getpathname(namebuf, dirp->d_ino, dirp->d_ino); 856 pwarn( 857 "%s IS AN EXTRANEOUS HARD LINK TO DIRECTORY %s\n", 858 pathbuf, namebuf); 859 if (preen) { 860 (void) printf(" (IGNORED)\n"); 861 } else { 862 act = reply(PASS2B_PROMPT, 863 idesc->id_number); 864 if (act == 1) { 865 update_lncntp = 1; 866 broke_dir_link = 1; 867 break; 868 } 869 } 870 } 871 872 if ((idesc->id_entryno > 2) && 873 (inp->i_extattr != idesc->id_number)) { 874 inp->i_parent = idesc->id_number; 875 } 876 /* FALLTHROUGH */ 877 878 case FSTATE: 879 case FZLINK: 880 /* 881 * There's nothing to do for normal file-like 882 * things. Extended attributes come through 883 * here as well, though, and for them, .. may point 884 * to a file. In this situation we don't want 885 * to decrement link count as it was already 886 * decremented when the entry was seen in the 887 * directory it actually lives in. 888 */ 889 pdirp = ginode(idesc->id_number); 890 pdirtype = (pdirp->di_mode & IFMT); 891 dp = ginode(dirp->d_ino); 892 isattr = (dp->di_cflags & IXATTR); 893 act = -1; 894 if (pdirtype == IFATTRDIR && 895 (strcmp(dirp->d_name, "..") == 0)) { 896 dontreconnect = 0; 897 if (dp->di_oeftflag != 0) { 898 attrdirp = ginode(dp->di_oeftflag); 899 900 /* 901 * is it really an attrdir? 902 * if so, then don't do anything. 903 */ 904 905 if ((attrdirp->di_mode & IFMT) == 906 IFATTRDIR) 907 dontreconnect = 1; 908 dp = ginode(dirp->d_ino); 909 } 910 /* 911 * Rare corner case - the attrdir's .. 912 * points to the attrdir itself. 913 */ 914 if (dirp->d_ino == idesc->id_number) { 915 dontreconnect = 1; 916 TRACK_LNCNTP(idesc->id_number, 917 lncntp[idesc->id_number]--); 918 } 919 /* 920 * Lets see if we have an orphaned attrdir 921 * that thinks it belongs to this file. 922 * Only re-connect it if the current 923 * attrdir is 0 or not an attrdir. 924 */ 925 if ((dp->di_oeftflag != idesc->id_number) && 926 (dontreconnect == 0)) { 927 fileerror(idesc->id_number, 928 dirp->d_ino, 929 "Attribute directory I=%d not " 930 "attached to file I=%d\n", 931 idesc->id_number, dirp->d_ino); 932 if ((act = reply("FIX")) == 1) { 933 dp = ginode(dirp->d_ino); 934 if (debug) 935 (void) printf( 936 "debug: changing i=%d's oeft from %d ", 937 dirp->d_ino, 938 dp->di_oeftflag); 939 dp->di_oeftflag = 940 idesc->id_number; 941 if (debug) 942 (void) printf("to %d\n", 943 dp->di_oeftflag); 944 inodirty(); 945 registershadowclient( 946 idesc->id_number, 947 dirp->d_ino, 948 &attrclientinfo); 949 } 950 dp = ginode(dirp->d_ino); 951 } 952 953 /* 954 * This can only be true if we've modified 955 * an inode/xattr connection, and we 956 * don't keep track of those in the link 957 * counts. So, skipping the checks just 958 * after this is not a problem. 959 */ 960 if (act > 0) 961 return (KEEPON | ALTERED); 962 963 /* 964 * Don't screw up link counts for directories. 965 * If we aren't careful we can perform 966 * an extra decrement, since the .. of 967 * an attrdir could be either a file or a 968 * directory. If it's a file then its link 969 * should be correct after it is seen when the 970 * directory it lives in scanned. 971 */ 972 if ((pdirtype == IFATTRDIR) && 973 ((dp->di_mode & IFMT) == IFDIR)) 974 breakout = 1; 975 if ((dp->di_mode & IFMT) != IFDIR) 976 breakout = 1; 977 978 } else if ((pdirtype != IFATTRDIR) || 979 (strcmp(dirp->d_name, ".") != 0)) { 980 if ((pdirtype == IFDIR) && isattr) { 981 fileerror(idesc->id_number, 982 dirp->d_ino, 983 "File should NOT be marked as " 984 "extended attribute\n"); 985 if ((act = reply("FIX")) == 1) { 986 dp = ginode(dirp->d_ino); 987 if (debug) 988 (void) printf( 989 "changing i=%d's cflags from 0x%x to ", 990 dirp->d_ino, 991 dp->di_cflags); 992 993 dp->di_cflags &= ~IXATTR; 994 if (debug) 995 (void) printf("0x%x\n", 996 dp->di_cflags); 997 inodirty(); 998 if ((dp->di_mode & IFMT) == 999 IFATTRDIR) { 1000 dp->di_mode &= 1001 ~IFATTRDIR; 1002 dp->di_mode |= IFDIR; 1003 inodirty(); 1004 pdirp = ginode( 1005 idesc->id_number); 1006 if (pdirp->di_oeftflag 1007 != 0) { 1008 pdirp->di_oeftflag = 0; 1009 inodirty(); 1010 } 1011 } 1012 } 1013 } else { 1014 if (pdirtype == IFATTRDIR && 1015 (isattr == 0)) { 1016 fileerror(idesc->id_number, 1017 dirp->d_ino, 1018 "File should BE marked as " 1019 "extended attribute\n"); 1020 if ((act = reply("FIX")) == 1) { 1021 dp = ginode( 1022 dirp->d_ino); 1023 dp->di_cflags |= IXATTR; 1024 /* 1025 * Make sure it's a file 1026 * while we're at it. 1027 */ 1028 dp->di_mode &= ~IFMT; 1029 dp->di_mode |= IFREG; 1030 inodirty(); 1031 } 1032 } 1033 } 1034 1035 } 1036 if (breakout == 0 || dontreconnect == 0) { 1037 TRACK_LNCNTP(dirp->d_ino, 1038 lncntp[dirp->d_ino]--); 1039 if (act > 0) 1040 return (KEEPON | ALTERED); 1041 } 1042 break; 1043 1044 case SSTATE: 1045 errmsg = "ACL IN DIRECTORY"; 1046 fileerror(idesc->id_number, dirp->d_ino, errmsg); 1047 act = (reply(PASS2B_PROMPT, idesc->id_number) == 1); 1048 break; 1049 1050 default: 1051 errexit("BAD STATE 0x%x FOR INODE I=%d", 1052 statemap[dirp->d_ino], dirp->d_ino); 1053 } 1054 } 1055 1056 if (act == 0) { 1057 iscorrupt = 1; 1058 } 1059 1060 if (act <= 0) 1061 return (ret|KEEPON); 1062 1063 if (update_lncntp) { 1064 LINK_RANGE(errmsg, lncntp[idesc->id_number], 1); 1065 if (errmsg != NULL) { 1066 LINK_CLEAR(errmsg, idesc->id_number, IFDIR, &ldesc); 1067 if (statemap[idesc->id_number] == USTATE) { 1068 idesc->id_number = 0; 1069 ret |= ALTERED; 1070 } 1071 } 1072 TRACK_LNCNTP(idesc->id_number, lncntp[idesc->id_number]++); 1073 } 1074 1075 dirp->d_ino = 0; 1076 1077 return (ret|KEEPON|ALTERED); 1078 } 1079 1080 #undef PASS2B_PROMPT 1081 1082 /* 1083 * Routine to sort disk blocks. 1084 */ 1085 static int 1086 blksort(const void *arg1, const void *arg2) 1087 { 1088 const struct inoinfo **inpp1 = (const struct inoinfo **)arg1; 1089 const struct inoinfo **inpp2 = (const struct inoinfo **)arg2; 1090 1091 return ((*inpp1)->i_blks[0] - (*inpp2)->i_blks[0]); 1092 } 1093