1 /* 2 * Copyright (c) 1980, 1986, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #ifndef lint 35 static const char sccsid[] = "@(#)inode.c 8.8 (Berkeley) 4/28/95"; 36 #endif /* not lint */ 37 38 #include <sys/param.h> 39 #include <sys/time.h> 40 41 #include <ufs/ufs/dinode.h> 42 #include <ufs/ufs/dir.h> 43 #include <ufs/ffs/fs.h> 44 45 #include <err.h> 46 #include <pwd.h> 47 #include <string.h> 48 49 #include "fsck.h" 50 51 static ino_t startinum; 52 53 static int iblock __P((struct inodesc *, long ilevel, quad_t isize)); 54 55 int 56 ckinode(dp, idesc) 57 struct dinode *dp; 58 register struct inodesc *idesc; 59 { 60 ufs_daddr_t *ap; 61 long ret, n, ndb, offset; 62 struct dinode dino; 63 quad_t remsize, sizepb; 64 mode_t mode; 65 char pathbuf[MAXPATHLEN + 1]; 66 67 if (idesc->id_fix != IGNORE) 68 idesc->id_fix = DONTKNOW; 69 idesc->id_entryno = 0; 70 idesc->id_filesize = dp->di_size; 71 mode = dp->di_mode & IFMT; 72 if (mode == IFBLK || mode == IFCHR || (mode == IFLNK && 73 (dp->di_size < sblock.fs_maxsymlinklen || dp->di_blocks == 0))) 74 return (KEEPON); 75 dino = *dp; 76 ndb = howmany(dino.di_size, sblock.fs_bsize); 77 for (ap = &dino.di_db[0]; ap < &dino.di_db[NDADDR]; ap++) { 78 if (--ndb == 0 && (offset = blkoff(&sblock, dino.di_size)) != 0) 79 idesc->id_numfrags = 80 numfrags(&sblock, fragroundup(&sblock, offset)); 81 else 82 idesc->id_numfrags = sblock.fs_frag; 83 if (*ap == 0) { 84 if (idesc->id_type == DATA && ndb >= 0) { 85 /* An empty block in a directory XXX */ 86 getpathname(pathbuf, idesc->id_number, 87 idesc->id_number); 88 pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", 89 pathbuf); 90 if (reply("ADJUST LENGTH") == 1) { 91 dp = ginode(idesc->id_number); 92 dp->di_size = (ap - &dino.di_db[0]) * 93 sblock.fs_bsize; 94 printf( 95 "YOU MUST RERUN FSCK AFTERWARDS\n"); 96 rerun = 1; 97 inodirty(); 98 99 } 100 } 101 continue; 102 } 103 idesc->id_blkno = *ap; 104 if (idesc->id_type == ADDR) 105 ret = (*idesc->id_func)(idesc); 106 else 107 ret = dirscan(idesc); 108 if (ret & STOP) 109 return (ret); 110 } 111 idesc->id_numfrags = sblock.fs_frag; 112 remsize = dino.di_size - sblock.fs_bsize * NDADDR; 113 sizepb = sblock.fs_bsize; 114 for (ap = &dino.di_ib[0], n = 1; n <= NIADDR; ap++, n++) { 115 if (*ap) { 116 idesc->id_blkno = *ap; 117 ret = iblock(idesc, n, remsize); 118 if (ret & STOP) 119 return (ret); 120 } else { 121 if (idesc->id_type == DATA && remsize > 0) { 122 /* An empty block in a directory XXX */ 123 getpathname(pathbuf, idesc->id_number, 124 idesc->id_number); 125 pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", 126 pathbuf); 127 if (reply("ADJUST LENGTH") == 1) { 128 dp = ginode(idesc->id_number); 129 dp->di_size -= remsize; 130 remsize = 0; 131 printf( 132 "YOU MUST RERUN FSCK AFTERWARDS\n"); 133 rerun = 1; 134 inodirty(); 135 break; 136 } 137 } 138 } 139 sizepb *= NINDIR(&sblock); 140 remsize -= sizepb; 141 } 142 return (KEEPON); 143 } 144 145 static int 146 iblock(idesc, ilevel, isize) 147 struct inodesc *idesc; 148 long ilevel; 149 quad_t isize; 150 { 151 ufs_daddr_t *ap; 152 ufs_daddr_t *aplim; 153 struct bufarea *bp; 154 int i, n, (*func)(), nif; 155 quad_t sizepb; 156 char buf[BUFSIZ]; 157 char pathbuf[MAXPATHLEN + 1]; 158 struct dinode *dp; 159 160 if (idesc->id_type == ADDR) { 161 func = idesc->id_func; 162 if (((n = (*func)(idesc)) & KEEPON) == 0) 163 return (n); 164 } else 165 func = dirscan; 166 if (chkrange(idesc->id_blkno, idesc->id_numfrags)) 167 return (SKIP); 168 bp = getdatablk(idesc->id_blkno, sblock.fs_bsize); 169 ilevel--; 170 for (sizepb = sblock.fs_bsize, i = 0; i < ilevel; i++) 171 sizepb *= NINDIR(&sblock); 172 nif = howmany(isize , sizepb); 173 if (nif > NINDIR(&sblock)) 174 nif = NINDIR(&sblock); 175 if (idesc->id_func == pass1check && nif < NINDIR(&sblock)) { 176 aplim = &bp->b_un.b_indir[NINDIR(&sblock)]; 177 for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) { 178 if (*ap == 0) 179 continue; 180 (void)sprintf(buf, "PARTIALLY TRUNCATED INODE I=%lu", 181 idesc->id_number); 182 if (dofix(idesc, buf)) { 183 *ap = 0; 184 dirty(bp); 185 } 186 } 187 flush(fswritefd, bp); 188 } 189 aplim = &bp->b_un.b_indir[nif]; 190 for (ap = bp->b_un.b_indir; ap < aplim; ap++) { 191 if (*ap) { 192 idesc->id_blkno = *ap; 193 if (ilevel == 0) 194 n = (*func)(idesc); 195 else 196 n = iblock(idesc, ilevel, isize); 197 if (n & STOP) { 198 bp->b_flags &= ~B_INUSE; 199 return (n); 200 } 201 } else { 202 if (idesc->id_type == DATA && isize > 0) { 203 /* An empty block in a directory XXX */ 204 getpathname(pathbuf, idesc->id_number, 205 idesc->id_number); 206 pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", 207 pathbuf); 208 if (reply("ADJUST LENGTH") == 1) { 209 dp = ginode(idesc->id_number); 210 dp->di_size -= isize; 211 isize = 0; 212 printf( 213 "YOU MUST RERUN FSCK AFTERWARDS\n"); 214 rerun = 1; 215 inodirty(); 216 bp->b_flags &= ~B_INUSE; 217 return(STOP); 218 } 219 } 220 } 221 isize -= sizepb; 222 } 223 bp->b_flags &= ~B_INUSE; 224 return (KEEPON); 225 } 226 227 /* 228 * Check that a block in a legal block number. 229 * Return 0 if in range, 1 if out of range. 230 */ 231 int 232 chkrange(blk, cnt) 233 ufs_daddr_t blk; 234 int cnt; 235 { 236 register int c; 237 238 if ((unsigned)(blk + cnt) > maxfsblock) 239 return (1); 240 c = dtog(&sblock, blk); 241 if (blk < cgdmin(&sblock, c)) { 242 if ((blk + cnt) > cgsblock(&sblock, c)) { 243 if (debug) { 244 printf("blk %ld < cgdmin %ld;", 245 blk, cgdmin(&sblock, c)); 246 printf(" blk + cnt %ld > cgsbase %ld\n", 247 blk + cnt, cgsblock(&sblock, c)); 248 } 249 return (1); 250 } 251 } else { 252 if ((blk + cnt) > cgbase(&sblock, c+1)) { 253 if (debug) { 254 printf("blk %ld >= cgdmin %ld;", 255 blk, cgdmin(&sblock, c)); 256 printf(" blk + cnt %ld > sblock.fs_fpg %ld\n", 257 blk+cnt, sblock.fs_fpg); 258 } 259 return (1); 260 } 261 } 262 return (0); 263 } 264 265 /* 266 * General purpose interface for reading inodes. 267 */ 268 struct dinode * 269 ginode(inumber) 270 ino_t inumber; 271 { 272 ufs_daddr_t iblk; 273 274 if (inumber < ROOTINO || inumber > maxino) 275 errx(EEXIT, "bad inode number %d to ginode", inumber); 276 if (startinum == 0 || 277 inumber < startinum || inumber >= startinum + INOPB(&sblock)) { 278 iblk = ino_to_fsba(&sblock, inumber); 279 if (pbp != 0) 280 pbp->b_flags &= ~B_INUSE; 281 pbp = getdatablk(iblk, sblock.fs_bsize); 282 startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock); 283 } 284 return (&pbp->b_un.b_dinode[inumber % INOPB(&sblock)]); 285 } 286 287 /* 288 * Special purpose version of ginode used to optimize first pass 289 * over all the inodes in numerical order. 290 */ 291 ino_t nextino, lastinum; 292 long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize; 293 struct dinode *inodebuf; 294 295 struct dinode * 296 getnextinode(inumber) 297 ino_t inumber; 298 { 299 long size; 300 ufs_daddr_t dblk; 301 static struct dinode *dp; 302 303 if (inumber != nextino++ || inumber > maxino) 304 errx(EEXIT, "bad inode number %d to nextinode", inumber); 305 if (inumber >= lastinum) { 306 readcnt++; 307 dblk = fsbtodb(&sblock, ino_to_fsba(&sblock, lastinum)); 308 if (readcnt % readpercg == 0) { 309 size = partialsize; 310 lastinum += partialcnt; 311 } else { 312 size = inobufsize; 313 lastinum += fullcnt; 314 } 315 (void)bread(fsreadfd, (char *)inodebuf, dblk, size); /* ??? */ 316 dp = inodebuf; 317 } 318 return (dp++); 319 } 320 321 void 322 resetinodebuf() 323 { 324 325 startinum = 0; 326 nextino = 0; 327 lastinum = 0; 328 readcnt = 0; 329 inobufsize = blkroundup(&sblock, INOBUFSIZE); 330 fullcnt = inobufsize / sizeof(struct dinode); 331 readpercg = sblock.fs_ipg / fullcnt; 332 partialcnt = sblock.fs_ipg % fullcnt; 333 partialsize = partialcnt * sizeof(struct dinode); 334 if (partialcnt != 0) { 335 readpercg++; 336 } else { 337 partialcnt = fullcnt; 338 partialsize = inobufsize; 339 } 340 if (inodebuf == NULL && 341 (inodebuf = (struct dinode *)malloc((unsigned)inobufsize)) == NULL) 342 errx(EEXIT, "Cannot allocate space for inode buffer"); 343 while (nextino < ROOTINO) 344 (void)getnextinode(nextino); 345 } 346 347 void 348 freeinodebuf() 349 { 350 351 if (inodebuf != NULL) 352 free((char *)inodebuf); 353 inodebuf = NULL; 354 } 355 356 /* 357 * Routines to maintain information about directory inodes. 358 * This is built during the first pass and used during the 359 * second and third passes. 360 * 361 * Enter inodes into the cache. 362 */ 363 void 364 cacheino(dp, inumber) 365 register struct dinode *dp; 366 ino_t inumber; 367 { 368 register struct inoinfo *inp; 369 struct inoinfo **inpp; 370 unsigned int blks; 371 372 blks = howmany(dp->di_size, sblock.fs_bsize); 373 if (blks > NDADDR) 374 blks = NDADDR + NIADDR; 375 inp = (struct inoinfo *) 376 malloc(sizeof(*inp) + (blks - 1) * sizeof(ufs_daddr_t)); 377 if (inp == NULL) 378 return; 379 inpp = &inphead[inumber % numdirs]; 380 inp->i_nexthash = *inpp; 381 *inpp = inp; 382 if (inumber == ROOTINO) 383 inp->i_parent = ROOTINO; 384 else 385 inp->i_parent = (ino_t)0; 386 inp->i_dotdot = (ino_t)0; 387 inp->i_number = inumber; 388 inp->i_isize = dp->di_size; 389 inp->i_numblks = blks * sizeof(ufs_daddr_t); 390 memmove(&inp->i_blks[0], &dp->di_db[0], (size_t)inp->i_numblks); 391 if (inplast == listmax) { 392 listmax += 100; 393 inpsort = (struct inoinfo **)realloc((char *)inpsort, 394 (unsigned)listmax * sizeof(struct inoinfo *)); 395 if (inpsort == NULL) 396 errx(EEXIT, "cannot increase directory list"); 397 } 398 inpsort[inplast++] = inp; 399 } 400 401 /* 402 * Look up an inode cache structure. 403 */ 404 struct inoinfo * 405 getinoinfo(inumber) 406 ino_t inumber; 407 { 408 register struct inoinfo *inp; 409 410 for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) { 411 if (inp->i_number != inumber) 412 continue; 413 return (inp); 414 } 415 errx(EEXIT, "cannot find inode %d", inumber); 416 return ((struct inoinfo *)0); 417 } 418 419 /* 420 * Clean up all the inode cache structure. 421 */ 422 void 423 inocleanup() 424 { 425 register struct inoinfo **inpp; 426 427 if (inphead == NULL) 428 return; 429 for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--) 430 free((char *)(*inpp)); 431 free((char *)inphead); 432 free((char *)inpsort); 433 inphead = inpsort = NULL; 434 } 435 436 void 437 inodirty() 438 { 439 440 dirty(pbp); 441 } 442 443 void 444 clri(idesc, type, flag) 445 register struct inodesc *idesc; 446 char *type; 447 int flag; 448 { 449 register struct dinode *dp; 450 451 dp = ginode(idesc->id_number); 452 if (flag == 1) { 453 pwarn("%s %s", type, 454 (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE"); 455 pinode(idesc->id_number); 456 } 457 if (preen || reply("CLEAR") == 1) { 458 if (preen) 459 printf(" (CLEARED)\n"); 460 n_files--; 461 (void)ckinode(dp, idesc); 462 clearinode(dp); 463 statemap[idesc->id_number] = USTATE; 464 inodirty(); 465 } 466 } 467 468 int 469 findname(idesc) 470 struct inodesc *idesc; 471 { 472 register struct direct *dirp = idesc->id_dirp; 473 474 if (dirp->d_ino != idesc->id_parent) 475 return (KEEPON); 476 memmove(idesc->id_name, dirp->d_name, (size_t)dirp->d_namlen + 1); 477 return (STOP|FOUND); 478 } 479 480 int 481 findino(idesc) 482 struct inodesc *idesc; 483 { 484 register struct direct *dirp = idesc->id_dirp; 485 486 if (dirp->d_ino == 0) 487 return (KEEPON); 488 if (strcmp(dirp->d_name, idesc->id_name) == 0 && 489 dirp->d_ino >= ROOTINO && dirp->d_ino <= maxino) { 490 idesc->id_parent = dirp->d_ino; 491 return (STOP|FOUND); 492 } 493 return (KEEPON); 494 } 495 496 void 497 pinode(ino) 498 ino_t ino; 499 { 500 register struct dinode *dp; 501 register char *p; 502 struct passwd *pw; 503 time_t t; 504 505 printf(" I=%lu ", ino); 506 if (ino < ROOTINO || ino > maxino) 507 return; 508 dp = ginode(ino); 509 printf(" OWNER="); 510 if ((pw = getpwuid((int)dp->di_uid)) != 0) 511 printf("%s ", pw->pw_name); 512 else 513 printf("%u ", (unsigned)dp->di_uid); 514 printf("MODE=%o\n", dp->di_mode); 515 if (preen) 516 printf("%s: ", cdevname); 517 printf("SIZE=%qu ", dp->di_size); 518 t = dp->di_mtime; 519 p = ctime(&t); 520 printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]); 521 } 522 523 void 524 blkerror(ino, type, blk) 525 ino_t ino; 526 char *type; 527 ufs_daddr_t blk; 528 { 529 530 pfatal("%ld %s I=%lu", blk, type, ino); 531 printf("\n"); 532 switch (statemap[ino]) { 533 534 case FSTATE: 535 statemap[ino] = FCLEAR; 536 return; 537 538 case DSTATE: 539 statemap[ino] = DCLEAR; 540 return; 541 542 case FCLEAR: 543 case DCLEAR: 544 return; 545 546 default: 547 errx(EEXIT, "BAD STATE %d TO BLKERR", statemap[ino]); 548 /* NOTREACHED */ 549 } 550 } 551 552 /* 553 * allocate an unused inode 554 */ 555 ino_t 556 allocino(request, type) 557 ino_t request; 558 int type; 559 { 560 register ino_t ino; 561 register struct dinode *dp; 562 563 if (request == 0) 564 request = ROOTINO; 565 else if (statemap[request] != USTATE) 566 return (0); 567 for (ino = request; ino < maxino; ino++) 568 if (statemap[ino] == USTATE) 569 break; 570 if (ino == maxino) 571 return (0); 572 switch (type & IFMT) { 573 case IFDIR: 574 statemap[ino] = DSTATE; 575 break; 576 case IFREG: 577 case IFLNK: 578 statemap[ino] = FSTATE; 579 break; 580 default: 581 return (0); 582 } 583 dp = ginode(ino); 584 dp->di_db[0] = allocblk((long)1); 585 if (dp->di_db[0] == 0) { 586 statemap[ino] = USTATE; 587 return (0); 588 } 589 dp->di_mode = type; 590 dp->di_atime = time(NULL); 591 dp->di_mtime = dp->di_ctime = dp->di_atime; 592 dp->di_size = sblock.fs_fsize; 593 dp->di_blocks = btodb(sblock.fs_fsize); 594 n_files++; 595 inodirty(); 596 if (newinofmt) 597 typemap[ino] = IFTODT(type); 598 return (ino); 599 } 600 601 /* 602 * deallocate an inode 603 */ 604 void 605 freeino(ino) 606 ino_t ino; 607 { 608 struct inodesc idesc; 609 struct dinode *dp; 610 611 memset(&idesc, 0, sizeof(struct inodesc)); 612 idesc.id_type = ADDR; 613 idesc.id_func = pass4check; 614 idesc.id_number = ino; 615 dp = ginode(ino); 616 (void)ckinode(dp, &idesc); 617 clearinode(dp); 618 inodirty(); 619 statemap[ino] = USTATE; 620 n_files--; 621 } 622