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