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