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