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