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