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