1 /* $NetBSD: inode.c,v 1.2 1997/09/14 14:27:24 lukem 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.2 1997/09/14 14:27:24 lukem 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 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 ext2fs_dinode *dp; 71 struct inodesc *idesc; 72 { 73 u_int32_t *ap; 74 long ret, n, ndb; 75 struct ext2fs_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->e2di_size; 84 mode = dp->e2di_mode & IFMT; 85 if (mode == IFBLK || mode == IFCHR || (mode == IFLNK && 86 (dp->e2di_size < EXT2_MAXSYMLINKLEN))) 87 return (KEEPON); 88 dino = *dp; 89 ndb = howmany(dino.e2di_size, sblock.e2fs_bsize); 90 for (ap = &dino.e2di_blocks[0]; ap < &dino.e2di_blocks[NDADDR]; 91 ap++,ndb--) { 92 idesc->id_numfrags = 1; 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->e2di_size = (ap - &dino.e2di_blocks[0]) * 103 sblock.e2fs_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 = 1; 121 remsize = dino.e2di_size - sblock.e2fs_bsize * NDADDR; 122 sizepb = sblock.e2fs_bsize; 123 for (ap = &dino.e2di_blocks[NDADDR], 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->e2di_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 daddr_t *ap; 161 daddr_t *aplim; 162 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 ext2fs_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.e2fs_bsize); 178 ilevel--; 179 for (sizepb = sblock.e2fs_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 && 186 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->e2di_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 int c; 248 249 if ((unsigned)(blk + cnt) > maxfsblock) 250 return (1); 251 c = dtog(&sblock, blk); 252 if (blk < sblock.e2fs.e2fs_bpg * c + cgoverhead + 253 sblock.e2fs.e2fs_first_dblock) { 254 if ((blk + cnt) > sblock.e2fs.e2fs_bpg * c + cgoverhead + 255 sblock.e2fs.e2fs_first_dblock) { 256 if (debug) { 257 printf("blk %d < cgdmin %d;", 258 blk, sblock.e2fs.e2fs_bpg * c + cgoverhead + 259 sblock.e2fs.e2fs_first_dblock); 260 printf(" blk + cnt %d > cgsbase %d\n", 261 blk + cnt, sblock.e2fs.e2fs_bpg * c + cgoverhead + 262 sblock.e2fs.e2fs_first_dblock); 263 } 264 return (1); 265 } 266 } else { 267 if ((blk + cnt) > sblock.e2fs.e2fs_bpg * (c + 1) + cgoverhead + 268 sblock.e2fs.e2fs_first_dblock) { 269 if (debug) { 270 printf("blk %d >= cgdmin %d;", 271 blk, sblock.e2fs.e2fs_bpg * c + cgoverhead + 272 sblock.e2fs.e2fs_first_dblock); 273 printf(" blk + cnt %d > cgdmax %d\n", 274 blk+cnt, sblock.e2fs.e2fs_bpg * (c + 1) + cgoverhead + 275 sblock.e2fs.e2fs_first_dblock); 276 } 277 return (1); 278 } 279 } 280 return (0); 281 } 282 283 /* 284 * General purpose interface for reading inodes. 285 */ 286 struct ext2fs_dinode * 287 ginode(inumber) 288 ino_t inumber; 289 { 290 daddr_t iblk; 291 292 if ((inumber < EXT2_FIRSTINO && inumber != EXT2_ROOTINO) 293 || inumber > maxino) 294 errexit("bad inode number %d to ginode\n", inumber); 295 if (startinum == 0 || 296 inumber < startinum || inumber >= startinum + sblock.e2fs_ipb) { 297 iblk = ino_to_fsba(&sblock, inumber); 298 if (pbp != 0) 299 pbp->b_flags &= ~B_INUSE; 300 pbp = getdatablk(iblk, sblock.e2fs_bsize); 301 startinum = ((inumber -1) / sblock.e2fs_ipb) * sblock.e2fs_ipb + 1; 302 } 303 return (&pbp->b_un.b_dinode[(inumber-1) % sblock.e2fs_ipb]); 304 } 305 306 /* 307 * Special purpose version of ginode used to optimize first pass 308 * over all the inodes in numerical order. 309 */ 310 ino_t nextino, lastinum; 311 long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize; 312 struct ext2fs_dinode *inodebuf; 313 314 struct ext2fs_dinode * 315 getnextinode(inumber) 316 ino_t inumber; 317 { 318 long size; 319 daddr_t dblk; 320 static struct ext2fs_dinode *dp; 321 322 if (inumber != nextino++ || inumber > maxino) 323 errexit("bad inode number %d to nextinode\n", inumber); 324 if (inumber >= lastinum) { 325 readcnt++; 326 dblk = fsbtodb(&sblock, ino_to_fsba(&sblock, lastinum)); 327 if (readcnt % readpercg == 0) { 328 size = partialsize; 329 lastinum += partialcnt; 330 } else { 331 size = inobufsize; 332 lastinum += fullcnt; 333 } 334 (void)bread(fsreadfd, (char *)inodebuf, dblk, size); 335 dp = inodebuf; 336 } 337 return (dp++); 338 } 339 340 void 341 resetinodebuf() 342 { 343 344 startinum = 0; 345 nextino = 1; 346 lastinum = 1; 347 readcnt = 0; 348 inobufsize = blkroundup(&sblock, INOBUFSIZE); 349 fullcnt = inobufsize / sizeof(struct ext2fs_dinode); 350 readpercg = sblock.e2fs.e2fs_ipg / fullcnt; 351 partialcnt = sblock.e2fs.e2fs_ipg % fullcnt; 352 partialsize = partialcnt * sizeof(struct ext2fs_dinode); 353 if (partialcnt != 0) { 354 readpercg++; 355 } else { 356 partialcnt = fullcnt; 357 partialsize = inobufsize; 358 } 359 if (inodebuf == NULL && 360 (inodebuf = (struct ext2fs_dinode *)malloc((unsigned)inobufsize)) == 361 NULL) 362 errexit("Cannot allocate space for inode buffer\n"); 363 while (nextino < EXT2_ROOTINO) 364 (void)getnextinode(nextino); 365 } 366 367 void 368 freeinodebuf() 369 { 370 371 if (inodebuf != NULL) 372 free((char *)inodebuf); 373 inodebuf = NULL; 374 } 375 376 /* 377 * Routines to maintain information about directory inodes. 378 * This is built during the first pass and used during the 379 * second and third passes. 380 * 381 * Enter inodes into the cache. 382 */ 383 void 384 cacheino(dp, inumber) 385 struct ext2fs_dinode *dp; 386 ino_t inumber; 387 { 388 struct inoinfo *inp; 389 struct inoinfo **inpp; 390 unsigned int blks; 391 392 blks = howmany(dp->e2di_size, sblock.e2fs_bsize); 393 if (blks > NDADDR) 394 blks = NDADDR + NIADDR; 395 inp = (struct inoinfo *) 396 malloc(sizeof(*inp) + (blks - 1) * sizeof(daddr_t)); 397 if (inp == NULL) 398 return; 399 inpp = &inphead[inumber % numdirs]; 400 inp->i_nexthash = *inpp; 401 *inpp = inp; 402 inp->i_child = inp->i_sibling = inp->i_parentp = 0; 403 if (inumber == EXT2_ROOTINO) 404 inp->i_parent = EXT2_ROOTINO; 405 else 406 inp->i_parent = (ino_t)0; 407 inp->i_dotdot = (ino_t)0; 408 inp->i_number = inumber; 409 inp->i_isize = dp->e2di_size; 410 inp->i_numblks = blks * sizeof(daddr_t); 411 memcpy(&inp->i_blks[0], &dp->e2di_blocks[0], (size_t)inp->i_numblks); 412 if (inplast == listmax) { 413 listmax += 100; 414 inpsort = (struct inoinfo **)realloc((char *)inpsort, 415 (unsigned)listmax * sizeof(struct inoinfo *)); 416 if (inpsort == NULL) 417 errexit("cannot increase directory list\n"); 418 } 419 inpsort[inplast++] = inp; 420 } 421 422 /* 423 * Look up an inode cache structure. 424 */ 425 struct inoinfo * 426 getinoinfo(inumber) 427 ino_t inumber; 428 { 429 struct inoinfo *inp; 430 431 for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) { 432 if (inp->i_number != inumber) 433 continue; 434 return (inp); 435 } 436 errexit("cannot find inode %d\n", inumber); 437 return ((struct inoinfo *)0); 438 } 439 440 /* 441 * Clean up all the inode cache structure. 442 */ 443 void 444 inocleanup() 445 { 446 struct inoinfo **inpp; 447 448 if (inphead == NULL) 449 return; 450 for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--) 451 free((char *)(*inpp)); 452 free((char *)inphead); 453 free((char *)inpsort); 454 inphead = inpsort = NULL; 455 } 456 457 void 458 inodirty() 459 { 460 461 dirty(pbp); 462 } 463 464 void 465 clri(idesc, type, flag) 466 struct inodesc *idesc; 467 char *type; 468 int flag; 469 { 470 struct ext2fs_dinode *dp; 471 472 dp = ginode(idesc->id_number); 473 if (flag == 1) { 474 pwarn("%s %s", type, 475 (dp->e2di_mode & IFMT) == IFDIR ? "DIR" : "FILE"); 476 pinode(idesc->id_number); 477 } 478 if (preen || reply("CLEAR") == 1) { 479 if (preen) 480 printf(" (CLEARED)\n"); 481 n_files--; 482 (void)ckinode(dp, idesc); 483 clearinode(dp); 484 statemap[idesc->id_number] = USTATE; 485 inodirty(); 486 } 487 } 488 489 int 490 findname(idesc) 491 struct inodesc *idesc; 492 { 493 struct ext2fs_direct *dirp = idesc->id_dirp; 494 495 if (dirp->e2d_ino != idesc->id_parent) 496 return (KEEPON); 497 memcpy(idesc->id_name, dirp->e2d_name, (size_t)dirp->e2d_namlen); 498 idesc->id_name[dirp->e2d_namlen] = '\0'; 499 return (STOP|FOUND); 500 } 501 502 int 503 findino(idesc) 504 struct inodesc *idesc; 505 { 506 struct ext2fs_direct *dirp = idesc->id_dirp; 507 508 if (dirp->e2d_ino == 0) 509 return (KEEPON); 510 if (strcmp(dirp->e2d_name, idesc->id_name) == 0 && 511 (dirp->e2d_ino == EXT2_ROOTINO || dirp->e2d_ino >= EXT2_FIRSTINO) 512 && dirp->e2d_ino <= maxino) { 513 idesc->id_parent = dirp->e2d_ino; 514 return (STOP|FOUND); 515 } 516 return (KEEPON); 517 } 518 519 void 520 pinode(ino) 521 ino_t ino; 522 { 523 struct ext2fs_dinode *dp; 524 char *p; 525 struct passwd *pw; 526 time_t t; 527 528 printf(" I=%u ", ino); 529 if ((ino < EXT2_FIRSTINO && ino != EXT2_ROOTINO) || ino > maxino) 530 return; 531 dp = ginode(ino); 532 printf(" OWNER="); 533 #ifndef SMALL 534 if ((pw = getpwuid((int)dp->e2di_uid)) != 0) 535 printf("%s ", pw->pw_name); 536 else 537 #endif 538 printf("%u ", (unsigned)dp->e2di_uid); 539 printf("MODE=%o\n", dp->e2di_mode); 540 if (preen) 541 printf("%s: ", cdevname()); 542 printf("SIZE=%u ", dp->e2di_size); 543 t = dp->e2di_mtime; 544 p = ctime(&t); 545 printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]); 546 } 547 548 void 549 blkerror(ino, type, blk) 550 ino_t ino; 551 char *type; 552 daddr_t blk; 553 { 554 555 pfatal("%d %s I=%u", blk, type, ino); 556 printf("\n"); 557 switch (statemap[ino]) { 558 559 case FSTATE: 560 statemap[ino] = FCLEAR; 561 return; 562 563 case DSTATE: 564 statemap[ino] = DCLEAR; 565 return; 566 567 case FCLEAR: 568 case DCLEAR: 569 return; 570 571 default: 572 errexit("BAD STATE %d TO BLKERR\n", statemap[ino]); 573 /* NOTREACHED */ 574 } 575 } 576 577 /* 578 * allocate an unused inode 579 */ 580 ino_t 581 allocino(request, type) 582 ino_t request; 583 int type; 584 { 585 ino_t ino; 586 struct ext2fs_dinode *dp; 587 time_t t; 588 589 if (request == 0) 590 request = EXT2_ROOTINO; 591 else if (statemap[request] != USTATE) 592 return (0); 593 for (ino = request; ino < maxino; ino++) { 594 if ((ino > EXT2_ROOTINO) && (ino < EXT2_FIRSTINO)) 595 continue; 596 if (statemap[ino] == USTATE) 597 break; 598 } 599 if (ino == maxino) 600 return (0); 601 switch (type & IFMT) { 602 case IFDIR: 603 statemap[ino] = DSTATE; 604 break; 605 case IFREG: 606 case IFLNK: 607 statemap[ino] = FSTATE; 608 break; 609 default: 610 return (0); 611 } 612 dp = ginode(ino); 613 dp->e2di_blocks[0] = allocblk(); 614 if (dp->e2di_blocks[0] == 0) { 615 statemap[ino] = USTATE; 616 return (0); 617 } 618 dp->e2di_mode = type; 619 (void)time(&t); 620 dp->e2di_atime = t; 621 dp->e2di_mtime = dp->e2di_ctime = dp->e2di_atime; 622 dp->e2di_dtime = 0; 623 dp->e2di_size = sblock.e2fs_bsize; 624 dp->e2di_nblock = btodb(sblock.e2fs_bsize); 625 n_files++; 626 inodirty(); 627 return (ino); 628 } 629 630 /* 631 * deallocate an inode 632 */ 633 void 634 freeino(ino) 635 ino_t ino; 636 { 637 struct inodesc idesc; 638 struct ext2fs_dinode *dp; 639 640 memset(&idesc, 0, sizeof(struct inodesc)); 641 idesc.id_type = ADDR; 642 idesc.id_func = pass4check; 643 idesc.id_number = ino; 644 dp = ginode(ino); 645 (void)ckinode(dp, &idesc); 646 clearinode(dp); 647 inodirty(); 648 statemap[ino] = USTATE; 649 n_files--; 650 } 651