1 /* $NetBSD: inode.c,v 1.3 1997/10/09 13:19:36 bouyer Exp $ */ 2 3 /* 4 * Copyright (c) 1997 Manuel Bouyer. 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 #include <sys/cdefs.h> 38 #ifndef lint 39 #if 0 40 static char sccsid[] = "@(#)inode.c 8.5 (Berkeley) 2/8/95"; 41 #else 42 __RCSID("$NetBSD: inode.c,v 1.3 1997/10/09 13:19:36 bouyer Exp $"); 43 #endif 44 #endif /* not lint */ 45 46 #include <sys/param.h> 47 #include <sys/time.h> 48 #include <ufs/ext2fs/ext2fs_dinode.h> 49 #include <ufs/ext2fs/ext2fs_dir.h> 50 #include <ufs/ext2fs/ext2fs.h> 51 52 #include <ufs/ufs/dinode.h> /* for IFMT & friends */ 53 #ifndef SMALL 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 /* 65 * CG is stored in fs byte order in memory, so we can't use ino_to_fsba 66 * here. 67 */ 68 69 #define fsck_ino_to_fsba(fs, x) \ 70 (fs2h32((fs)->e2fs_gd[ino_to_cg(fs, x)].ext2bgd_i_tables) + \ 71 (((x)-1) % (fs)->e2fs.e2fs_ipg)/(fs)->e2fs_ipb) 72 73 74 static ino_t startinum; 75 76 static int iblock __P((struct inodesc *, long, u_int64_t)); 77 78 int 79 ckinode(dp, idesc) 80 struct ext2fs_dinode *dp; 81 struct inodesc *idesc; 82 { 83 u_int32_t *ap; 84 long ret, n, ndb; 85 struct ext2fs_dinode dino; 86 u_int64_t remsize, sizepb; 87 mode_t mode; 88 char pathbuf[MAXPATHLEN + 1]; 89 90 if (idesc->id_fix != IGNORE) 91 idesc->id_fix = DONTKNOW; 92 idesc->id_entryno = 0; 93 idesc->id_filesize = fs2h32(dp->e2di_size); 94 mode = fs2h16(dp->e2di_mode) & IFMT; 95 if (mode == IFBLK || mode == IFCHR || (mode == IFLNK && 96 (fs2h32(dp->e2di_size) < EXT2_MAXSYMLINKLEN))) 97 return (KEEPON); 98 dino = *dp; 99 ndb = howmany(fs2h32(dino.e2di_size), sblock.e2fs_bsize); 100 for (ap = &dino.e2di_blocks[0]; ap < &dino.e2di_blocks[NDADDR]; 101 ap++,ndb--) { 102 idesc->id_numfrags = 1; 103 if (*ap == 0) { 104 if (idesc->id_type == DATA && ndb > 0) { 105 /* An empty block in a directory XXX */ 106 getpathname(pathbuf, idesc->id_number, 107 idesc->id_number); 108 pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", 109 pathbuf); 110 if (reply("ADJUST LENGTH") == 1) { 111 dp = ginode(idesc->id_number); 112 dp->e2di_size = h2fs32((ap - &dino.e2di_blocks[0]) * 113 sblock.e2fs_bsize); 114 printf( 115 "YOU MUST RERUN FSCK AFTERWARDS\n"); 116 rerun = 1; 117 inodirty(); 118 } 119 } 120 continue; 121 } 122 idesc->id_blkno = fs2h32(*ap); 123 if (idesc->id_type == ADDR) 124 ret = (*idesc->id_func)(idesc); 125 else 126 ret = dirscan(idesc); 127 if (ret & STOP) 128 return (ret); 129 } 130 idesc->id_numfrags = 1; 131 remsize = fs2h32(dino.e2di_size) - sblock.e2fs_bsize * NDADDR; 132 sizepb = sblock.e2fs_bsize; 133 for (ap = &dino.e2di_blocks[NDADDR], n = 1; n <= NIADDR; ap++, n++) { 134 if (*ap) { 135 idesc->id_blkno = fs2h32(*ap); 136 ret = iblock(idesc, n, remsize); 137 if (ret & STOP) 138 return (ret); 139 } else { 140 if (idesc->id_type == DATA && remsize > 0) { 141 /* An empty block in a directory XXX */ 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->e2di_size = h2fs32(fs2h32(dp->e2di_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 daddr_t *ap; 171 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 ext2fs_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.e2fs_bsize); 188 ilevel--; 189 for (sizepb = sblock.e2fs_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 (idesc->id_func == pass1check && 196 nif < NINDIR(&sblock)) { 197 aplim = &bp->b_un.b_indir[NINDIR(&sblock)]; 198 for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) { 199 if (*ap == 0) 200 continue; 201 (void)sprintf(buf, "PARTIALLY TRUNCATED INODE I=%u", 202 idesc->id_number); 203 if (dofix(idesc, buf)) { 204 *ap = 0; 205 dirty(bp); 206 } 207 } 208 flush(fswritefd, bp); 209 } 210 aplim = &bp->b_un.b_indir[nif]; 211 for (ap = bp->b_un.b_indir; ap < aplim; ap++) { 212 if (*ap) { 213 idesc->id_blkno = fs2h32(*ap); 214 if (ilevel == 0) 215 n = (*func)(idesc); 216 else 217 n = iblock(idesc, ilevel, isize); 218 if (n & STOP) { 219 bp->b_flags &= ~B_INUSE; 220 return (n); 221 } 222 } else { 223 if (idesc->id_type == DATA && isize > 0) { 224 /* An empty block in a directory XXX */ 225 getpathname(pathbuf, idesc->id_number, 226 idesc->id_number); 227 pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", 228 pathbuf); 229 if (reply("ADJUST LENGTH") == 1) { 230 dp = ginode(idesc->id_number); 231 dp->e2di_size = h2fs32(fs2h32(dp->e2di_size) - isize); 232 isize = 0; 233 printf( 234 "YOU MUST RERUN FSCK AFTERWARDS\n"); 235 rerun = 1; 236 inodirty(); 237 bp->b_flags &= ~B_INUSE; 238 return(STOP); 239 } 240 } 241 } 242 isize -= sizepb; 243 } 244 bp->b_flags &= ~B_INUSE; 245 return (KEEPON); 246 } 247 248 /* 249 * Check that a block in a legal block number. 250 * Return 0 if in range, 1 if out of range. 251 */ 252 int 253 chkrange(blk, cnt) 254 daddr_t blk; 255 int cnt; 256 { 257 int c; 258 259 if ((unsigned)(blk + cnt) > maxfsblock) 260 return (1); 261 c = dtog(&sblock, blk); 262 if (blk < sblock.e2fs.e2fs_bpg * c + cgoverhead + 263 sblock.e2fs.e2fs_first_dblock) { 264 if ((blk + cnt) > sblock.e2fs.e2fs_bpg * c + cgoverhead + 265 sblock.e2fs.e2fs_first_dblock) { 266 if (debug) { 267 printf("blk %d < cgdmin %d;", 268 blk, sblock.e2fs.e2fs_bpg * c + cgoverhead + 269 sblock.e2fs.e2fs_first_dblock); 270 printf(" blk + cnt %d > cgsbase %d\n", 271 blk + cnt, sblock.e2fs.e2fs_bpg * c + cgoverhead + 272 sblock.e2fs.e2fs_first_dblock); 273 } 274 return (1); 275 } 276 } else { 277 if ((blk + cnt) > sblock.e2fs.e2fs_bpg * (c + 1) + cgoverhead + 278 sblock.e2fs.e2fs_first_dblock) { 279 if (debug) { 280 printf("blk %d >= cgdmin %d;", 281 blk, sblock.e2fs.e2fs_bpg * c + cgoverhead + 282 sblock.e2fs.e2fs_first_dblock); 283 printf(" blk + cnt %d > cgdmax %d\n", 284 blk+cnt, sblock.e2fs.e2fs_bpg * (c + 1) + cgoverhead + 285 sblock.e2fs.e2fs_first_dblock); 286 } 287 return (1); 288 } 289 } 290 return (0); 291 } 292 293 /* 294 * General purpose interface for reading inodes. 295 */ 296 struct ext2fs_dinode * 297 ginode(inumber) 298 ino_t inumber; 299 { 300 daddr_t iblk; 301 302 if ((inumber < EXT2_FIRSTINO && inumber != EXT2_ROOTINO) 303 || inumber > maxino) 304 errexit("bad inode number %d to ginode\n", inumber); 305 if (startinum == 0 || 306 inumber < startinum || inumber >= startinum + sblock.e2fs_ipb) { 307 iblk = fsck_ino_to_fsba(&sblock, inumber); 308 if (pbp != 0) 309 pbp->b_flags &= ~B_INUSE; 310 pbp = getdatablk(iblk, sblock.e2fs_bsize); 311 startinum = ((inumber -1) / sblock.e2fs_ipb) * sblock.e2fs_ipb + 1; 312 } 313 return (&pbp->b_un.b_dinode[(inumber-1) % sblock.e2fs_ipb]); 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 ext2fs_dinode *inodebuf; 323 324 struct ext2fs_dinode * 325 getnextinode(inumber) 326 ino_t inumber; 327 { 328 long size; 329 daddr_t dblk; 330 static struct ext2fs_dinode *dp; 331 332 if (inumber != nextino++ || inumber > maxino) 333 errexit("bad inode number %d to nextinode\n", inumber); 334 if (inumber >= lastinum) { 335 readcnt++; 336 dblk = fsbtodb(&sblock, fsck_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 dp = inodebuf; 346 } 347 return (dp++); 348 } 349 350 void 351 resetinodebuf() 352 { 353 354 startinum = 0; 355 nextino = 1; 356 lastinum = 1; 357 readcnt = 0; 358 inobufsize = blkroundup(&sblock, INOBUFSIZE); 359 fullcnt = inobufsize / sizeof(struct ext2fs_dinode); 360 readpercg = sblock.e2fs.e2fs_ipg / fullcnt; 361 partialcnt = sblock.e2fs.e2fs_ipg % fullcnt; 362 partialsize = partialcnt * sizeof(struct ext2fs_dinode); 363 if (partialcnt != 0) { 364 readpercg++; 365 } else { 366 partialcnt = fullcnt; 367 partialsize = inobufsize; 368 } 369 if (inodebuf == NULL && 370 (inodebuf = (struct ext2fs_dinode *)malloc((unsigned)inobufsize)) == 371 NULL) 372 errexit("Cannot allocate space for inode buffer\n"); 373 while (nextino < EXT2_ROOTINO) 374 (void)getnextinode(nextino); 375 } 376 377 void 378 freeinodebuf() 379 { 380 381 if (inodebuf != NULL) 382 free((char *)inodebuf); 383 inodebuf = NULL; 384 } 385 386 /* 387 * Routines to maintain information about directory inodes. 388 * This is built during the first pass and used during the 389 * second and third passes. 390 * 391 * Enter inodes into the cache. 392 */ 393 void 394 cacheino(dp, inumber) 395 struct ext2fs_dinode *dp; 396 ino_t inumber; 397 { 398 struct inoinfo *inp; 399 struct inoinfo **inpp; 400 unsigned int blks; 401 402 blks = howmany(fs2h32(dp->e2di_size), sblock.e2fs_bsize); 403 if (blks > NDADDR) 404 blks = NDADDR + NIADDR; 405 inp = (struct inoinfo *) 406 malloc(sizeof(*inp) + (blks - 1) * sizeof(daddr_t)); 407 if (inp == NULL) 408 return; 409 inpp = &inphead[inumber % numdirs]; 410 inp->i_nexthash = *inpp; 411 *inpp = inp; 412 inp->i_child = inp->i_sibling = inp->i_parentp = 0; 413 if (inumber == EXT2_ROOTINO) 414 inp->i_parent = EXT2_ROOTINO; 415 else 416 inp->i_parent = (ino_t)0; 417 inp->i_dotdot = (ino_t)0; 418 inp->i_number = inumber; 419 inp->i_isize = fs2h32(dp->e2di_size); 420 inp->i_numblks = blks * sizeof(daddr_t); 421 memcpy(&inp->i_blks[0], &dp->e2di_blocks[0], (size_t)inp->i_numblks); 422 if (inplast == listmax) { 423 listmax += 100; 424 inpsort = (struct inoinfo **)realloc((char *)inpsort, 425 (unsigned)listmax * sizeof(struct inoinfo *)); 426 if (inpsort == NULL) 427 errexit("cannot increase directory list\n"); 428 } 429 inpsort[inplast++] = inp; 430 } 431 432 /* 433 * Look up an inode cache structure. 434 */ 435 struct inoinfo * 436 getinoinfo(inumber) 437 ino_t inumber; 438 { 439 struct inoinfo *inp; 440 441 for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) { 442 if (inp->i_number != inumber) 443 continue; 444 return (inp); 445 } 446 errexit("cannot find inode %d\n", inumber); 447 return ((struct inoinfo *)0); 448 } 449 450 /* 451 * Clean up all the inode cache structure. 452 */ 453 void 454 inocleanup() 455 { 456 struct inoinfo **inpp; 457 458 if (inphead == NULL) 459 return; 460 for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--) 461 free((char *)(*inpp)); 462 free((char *)inphead); 463 free((char *)inpsort); 464 inphead = inpsort = NULL; 465 } 466 467 void 468 inodirty() 469 { 470 471 dirty(pbp); 472 } 473 474 void 475 clri(idesc, type, flag) 476 struct inodesc *idesc; 477 char *type; 478 int flag; 479 { 480 struct ext2fs_dinode *dp; 481 482 dp = ginode(idesc->id_number); 483 if (flag == 1) { 484 pwarn("%s %s", type, 485 (dp->e2di_mode & IFMT) == IFDIR ? "DIR" : "FILE"); 486 pinode(idesc->id_number); 487 } 488 if (preen || reply("CLEAR") == 1) { 489 if (preen) 490 printf(" (CLEARED)\n"); 491 n_files--; 492 (void)ckinode(dp, idesc); 493 clearinode(dp); 494 statemap[idesc->id_number] = USTATE; 495 inodirty(); 496 } 497 } 498 499 int 500 findname(idesc) 501 struct inodesc *idesc; 502 { 503 struct ext2fs_direct *dirp = idesc->id_dirp; 504 u_int16_t namlen = fs2h16(dirp->e2d_namlen); 505 506 if (fs2h32(dirp->e2d_ino) != idesc->id_parent) 507 return (KEEPON); 508 memcpy(idesc->id_name, dirp->e2d_name, (size_t)namlen); 509 idesc->id_name[namlen] = '\0'; 510 return (STOP|FOUND); 511 } 512 513 int 514 findino(idesc) 515 struct inodesc *idesc; 516 { 517 struct ext2fs_direct *dirp = idesc->id_dirp; 518 u_int32_t ino = fs2h32(dirp->e2d_ino); 519 520 if (ino == 0) 521 return (KEEPON); 522 if (strcmp(dirp->e2d_name, idesc->id_name) == 0 && 523 (ino == EXT2_ROOTINO || ino >= EXT2_FIRSTINO) 524 && ino <= maxino) { 525 idesc->id_parent = ino; 526 return (STOP|FOUND); 527 } 528 return (KEEPON); 529 } 530 531 void 532 pinode(ino) 533 ino_t ino; 534 { 535 struct ext2fs_dinode *dp; 536 char *p; 537 struct passwd *pw; 538 time_t t; 539 540 printf(" I=%u ", ino); 541 if ((ino < EXT2_FIRSTINO && ino != EXT2_ROOTINO) || ino > maxino) 542 return; 543 dp = ginode(ino); 544 printf(" OWNER="); 545 #ifndef SMALL 546 if ((pw = getpwuid((int)dp->e2di_uid)) != 0) 547 printf("%s ", pw->pw_name); 548 else 549 #endif 550 printf("%u ", (unsigned)fs2h16(dp->e2di_uid)); 551 printf("MODE=%o\n", fs2h16(dp->e2di_mode)); 552 if (preen) 553 printf("%s: ", cdevname()); 554 printf("SIZE=%u ", fs2h32(dp->e2di_size)); 555 t = fs2h32(dp->e2di_mtime); 556 p = ctime(&t); 557 printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]); 558 } 559 560 void 561 blkerror(ino, type, blk) 562 ino_t ino; 563 char *type; 564 daddr_t blk; 565 { 566 567 pfatal("%d %s I=%u", blk, type, ino); 568 printf("\n"); 569 switch (statemap[ino]) { 570 571 case FSTATE: 572 statemap[ino] = FCLEAR; 573 return; 574 575 case DSTATE: 576 statemap[ino] = DCLEAR; 577 return; 578 579 case FCLEAR: 580 case DCLEAR: 581 return; 582 583 default: 584 errexit("BAD STATE %d TO BLKERR\n", statemap[ino]); 585 /* NOTREACHED */ 586 } 587 } 588 589 /* 590 * allocate an unused inode 591 */ 592 ino_t 593 allocino(request, type) 594 ino_t request; 595 int type; 596 { 597 ino_t ino; 598 struct ext2fs_dinode *dp; 599 time_t t; 600 601 if (request == 0) 602 request = EXT2_ROOTINO; 603 else if (statemap[request] != USTATE) 604 return (0); 605 for (ino = request; ino < maxino; ino++) { 606 if ((ino > EXT2_ROOTINO) && (ino < EXT2_FIRSTINO)) 607 continue; 608 if (statemap[ino] == USTATE) 609 break; 610 } 611 if (ino == maxino) 612 return (0); 613 switch (type & IFMT) { 614 case IFDIR: 615 statemap[ino] = DSTATE; 616 break; 617 case IFREG: 618 case IFLNK: 619 statemap[ino] = FSTATE; 620 break; 621 default: 622 return (0); 623 } 624 dp = ginode(ino); 625 dp->e2di_blocks[0] = h2fs32(allocblk()); 626 if (dp->e2di_blocks[0] == 0) { 627 statemap[ino] = USTATE; 628 return (0); 629 } 630 dp->e2di_mode = h2fs16(type); 631 (void)time(&t); 632 dp->e2di_atime = h2fs32(t); 633 dp->e2di_mtime = dp->e2di_ctime = dp->e2di_atime; 634 dp->e2di_dtime = 0; 635 dp->e2di_size = h2fs32(sblock.e2fs_bsize); 636 dp->e2di_nblock = h2fs32(btodb(sblock.e2fs_bsize)); 637 n_files++; 638 inodirty(); 639 return (ino); 640 } 641 642 /* 643 * deallocate an inode 644 */ 645 void 646 freeino(ino) 647 ino_t ino; 648 { 649 struct inodesc idesc; 650 struct ext2fs_dinode *dp; 651 652 memset(&idesc, 0, sizeof(struct inodesc)); 653 idesc.id_type = ADDR; 654 idesc.id_func = pass4check; 655 idesc.id_number = ino; 656 dp = ginode(ino); 657 (void)ckinode(dp, &idesc); 658 clearinode(dp); 659 inodirty(); 660 statemap[ino] = USTATE; 661 n_files--; 662 } 663