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