|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1980, 1986 The Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms are permitted provided ! 6: * that: (1) source distributions retain this entire copyright notice and ! 7: * comment, and (2) distributions including binaries display the following ! 8: * acknowledgement: ``This product includes software developed by the ! 9: * University of California, Berkeley and its contributors'' in the ! 10: * documentation or other materials provided with the distribution and in ! 11: * all advertising materials mentioning features or use of this software. ! 12: * Neither the name of the University nor the names of its contributors may ! 13: * be used to endorse or promote products derived from this software without ! 14: * specific prior written permission. ! 15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 16: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 17: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 18: */ ! 19: ! 20: #ifndef lint ! 21: static char sccsid[] = "@(#)pass2.c 5.16 (Berkeley) 9/18/90"; ! 22: #endif /* not lint */ ! 23: ! 24: #include <sys/param.h> ! 25: #include <ufs/dinode.h> ! 26: #include <ufs/fs.h> ! 27: #define KERNEL ! 28: #include <ufs/dir.h> ! 29: #undef KERNEL ! 30: #include <stdlib.h> ! 31: #include <string.h> ! 32: #include "fsck.h" ! 33: ! 34: #define MINDIRSIZE (sizeof (struct dirtemplate)) ! 35: ! 36: int pass2check(), blksort(); ! 37: ! 38: pass2() ! 39: { ! 40: register struct dinode *dp; ! 41: register struct inoinfo **inpp, *inp; ! 42: struct inoinfo **inpend; ! 43: struct inodesc curino; ! 44: struct dinode dino; ! 45: char pathbuf[MAXPATHLEN + 1]; ! 46: ! 47: switch (statemap[ROOTINO]) { ! 48: ! 49: case USTATE: ! 50: pfatal("ROOT INODE UNALLOCATED"); ! 51: if (reply("ALLOCATE") == 0) ! 52: errexit(""); ! 53: if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO) ! 54: errexit("CANNOT ALLOCATE ROOT INODE\n"); ! 55: break; ! 56: ! 57: case DCLEAR: ! 58: pfatal("DUPS/BAD IN ROOT INODE"); ! 59: if (reply("REALLOCATE")) { ! 60: freeino(ROOTINO); ! 61: if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO) ! 62: errexit("CANNOT ALLOCATE ROOT INODE\n"); ! 63: break; ! 64: } ! 65: if (reply("CONTINUE") == 0) ! 66: errexit(""); ! 67: break; ! 68: ! 69: case FSTATE: ! 70: case FCLEAR: ! 71: pfatal("ROOT INODE NOT DIRECTORY"); ! 72: if (reply("REALLOCATE")) { ! 73: freeino(ROOTINO); ! 74: if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO) ! 75: errexit("CANNOT ALLOCATE ROOT INODE\n"); ! 76: break; ! 77: } ! 78: if (reply("FIX") == 0) ! 79: errexit(""); ! 80: dp = ginode(ROOTINO); ! 81: dp->di_mode &= ~IFMT; ! 82: dp->di_mode |= IFDIR; ! 83: inodirty(); ! 84: break; ! 85: ! 86: case DSTATE: ! 87: break; ! 88: ! 89: default: ! 90: errexit("BAD STATE %d FOR ROOT INODE", statemap[ROOTINO]); ! 91: } ! 92: statemap[ROOTINO] = DFOUND; ! 93: /* ! 94: * Sort the directory list into disk block order. ! 95: */ ! 96: qsort((char *)inpsort, (size_t)inplast, sizeof *inpsort, blksort); ! 97: /* ! 98: * Check the integrity of each directory. ! 99: */ ! 100: bzero((char *)&curino, sizeof(struct inodesc)); ! 101: curino.id_type = DATA; ! 102: curino.id_func = pass2check; ! 103: dino.di_mode = IFDIR; ! 104: dp = &dino; ! 105: inpend = &inpsort[inplast]; ! 106: for (inpp = inpsort; inpp < inpend; inpp++) { ! 107: inp = *inpp; ! 108: if (inp->i_isize == 0) ! 109: continue; ! 110: if (inp->i_isize < MINDIRSIZE) { ! 111: direrror(inp->i_number, "DIRECTORY TOO SHORT"); ! 112: inp->i_isize = roundup(MINDIRSIZE, DIRBLKSIZ); ! 113: if (reply("FIX") == 1) { ! 114: dp = ginode(inp->i_number); ! 115: dp->di_size = inp->i_isize; ! 116: inodirty(); ! 117: dp = &dino; ! 118: } ! 119: } else if ((inp->i_isize & (DIRBLKSIZ - 1)) != 0) { ! 120: getpathname(pathbuf, inp->i_number, inp->i_number); ! 121: pwarn("DIRECTORY %s: LENGTH %d NOT MULTIPLE OF %d", ! 122: pathbuf, inp->i_isize, DIRBLKSIZ); ! 123: if (preen) ! 124: printf(" (ADJUSTED)\n"); ! 125: inp->i_isize = roundup(inp->i_isize, DIRBLKSIZ); ! 126: if (preen || reply("ADJUST") == 1) { ! 127: dp = ginode(inp->i_number); ! 128: dp->di_size = roundup(inp->i_isize, DIRBLKSIZ); ! 129: inodirty(); ! 130: dp = &dino; ! 131: } ! 132: } ! 133: dp->di_size = inp->i_isize; ! 134: bcopy((char *)&inp->i_blks[0], (char *)&dp->di_db[0], ! 135: (size_t)inp->i_numblks); ! 136: curino.id_number = inp->i_number; ! 137: curino.id_parent = inp->i_parent; ! 138: (void)ckinode(dp, &curino); ! 139: } ! 140: /* ! 141: * Now that the parents of all directories have been found, ! 142: * make another pass to verify the value of `..' ! 143: */ ! 144: for (inpp = inpsort; inpp < inpend; inpp++) { ! 145: inp = *inpp; ! 146: if (inp->i_parent == 0 || inp->i_isize == 0) ! 147: continue; ! 148: if (statemap[inp->i_parent] == DFOUND && ! 149: statemap[inp->i_number] == DSTATE) ! 150: statemap[inp->i_number] = DFOUND; ! 151: if (inp->i_dotdot == inp->i_parent || ! 152: inp->i_dotdot == (ino_t)-1) ! 153: continue; ! 154: if (inp->i_dotdot == 0) { ! 155: inp->i_dotdot = inp->i_parent; ! 156: fileerror(inp->i_parent, inp->i_number, "MISSING '..'"); ! 157: if (reply("FIX") == 0) ! 158: continue; ! 159: (void)makeentry(inp->i_number, inp->i_parent, ".."); ! 160: lncntp[inp->i_parent]--; ! 161: continue; ! 162: } ! 163: fileerror(inp->i_parent, inp->i_number, ! 164: "BAD INODE NUMBER FOR '..'"); ! 165: if (reply("FIX") == 0) ! 166: continue; ! 167: lncntp[inp->i_dotdot]++; ! 168: lncntp[inp->i_parent]--; ! 169: inp->i_dotdot = inp->i_parent; ! 170: (void)changeino(inp->i_number, "..", inp->i_parent); ! 171: } ! 172: /* ! 173: * Mark all the directories that can be found from the root. ! 174: */ ! 175: propagate(); ! 176: } ! 177: ! 178: pass2check(idesc) ! 179: struct inodesc *idesc; ! 180: { ! 181: register struct direct *dirp = idesc->id_dirp; ! 182: register struct inoinfo *inp; ! 183: int n, entrysize, ret = 0; ! 184: struct dinode *dp; ! 185: char *errmsg; ! 186: struct direct proto; ! 187: char namebuf[MAXPATHLEN + 1]; ! 188: char pathbuf[MAXPATHLEN + 1]; ! 189: ! 190: /* ! 191: * check for "." ! 192: */ ! 193: if (idesc->id_entryno != 0) ! 194: goto chk1; ! 195: if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") == 0) { ! 196: if (dirp->d_ino != idesc->id_number) { ! 197: direrror(idesc->id_number, "BAD INODE NUMBER FOR '.'"); ! 198: dirp->d_ino = idesc->id_number; ! 199: if (reply("FIX") == 1) ! 200: ret |= ALTERED; ! 201: } ! 202: goto chk1; ! 203: } ! 204: direrror(idesc->id_number, "MISSING '.'"); ! 205: proto.d_ino = idesc->id_number; ! 206: proto.d_namlen = 1; ! 207: (void)strcpy(proto.d_name, "."); ! 208: entrysize = DIRSIZ(&proto); ! 209: if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") != 0) { ! 210: pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n", ! 211: dirp->d_name); ! 212: } else if (dirp->d_reclen < entrysize) { ! 213: pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '.'\n"); ! 214: } else if (dirp->d_reclen < 2 * entrysize) { ! 215: proto.d_reclen = dirp->d_reclen; ! 216: bcopy((char *)&proto, (char *)dirp, (size_t)entrysize); ! 217: if (reply("FIX") == 1) ! 218: ret |= ALTERED; ! 219: } else { ! 220: n = dirp->d_reclen - entrysize; ! 221: proto.d_reclen = entrysize; ! 222: bcopy((char *)&proto, (char *)dirp, (size_t)entrysize); ! 223: idesc->id_entryno++; ! 224: lncntp[dirp->d_ino]--; ! 225: dirp = (struct direct *)((char *)(dirp) + entrysize); ! 226: bzero((char *)dirp, (size_t)n); ! 227: dirp->d_reclen = n; ! 228: if (reply("FIX") == 1) ! 229: ret |= ALTERED; ! 230: } ! 231: chk1: ! 232: if (idesc->id_entryno > 1) ! 233: goto chk2; ! 234: inp = getinoinfo(idesc->id_number); ! 235: proto.d_ino = inp->i_parent; ! 236: proto.d_namlen = 2; ! 237: (void)strcpy(proto.d_name, ".."); ! 238: entrysize = DIRSIZ(&proto); ! 239: if (idesc->id_entryno == 0) { ! 240: n = DIRSIZ(dirp); ! 241: if (dirp->d_reclen < n + entrysize) ! 242: goto chk2; ! 243: proto.d_reclen = dirp->d_reclen - n; ! 244: dirp->d_reclen = n; ! 245: idesc->id_entryno++; ! 246: lncntp[dirp->d_ino]--; ! 247: dirp = (struct direct *)((char *)(dirp) + n); ! 248: bzero((char *)dirp, (size_t)proto.d_reclen); ! 249: dirp->d_reclen = proto.d_reclen; ! 250: } ! 251: if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") == 0) { ! 252: inp->i_dotdot = dirp->d_ino; ! 253: goto chk2; ! 254: } ! 255: if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") != 0) { ! 256: fileerror(inp->i_parent, idesc->id_number, "MISSING '..'"); ! 257: pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n", ! 258: dirp->d_name); ! 259: inp->i_dotdot = (ino_t)-1; ! 260: } else if (dirp->d_reclen < entrysize) { ! 261: fileerror(inp->i_parent, idesc->id_number, "MISSING '..'"); ! 262: pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n"); ! 263: inp->i_dotdot = (ino_t)-1; ! 264: } else if (inp->i_parent != 0) { ! 265: /* ! 266: * We know the parent, so fix now. ! 267: */ ! 268: inp->i_dotdot = inp->i_parent; ! 269: fileerror(inp->i_parent, idesc->id_number, "MISSING '..'"); ! 270: proto.d_reclen = dirp->d_reclen; ! 271: bcopy((char *)&proto, (char *)dirp, (size_t)entrysize); ! 272: if (reply("FIX") == 1) ! 273: ret |= ALTERED; ! 274: } ! 275: idesc->id_entryno++; ! 276: if (dirp->d_ino != 0) ! 277: lncntp[dirp->d_ino]--; ! 278: return (ret|KEEPON); ! 279: chk2: ! 280: if (dirp->d_ino == 0) ! 281: return (ret|KEEPON); ! 282: if (dirp->d_namlen <= 2 && ! 283: dirp->d_name[0] == '.' && ! 284: idesc->id_entryno >= 2) { ! 285: if (dirp->d_namlen == 1) { ! 286: direrror(idesc->id_number, "EXTRA '.' ENTRY"); ! 287: dirp->d_ino = 0; ! 288: if (reply("FIX") == 1) ! 289: ret |= ALTERED; ! 290: return (KEEPON | ret); ! 291: } ! 292: if (dirp->d_name[1] == '.') { ! 293: direrror(idesc->id_number, "EXTRA '..' ENTRY"); ! 294: dirp->d_ino = 0; ! 295: if (reply("FIX") == 1) ! 296: ret |= ALTERED; ! 297: return (KEEPON | ret); ! 298: } ! 299: } ! 300: idesc->id_entryno++; ! 301: n = 0; ! 302: if (dirp->d_ino > maxino || dirp->d_ino <= 0) { ! 303: fileerror(idesc->id_number, dirp->d_ino, "I OUT OF RANGE"); ! 304: n = reply("REMOVE"); ! 305: } else { ! 306: again: ! 307: switch (statemap[dirp->d_ino]) { ! 308: case USTATE: ! 309: if (idesc->id_entryno <= 2) ! 310: break; ! 311: fileerror(idesc->id_number, dirp->d_ino, "UNALLOCATED"); ! 312: n = reply("REMOVE"); ! 313: break; ! 314: ! 315: case DCLEAR: ! 316: case FCLEAR: ! 317: if (idesc->id_entryno <= 2) ! 318: break; ! 319: if (statemap[dirp->d_ino] == DCLEAR) ! 320: errmsg = "ZERO LENGTH DIRECTORY"; ! 321: else ! 322: errmsg = "DUP/BAD"; ! 323: fileerror(idesc->id_number, dirp->d_ino, errmsg); ! 324: if ((n = reply("REMOVE")) == 1) ! 325: break; ! 326: dp = ginode(dirp->d_ino); ! 327: statemap[dirp->d_ino] = ! 328: (dp->di_mode & IFMT) == IFDIR ? DSTATE : FSTATE; ! 329: lncntp[dirp->d_ino] = dp->di_nlink; ! 330: goto again; ! 331: ! 332: case DSTATE: ! 333: if (statemap[idesc->id_number] == DFOUND) ! 334: statemap[dirp->d_ino] = DFOUND; ! 335: /* fall through */ ! 336: ! 337: case DFOUND: ! 338: inp = getinoinfo(dirp->d_ino); ! 339: if (inp->i_parent != 0 && idesc->id_entryno > 2) { ! 340: getpathname(pathbuf, idesc->id_number, ! 341: idesc->id_number); ! 342: getpathname(namebuf, dirp->d_ino, dirp->d_ino); ! 343: pwarn("%s %s %s\n", pathbuf, ! 344: "IS AN EXTRANEOUS HARD LINK TO DIRECTORY", ! 345: namebuf); ! 346: if (preen) ! 347: printf(" (IGNORED)\n"); ! 348: else if ((n = reply("REMOVE")) == 1) ! 349: break; ! 350: } ! 351: if (idesc->id_entryno > 2) ! 352: inp->i_parent = idesc->id_number; ! 353: /* fall through */ ! 354: ! 355: case FSTATE: ! 356: lncntp[dirp->d_ino]--; ! 357: break; ! 358: ! 359: default: ! 360: errexit("BAD STATE %d FOR INODE I=%d", ! 361: statemap[dirp->d_ino], dirp->d_ino); ! 362: } ! 363: } ! 364: if (n == 0) ! 365: return (ret|KEEPON); ! 366: dirp->d_ino = 0; ! 367: return (ret|KEEPON|ALTERED); ! 368: } ! 369: ! 370: /* ! 371: * Routine to sort disk blocks. ! 372: */ ! 373: blksort(inpp1, inpp2) ! 374: struct inoinfo **inpp1, **inpp2; ! 375: { ! 376: ! 377: return ((*inpp1)->i_blks[0] - (*inpp2)->i_blks[0]); ! 378: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.