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