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