1 /* $NetBSD: inode.c,v 1.35 2002/09/28 20:11:06 dbj 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.35 2002/09/28 20:11:06 dbj 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 (isappleufs && (idesc->id_filesize < APPLEUFS_MAXSYMLINKLEN)) || 92 (sblock->fs_maxsymlinklen == 0 && dp->di_blocks == 0)))) 93 return (KEEPON); 94 dino = *dp; 95 ndb = howmany(iswap64(dino.di_size), sblock->fs_bsize); 96 for (ap = &dino.di_db[0]; ap < &dino.di_db[NDADDR]; ap++) { 97 if (--ndb == 0 && 98 (offset = blkoff(sblock, iswap64(dino.di_size))) != 0) 99 idesc->id_numfrags = 100 numfrags(sblock, fragroundup(sblock, offset)); 101 else 102 idesc->id_numfrags = sblock->fs_frag; 103 if (*ap == 0) { 104 if (idesc->id_type == DATA && ndb >= 0) { 105 /* An empty block in a directory XXX */ 106 markclean = 0; 107 getpathname(pathbuf, idesc->id_number, 108 idesc->id_number); 109 pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", 110 pathbuf); 111 if (reply("ADJUST LENGTH") == 1) { 112 dp = ginode(idesc->id_number); 113 dp->di_size = iswap64((ap - &dino.di_db[0]) * 114 sblock->fs_bsize); 115 printf( 116 "YOU MUST RERUN FSCK AFTERWARDS\n"); 117 rerun = 1; 118 inodirty(); 119 } 120 } 121 continue; 122 } 123 idesc->id_blkno = iswap32(*ap); 124 if (idesc->id_type == ADDR) 125 ret = (*idesc->id_func)(idesc); 126 else 127 ret = dirscan(idesc); 128 if (ret & STOP) 129 return (ret); 130 } 131 idesc->id_numfrags = sblock->fs_frag; 132 remsize = iswap64(dino.di_size) - sblock->fs_bsize * NDADDR; 133 sizepb = sblock->fs_bsize; 134 for (ap = &dino.di_ib[0], n = 1; n <= NIADDR; ap++, n++) { 135 if (*ap) { 136 idesc->id_blkno = iswap32(*ap); 137 ret = iblock(idesc, n, remsize); 138 if (ret & STOP) 139 return (ret); 140 } else { 141 if (idesc->id_type == DATA && remsize > 0) { 142 /* An empty block in a directory XXX */ 143 markclean = 0; 144 getpathname(pathbuf, idesc->id_number, 145 idesc->id_number); 146 pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", 147 pathbuf); 148 if (reply("ADJUST LENGTH") == 1) { 149 dp = ginode(idesc->id_number); 150 dp->di_size = iswap64(iswap64(dp->di_size) - remsize); 151 remsize = 0; 152 printf( 153 "YOU MUST RERUN FSCK AFTERWARDS\n"); 154 rerun = 1; 155 inodirty(); 156 break; 157 } 158 } 159 } 160 sizepb *= NINDIR(sblock); 161 remsize -= sizepb; 162 } 163 return (KEEPON); 164 } 165 166 static int 167 iblock(idesc, ilevel, isize) 168 struct inodesc *idesc; 169 long ilevel; 170 u_int64_t isize; 171 { 172 ufs_daddr_t *ap; 173 ufs_daddr_t *aplim; 174 struct bufarea *bp; 175 int i, n, (*func) __P((struct inodesc *)), nif; 176 u_int64_t sizepb; 177 char buf[BUFSIZ]; 178 char pathbuf[MAXPATHLEN + 1]; 179 struct dinode *dp; 180 181 if (idesc->id_type == ADDR) { 182 func = idesc->id_func; 183 if (((n = (*func)(idesc)) & KEEPON) == 0) 184 return (n); 185 } else 186 func = dirscan; 187 if (chkrange(idesc->id_blkno, idesc->id_numfrags)) 188 return (SKIP); 189 bp = getdatablk(idesc->id_blkno, sblock->fs_bsize); 190 ilevel--; 191 for (sizepb = sblock->fs_bsize, i = 0; i < ilevel; i++) 192 sizepb *= NINDIR(sblock); 193 if (isize > sizepb * NINDIR(sblock)) 194 nif = NINDIR(sblock); 195 else 196 nif = howmany(isize, sizepb); 197 if (do_blkswap) { /* swap byte order of the whole blk */ 198 aplim = &bp->b_un.b_indir[nif]; 199 for (ap = bp->b_un.b_indir; ap < aplim; ap++) 200 *ap = bswap32(*ap); 201 dirty(bp); 202 flush(fswritefd, bp); 203 } 204 if (idesc->id_func == pass1check && nif < NINDIR(sblock)) { 205 aplim = &bp->b_un.b_indir[NINDIR(sblock)]; 206 for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) { 207 if (*ap == 0) 208 continue; 209 (void)snprintf(buf, sizeof(buf), 210 "PARTIALLY TRUNCATED INODE I=%u", idesc->id_number); 211 if (dofix(idesc, buf)) { 212 *ap = 0; 213 dirty(bp); 214 } else 215 markclean= 0; 216 } 217 flush(fswritefd, bp); 218 } 219 aplim = &bp->b_un.b_indir[nif]; 220 for (ap = bp->b_un.b_indir; ap < aplim; ap++) { 221 if (*ap) { 222 idesc->id_blkno = iswap32(*ap); 223 if (ilevel == 0) 224 n = (*func)(idesc); 225 else 226 n = iblock(idesc, ilevel, isize); 227 if (n & STOP) { 228 bp->b_flags &= ~B_INUSE; 229 return (n); 230 } 231 } else { 232 if (idesc->id_type == DATA && isize > 0) { 233 /* An empty block in a directory XXX */ 234 markclean= 0; 235 getpathname(pathbuf, idesc->id_number, 236 idesc->id_number); 237 pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", 238 pathbuf); 239 if (reply("ADJUST LENGTH") == 1) { 240 dp = ginode(idesc->id_number); 241 dp->di_size = iswap64(iswap64(dp->di_size) - isize); 242 isize = 0; 243 printf( 244 "YOU MUST RERUN FSCK AFTERWARDS\n"); 245 rerun = 1; 246 inodirty(); 247 bp->b_flags &= ~B_INUSE; 248 return(STOP); 249 } 250 } 251 } 252 isize -= sizepb; 253 } 254 bp->b_flags &= ~B_INUSE; 255 return (KEEPON); 256 } 257 258 /* 259 * Check that a block in a legal block number. 260 * Return 0 if in range, 1 if out of range. 261 */ 262 int 263 chkrange(blk, cnt) 264 ufs_daddr_t blk; 265 int cnt; 266 { 267 int c; 268 269 if ((unsigned)(blk + cnt) > maxfsblock) 270 return (1); 271 c = dtog(sblock, blk); 272 if (blk < cgdmin(sblock, c)) { 273 if ((blk + cnt) > cgsblock(sblock, c)) { 274 if (debug) { 275 printf("blk %d < cgdmin %d;", 276 blk, cgdmin(sblock, c)); 277 printf(" blk + cnt %d > cgsbase %d\n", 278 blk + cnt, cgsblock(sblock, c)); 279 } 280 return (1); 281 } 282 } else { 283 if ((blk + cnt) > cgbase(sblock, c+1)) { 284 if (debug) { 285 printf("blk %d >= cgdmin %d;", 286 blk, cgdmin(sblock, c)); 287 printf(" blk + cnt %d > sblock->fs_fpg %d\n", 288 blk+cnt, sblock->fs_fpg); 289 } 290 return (1); 291 } 292 } 293 return (0); 294 } 295 296 /* 297 * General purpose interface for reading inodes. 298 */ 299 struct dinode * 300 ginode(inumber) 301 ino_t inumber; 302 { 303 ufs_daddr_t iblk; 304 int blkoff; 305 306 if (inumber < ROOTINO || inumber > maxino) 307 errx(EEXIT, "bad inode number %d to ginode", inumber); 308 if (startinum == 0 || 309 inumber < startinum || inumber >= startinum + INOPB(sblock)) { 310 iblk = ino_to_fsba(sblock, inumber); 311 if (pbp != 0) 312 pbp->b_flags &= ~B_INUSE; 313 pbp = getdatablk(iblk, sblock->fs_bsize); 314 startinum = (inumber / INOPB(sblock)) * INOPB(sblock); 315 } 316 blkoff = (inumber % INOPB(sblock)) * DINODE_SIZE; 317 return ((struct dinode *)((caddr_t)pbp->b_un.b_buf + blkoff)); 318 } 319 320 /* 321 * Special purpose version of ginode used to optimize first pass 322 * over all the inodes in numerical order. 323 */ 324 ino_t nextino, lastinum; 325 long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize; 326 struct dinode *inodebuf; 327 328 struct dinode * 329 getnextinode(inumber) 330 ino_t inumber; 331 { 332 long size; 333 ufs_daddr_t dblk; 334 static struct dinode *dp; 335 336 if (inumber != nextino++ || inumber > maxino) 337 errx(EEXIT, "bad inode number %d to nextinode", inumber); 338 if (inumber >= lastinum) { 339 readcnt++; 340 dblk = fsbtodb(sblock, ino_to_fsba(sblock, lastinum)); 341 if (readcnt % readpercg == 0) { 342 size = partialsize; 343 lastinum += partialcnt; 344 } else { 345 size = inobufsize; 346 lastinum += fullcnt; 347 } 348 (void)bread(fsreadfd, (char *)inodebuf, dblk, size); /* ??? */ 349 if (doswap) { 350 int i, j; 351 for (i = inumber, dp = inodebuf; i < lastinum; i++, dp++) { 352 ffs_dinode_swap(dp, dp); 353 /* ffs_dinode_swap() doesn't swap blocks addrs */ 354 if ((iswap16(dp->di_mode) & IFMT) != IFLNK || 355 (isappleufs && (iswap64(dp->di_size) > APPLEUFS_MAXSYMLINKLEN)) || 356 iswap64(dp->di_size) > sblock->fs_maxsymlinklen) { 357 for (j=0; j<NDADDR + NIADDR; j++) 358 dp->di_db[j] = bswap32(dp->di_db[j]); 359 } 360 } 361 bwrite(fswritefd, (char *)inodebuf, dblk, size); 362 } 363 dp = inodebuf; 364 } 365 return (dp++); 366 } 367 368 void 369 resetinodebuf() 370 { 371 372 startinum = 0; 373 nextino = 0; 374 lastinum = 0; 375 readcnt = 0; 376 inobufsize = blkroundup(sblock, INOBUFSIZE); 377 fullcnt = inobufsize / DINODE_SIZE; 378 readpercg = sblock->fs_ipg / fullcnt; 379 partialcnt = sblock->fs_ipg % fullcnt; 380 partialsize = partialcnt * DINODE_SIZE; 381 if (partialcnt != 0) { 382 readpercg++; 383 } else { 384 partialcnt = fullcnt; 385 partialsize = inobufsize; 386 } 387 if (inodebuf == NULL && 388 (inodebuf = (struct dinode *)malloc((unsigned)inobufsize)) == NULL) 389 errx(EEXIT, "Cannot allocate space for inode buffer"); 390 while (nextino < ROOTINO) 391 (void)getnextinode(nextino); 392 } 393 394 void 395 freeinodebuf() 396 { 397 398 if (inodebuf != NULL) 399 free((char *)inodebuf); 400 inodebuf = NULL; 401 } 402 403 /* 404 * Routines to maintain information about directory inodes. 405 * This is built during the first pass and used during the 406 * second and third passes. 407 * 408 * Enter inodes into the cache. 409 */ 410 void 411 cacheino(dp, inumber) 412 struct dinode *dp; 413 ino_t inumber; 414 { 415 struct inoinfo *inp; 416 struct inoinfo **inpp; 417 unsigned int blks, extra; 418 419 blks = howmany(iswap64(dp->di_size), sblock->fs_bsize); 420 if (blks > NDADDR) 421 blks = NDADDR + NIADDR; 422 if (blks > 0) 423 extra = (blks - 1) * sizeof(ufs_daddr_t); 424 else 425 extra = 0; 426 inp = (struct inoinfo *) malloc(sizeof(*inp) + extra); 427 if (inp == NULL) 428 return; 429 inpp = &inphead[inumber % numdirs]; 430 inp->i_nexthash = *inpp; 431 *inpp = inp; 432 inp->i_child = inp->i_sibling = inp->i_parentp = 0; 433 if (inumber == ROOTINO) 434 inp->i_parent = ROOTINO; 435 else 436 inp->i_parent = (ino_t)0; 437 inp->i_dotdot = (ino_t)0; 438 inp->i_number = inumber; 439 inp->i_isize = iswap64(dp->di_size); 440 inp->i_numblks = blks * sizeof(ufs_daddr_t); 441 memmove(&inp->i_blks[0], &dp->di_db[0], (size_t)inp->i_numblks); 442 if (inplast == listmax) { 443 listmax += 100; 444 inpsort = (struct inoinfo **)realloc((char *)inpsort, 445 (unsigned)listmax * sizeof(struct inoinfo *)); 446 if (inpsort == NULL) 447 errx(EEXIT, "cannot increase directory list"); 448 } 449 inpsort[inplast++] = inp; 450 } 451 452 /* 453 * Look up an inode cache structure. 454 */ 455 struct inoinfo * 456 getinoinfo(inumber) 457 ino_t inumber; 458 { 459 struct inoinfo *inp; 460 461 for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) { 462 if (inp->i_number != inumber) 463 continue; 464 return (inp); 465 } 466 errx(EEXIT, "cannot find inode %d", inumber); 467 return ((struct inoinfo *)0); 468 } 469 470 /* 471 * Clean up all the inode cache structure. 472 */ 473 void 474 inocleanup() 475 { 476 struct inoinfo **inpp; 477 478 if (inphead == NULL) 479 return; 480 for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--) 481 free((char *)(*inpp)); 482 free((char *)inphead); 483 free((char *)inpsort); 484 inphead = inpsort = NULL; 485 } 486 487 void 488 inodirty() 489 { 490 491 dirty(pbp); 492 } 493 494 void 495 clri(idesc, type, flag) 496 struct inodesc *idesc; 497 char *type; 498 int flag; 499 { 500 struct dinode *dp; 501 502 dp = ginode(idesc->id_number); 503 if (flag == 1) { 504 pwarn("%s %s", type, 505 (iswap16(dp->di_mode) & IFMT) == IFDIR ? "DIR" : "FILE"); 506 pinode(idesc->id_number); 507 } 508 if (preen || reply("CLEAR") == 1) { 509 if (preen) 510 printf(" (CLEARED)\n"); 511 n_files--; 512 (void)ckinode(dp, idesc); 513 clearinode(dp); 514 statemap[idesc->id_number] = USTATE; 515 inodirty(); 516 } else 517 markclean= 0; 518 } 519 520 int 521 findname(idesc) 522 struct inodesc *idesc; 523 { 524 struct direct *dirp = idesc->id_dirp; 525 526 if (iswap32(dirp->d_ino) != idesc->id_parent) 527 return (KEEPON); 528 memmove(idesc->id_name, dirp->d_name, (size_t)dirp->d_namlen + 1); 529 return (STOP|FOUND); 530 } 531 532 int 533 findino(idesc) 534 struct inodesc *idesc; 535 { 536 struct direct *dirp = idesc->id_dirp; 537 538 if (dirp->d_ino == 0) 539 return (KEEPON); 540 if (strcmp(dirp->d_name, idesc->id_name) == 0 && 541 iswap32(dirp->d_ino) >= ROOTINO && iswap32(dirp->d_ino) <= maxino) { 542 idesc->id_parent = iswap32(dirp->d_ino); 543 return (STOP|FOUND); 544 } 545 return (KEEPON); 546 } 547 548 void 549 pinode(ino) 550 ino_t ino; 551 { 552 struct dinode *dp; 553 char *p; 554 struct passwd *pw; 555 time_t t; 556 557 printf(" I=%u ", ino); 558 if (ino < ROOTINO || ino > maxino) 559 return; 560 dp = ginode(ino); 561 printf(" OWNER="); 562 #ifndef SMALL 563 if ((pw = getpwuid((int)iswap32(dp->di_uid))) != 0) 564 printf("%s ", pw->pw_name); 565 else 566 #endif 567 printf("%u ", (unsigned)iswap32(dp->di_uid)); 568 printf("MODE=%o\n", iswap16(dp->di_mode)); 569 if (preen) 570 printf("%s: ", cdevname()); 571 printf("SIZE=%llu ", (unsigned long long)iswap64(dp->di_size)); 572 t = iswap32(dp->di_mtime); 573 p = ctime(&t); 574 printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]); 575 } 576 577 void 578 blkerror(ino, type, blk) 579 ino_t ino; 580 char *type; 581 ufs_daddr_t blk; 582 { 583 584 pfatal("%d %s I=%u", blk, type, ino); 585 printf("\n"); 586 switch (statemap[ino]) { 587 588 case FSTATE: 589 statemap[ino] = FCLEAR; 590 return; 591 592 case DSTATE: 593 statemap[ino] = DCLEAR; 594 return; 595 596 case FCLEAR: 597 case DCLEAR: 598 return; 599 600 default: 601 errx(EEXIT, "BAD STATE %d TO BLKERR", statemap[ino]); 602 /* NOTREACHED */ 603 } 604 } 605 606 /* 607 * allocate an unused inode 608 */ 609 ino_t 610 allocino(request, type) 611 ino_t request; 612 int type; 613 { 614 ino_t ino; 615 struct dinode *dp; 616 time_t t; 617 struct cg *cgp = cgrp; 618 int cg; 619 620 if (request == 0) 621 request = ROOTINO; 622 else if (statemap[request] != USTATE) 623 return (0); 624 for (ino = request; ino < maxino; ino++) 625 if (statemap[ino] == USTATE) 626 break; 627 if (ino == maxino) 628 return (0); 629 cg = ino_to_cg(sblock, ino); 630 getblk(&cgblk, cgtod(sblock, cg), sblock->fs_cgsize); 631 memcpy(cgp, cgblk.b_un.b_cg, sblock->fs_cgsize); 632 if ((doswap && !needswap) || (!doswap && needswap)) 633 swap_cg(cgblk.b_un.b_cg, cgp); 634 if (!cg_chkmagic(cgp, 0)) 635 pfatal("CG %d: ALLOCINO: BAD MAGIC NUMBER\n", cg); 636 if (doswap) 637 cgdirty(); 638 setbit(cg_inosused(cgp, 0), ino % sblock->fs_ipg); 639 cgp->cg_cs.cs_nifree--; 640 switch (type & IFMT) { 641 case IFDIR: 642 statemap[ino] = DSTATE; 643 cgp->cg_cs.cs_ndir++; 644 break; 645 case IFREG: 646 case IFLNK: 647 statemap[ino] = FSTATE; 648 break; 649 default: 650 return (0); 651 } 652 cgdirty(); 653 dp = ginode(ino); 654 dp->di_db[0] = iswap32(allocblk((long)1)); 655 if (dp->di_db[0] == 0) { 656 statemap[ino] = USTATE; 657 return (0); 658 } 659 dp->di_mode = iswap16(type); 660 dp->di_flags = 0; 661 (void)time(&t); 662 dp->di_atime = iswap32(t); 663 dp->di_mtime = dp->di_ctime = dp->di_atime; 664 dp->di_size = iswap64(sblock->fs_fsize); 665 dp->di_blocks = iswap32(btodb(sblock->fs_fsize)); 666 n_files++; 667 inodirty(); 668 if (newinofmt) 669 typemap[ino] = IFTODT(type); 670 return (ino); 671 } 672 673 /* 674 * deallocate an inode 675 */ 676 void 677 freeino(ino) 678 ino_t ino; 679 { 680 struct inodesc idesc; 681 struct dinode *dp; 682 683 memset(&idesc, 0, sizeof(struct inodesc)); 684 idesc.id_type = ADDR; 685 idesc.id_func = pass4check; 686 idesc.id_number = ino; 687 dp = ginode(ino); 688 (void)ckinode(dp, &idesc); 689 clearinode(dp); 690 inodirty(); 691 statemap[ino] = USTATE; 692 n_files--; 693 } 694