1 /* $NetBSD: inode.c,v 1.11 2001/07/13 20:30:18 perseant Exp $ */ 2 3 /* 4 * Copyright (c) 1997, 1998 5 * Konrad Schroder. All rights reserved. 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 #include <sys/param.h> 39 #include <sys/time.h> 40 #include <ufs/ufs/dinode.h> 41 #include <ufs/ufs/dir.h> 42 #include <sys/mount.h> /* XXX */ 43 #include <ufs/lfs/lfs.h> 44 #ifndef SMALL 45 #include <pwd.h> 46 #endif 47 #include <stdio.h> 48 #include <stdlib.h> 49 #include <string.h> 50 51 #include "fsck.h" 52 #include "fsutil.h" 53 #include "extern.h" 54 55 extern SEGUSE *seg_table; 56 extern daddr_t *din_table; 57 58 static int iblock(struct inodesc *, long, u_int64_t); 59 int blksreqd(struct lfs *, int); 60 int lfs_maxino(void); 61 /* static void dump_inoblk (struct lfs *, struct dinode *); */ 62 63 /* stolen from lfs_inode.c */ 64 /* Search a block for a specific dinode. */ 65 struct dinode * 66 lfs_difind(struct lfs * fs, ino_t ino, struct dinode * dip) 67 { 68 struct dinode *ldip, *fin; 69 70 #ifdef LFS_IFILE_FRAG_ADDRESSING 71 if (fs->lfs_version == 1) 72 fin = dip + INOPB(fs); 73 else 74 fin = dip + INOPF(fs); 75 #else 76 fin = dip + INOPB(fs); 77 #endif 78 79 for (ldip = dip; ldip < fin; ++ldip) { 80 if (ldip->di_inumber == ino) 81 return ldip; 82 } 83 /* printf("lfs_difind: dinode %u not found\n", ino); */ 84 return NULL; 85 } 86 87 /* 88 * Calculate the number of blocks required to be able to address data block 89 * blkno (counting, of course, indirect blocks). blkno must >=0. 90 */ 91 int 92 blksreqd(struct lfs * fs, int blkno) 93 { 94 long n = blkno; 95 96 if (blkno < NDADDR) 97 return blkno; 98 n -= NDADDR; 99 if (n < NINDIR(fs)) 100 return blkno + 1; 101 n -= NINDIR(fs); 102 if (n < NINDIR(fs) * NINDIR(fs)) 103 return blkno + 2 + n / NINDIR(fs) + 1; 104 n -= NINDIR(fs) * NINDIR(fs); 105 return blkno + 2 + NINDIR(fs) + n / (NINDIR(fs) * NINDIR(fs)) + 1; 106 } 107 108 #define BASE_SINDIR (NDADDR) 109 #define BASE_DINDIR (NDADDR+NINDIR(fs)) 110 #define BASE_TINDIR (NDADDR+NINDIR(fs)+NINDIR(fs)*NINDIR(fs)) 111 112 #define D_UNITS (NINDIR(fs)) 113 #define T_UNITS (NINDIR(fs)*NINDIR(fs)) 114 115 ufs_daddr_t lfs_bmap(struct lfs *, struct dinode *, ufs_daddr_t); 116 117 ufs_daddr_t 118 lfs_bmap(struct lfs * fs, struct dinode * idinode, ufs_daddr_t lbn) 119 { 120 ufs_daddr_t residue, up, off = 0; 121 struct bufarea *bp; 122 123 if (lbn > 0 && lbn > (idinode->di_size - 1) / dev_bsize) { 124 return UNASSIGNED; 125 } 126 /* 127 * Indirect blocks: if it is a first-level indirect, pull its 128 * address from the inode; otherwise, call ourselves to find the 129 * address of the parent indirect block, and load that to find 130 * the desired address. 131 */ 132 if (lbn < 0) { 133 lbn *= -1; 134 if (lbn == NDADDR) { 135 /* printf("lbn %d: single indir base\n", -lbn); */ 136 return idinode->di_ib[0]; /* single indirect */ 137 } else if (lbn == BASE_DINDIR + 1) { 138 /* printf("lbn %d: double indir base\n", -lbn); */ 139 return idinode->di_ib[1]; /* double indirect */ 140 } else if (lbn == BASE_TINDIR + 2) { 141 /* printf("lbn %d: triple indir base\n", -lbn); */ 142 return idinode->di_ib[2]; /* triple indirect */ 143 } 144 /* 145 * Find the immediate parent. This is essentially finding the 146 * residue of modulus, and then rounding accordingly. 147 */ 148 residue = (lbn - NDADDR) % NINDIR(fs); 149 if (residue == 1) { 150 /* Double indirect. Parent is the triple. */ 151 up = idinode->di_ib[2]; 152 off = (lbn - 2 - BASE_TINDIR) / (NINDIR(fs) * NINDIR(fs)); 153 if (up == UNASSIGNED || up == LFS_UNUSED_DADDR) 154 return UNASSIGNED; 155 /* printf("lbn %d: parent is the triple\n", -lbn); */ 156 bp = getddblk(up, sblock.lfs_bsize); 157 bp->b_flags &= ~B_INUSE; 158 return ((daddr_t *)(bp->b_un.b_buf))[off]; 159 } else { /* residue == 0 */ 160 /* Single indirect. Two cases. */ 161 if (lbn < BASE_TINDIR) { 162 /* Parent is the double, simple */ 163 up = -(BASE_DINDIR) - 1; 164 off = (lbn - BASE_DINDIR) / D_UNITS; 165 /* 166 * printf("lbn %d: parent is %d/%d\n", -lbn, 167 * up,off); 168 */ 169 } else { 170 /* Ancestor is the triple, more complex */ 171 up = ((lbn - BASE_TINDIR) / T_UNITS) 172 * T_UNITS + BASE_TINDIR + 1; 173 off = (lbn / D_UNITS) - (up / D_UNITS); 174 up = -up; 175 /* 176 * printf("lbn %d: parent is %d/%d\n", -lbn, 177 * up,off); 178 */ 179 } 180 } 181 } else { 182 /* Direct block. Its parent must be a single indirect. */ 183 if (lbn < NDADDR) 184 return idinode->di_db[lbn]; 185 else { 186 /* Parent is an indirect block. */ 187 up = -(((lbn - NDADDR) / D_UNITS) * D_UNITS + NDADDR); 188 off = (lbn - NDADDR) % D_UNITS; 189 /* printf("lbn %d: parent is %d/%d\n", lbn,up,off); */ 190 } 191 } 192 up = lfs_bmap(fs, idinode, up); 193 if (up == UNASSIGNED || up == LFS_UNUSED_DADDR) 194 return UNASSIGNED; 195 bp = getddblk(up, sblock.lfs_bsize); 196 bp->b_flags &= ~B_INUSE; 197 return ((daddr_t *)(bp->b_un.b_buf))[off]; 198 } 199 200 /* 201 * This is kind of gross. We use this to find the nth block 202 * from a file whose inode has disk address idaddr. In practice 203 * we will only use this to find blocks of the ifile. 204 */ 205 static struct bufarea empty; 206 207 struct bufarea * 208 getfileblk(struct lfs * fs, struct dinode * idinode, ino_t lbn) 209 { 210 struct bufarea *bp; 211 ufs_daddr_t blkno; 212 static char empty_buf[65536]; 213 214 empty.b_un.b_buf = &(empty_buf[0]); 215 216 blkno = lfs_bmap(fs, idinode, lbn); 217 if (blkno == UNASSIGNED || blkno == LFS_UNUSED_DADDR) { 218 printf("Warning: ifile lbn %d unassigned!\n", lbn); 219 return ∅ 220 } 221 bp = getddblk(blkno, sblock.lfs_bsize); 222 return bp; 223 } 224 225 #if 0 226 static struct dinode * 227 gidinode(void) 228 { 229 static struct dinode *idinode; 230 231 if (!idinode) { /* only need to do this once */ 232 idinode = lfs_difind(&sblock, sblock.lfs_ifile, &ifblock); 233 } 234 return idinode; 235 } 236 #endif 237 238 struct ifile * 239 lfs_ientry(ino_t ino, struct bufarea ** bpp) 240 { 241 IFILE *ifp; 242 243 *bpp = getfileblk(&sblock, lfs_ginode(LFS_IFILE_INUM), 244 ino / sblock.lfs_ifpb + sblock.lfs_cleansz + 245 sblock.lfs_segtabsz); 246 if (*bpp == &empty) { 247 printf("Warning: ino %d ientry in unassigned block\n", ino); 248 } 249 if (*bpp) { 250 if (sblock.lfs_version > 1) { 251 ifp = (((IFILE *)((*bpp)->b_un.b_buf)) + 252 (ino % sblock.lfs_ifpb)); 253 } else { 254 ifp = (IFILE *)(((IFILE_V1 *) 255 ((*bpp)->b_un.b_buf)) + 256 (ino % sblock.lfs_ifpb)); 257 } 258 return ifp; 259 } else 260 return NULL; 261 } 262 263 SEGUSE * 264 lfs_gseguse(int segnum, struct bufarea ** bpp) 265 { 266 int blkno; 267 struct bufarea *bp; 268 269 blkno = segnum / sblock.lfs_sepb + sblock.lfs_cleansz; 270 (*bpp) = bp = getfileblk(&sblock, lfs_ginode(LFS_IFILE_INUM), blkno); 271 if (sblock.lfs_version == 1) 272 return (SEGUSE *)((SEGUSE_V1 *)(bp->b_un.b_buf) + 273 segnum % sblock.lfs_sepb); 274 else 275 return (SEGUSE *)(bp->b_un.b_buf) + segnum % sblock.lfs_sepb; 276 } 277 278 daddr_t 279 lfs_ino_daddr(ino_t inumber) 280 { 281 daddr_t daddr; 282 IFILE *ifp; 283 struct bufarea *bp; 284 285 if (din_table[inumber]) { 286 daddr = din_table[inumber]; 287 } else { 288 if (inumber == LFS_IFILE_INUM) 289 daddr = idaddr; 290 else { 291 ifp = lfs_ientry(inumber, &bp); 292 if (ifp == NULL) { 293 return NULL; 294 } 295 if (ifp->if_daddr == LFS_UNUSED_DADDR) { 296 bp->b_flags &= ~B_INUSE; 297 return NULL; 298 } 299 bp->b_flags &= ~B_INUSE; 300 daddr = ifp->if_daddr; 301 } 302 303 din_table[inumber] = daddr; 304 seg_table[dtosn(&sblock, daddr)].su_nbytes += DINODE_SIZE; 305 } 306 return daddr; 307 } 308 309 struct dinode * 310 lfs_ginode(ino_t inumber) 311 { 312 struct ifile *ifp; 313 struct dinode *din; 314 struct bufarea *bp; 315 daddr_t daddr; 316 317 if (inumber >= maxino) 318 errexit("bad inode number %d to lfs_ginode\n", inumber); 319 320 #if 0 321 if (inumber == LFS_IFILE_INUM) { 322 daddr = idaddr; 323 if (din_table[LFS_IFILE_INUM] == 0) { 324 din_table[LFS_IFILE_INUM] = daddr; 325 seg_table[dtosn(&sblock, daddr)].su_nbytes += DINODE_SIZE; 326 } 327 return gidinode(); 328 } 329 #endif 330 331 daddr = lfs_ino_daddr(inumber); 332 if (daddr == 0) 333 return NULL; 334 335 if (pbp) 336 pbp->b_flags &= ~B_INUSE; 337 338 if (sblock.lfs_version == 1) 339 pbp = getddblk(daddr, sblock.lfs_bsize); 340 else 341 pbp = getddblk(daddr, sblock.lfs_fsize); 342 din = lfs_difind(&sblock, inumber, pbp->b_un.b_dinode); 343 344 if (din == NULL) { 345 pfatal("INODE %d NOT FOUND\n", inumber); 346 if (reply("free")) { 347 ifp = lfs_ientry(inumber, &bp); 348 ifp->if_daddr = LFS_UNUSED_DADDR; 349 ifp->if_nextfree = sblock.lfs_free; 350 sblock.lfs_free = inumber; 351 sbdirty(); 352 dirty(bp); 353 bp->b_flags &= ~B_INUSE; 354 } 355 } 356 return din; 357 } 358 359 /* imported from lfs_vfsops.c */ 360 int 361 ino_to_fsba(struct lfs * fs, ino_t ino) 362 { 363 daddr_t daddr = LFS_UNUSED_DADDR; 364 struct ifile *ifp; 365 struct bufarea *bp; 366 367 /* Translate the inode number to a disk address. */ 368 if (ino == LFS_IFILE_INUM) 369 daddr = fs->lfs_idaddr; 370 else { 371 ifp = lfs_ientry(ino, &bp); 372 if (ifp) { 373 daddr = ifp->if_daddr; 374 } else { 375 pwarn("Can't locate inode #%ud\n", ino); 376 } 377 bp->b_flags &= ~B_INUSE; 378 } 379 return daddr; 380 } 381 382 /* 383 * Check validity of held (direct) blocks in an inode. 384 */ 385 int 386 ckinode(struct dinode *dp, struct inodesc *idesc) 387 { 388 register ufs_daddr_t *ap; 389 long ret, n, ndb, offset; 390 struct dinode dino; 391 u_int64_t remsize, sizepb; 392 mode_t mode; 393 char pathbuf[MAXPATHLEN + 1]; 394 395 if (idesc->id_fix != IGNORE) 396 idesc->id_fix = DONTKNOW; 397 idesc->id_entryno = 0; 398 idesc->id_filesize = dp->di_size; 399 mode = dp->di_mode & IFMT; 400 if (mode == IFBLK || mode == IFCHR || 401 (mode == IFLNK && (dp->di_size < sblock.lfs_maxsymlinklen || 402 (sblock.lfs_maxsymlinklen == 0 && 403 dp->di_blocks == 0)))) 404 return (KEEPON); 405 dino = *dp; 406 ndb = howmany(dino.di_size, sblock.lfs_bsize); 407 408 for (ap = &dino.di_db[0]; ap < &dino.di_db[NDADDR]; ap++) { 409 if (--ndb == 0 && (offset = blkoff(&sblock, dino.di_size)) != 0) { 410 idesc->id_numfrags = 411 numfrags(&sblock, fragroundup(&sblock, offset)); 412 } else 413 idesc->id_numfrags = sblock.lfs_frag; 414 if (*ap == 0) { 415 if (idesc->id_type == DATA && ndb >= 0) { 416 /* An empty block in a directory XXX */ 417 getpathname(pathbuf, idesc->id_number, 418 idesc->id_number); 419 pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", 420 pathbuf); 421 if (reply("ADJUST LENGTH") == 1) { 422 dp = ginode(idesc->id_number); 423 dp->di_size = (ap - &dino.di_db[0]) * 424 sblock.lfs_bsize; 425 printf( 426 "YOU MUST RERUN FSCK AFTERWARDS\n"); 427 rerun = 1; 428 inodirty(); 429 } 430 } 431 continue; 432 } 433 idesc->id_blkno = *ap; 434 idesc->id_lblkno = ap - &dino.di_db[0]; 435 if (idesc->id_type == ADDR) { 436 ret = (*idesc->id_func)(idesc); 437 } else 438 ret = dirscan(idesc); 439 idesc->id_lblkno = 0; 440 if (ret & STOP) 441 return (ret); 442 } 443 idesc->id_numfrags = sblock.lfs_frag; 444 remsize = dino.di_size - sblock.lfs_bsize * NDADDR; 445 sizepb = sblock.lfs_bsize; 446 for (ap = &dino.di_ib[0], n = 1; n <= NIADDR; ap++, n++) { 447 if (*ap) { 448 idesc->id_blkno = *ap; 449 ret = iblock(idesc, n, remsize); 450 if (ret & STOP) 451 return (ret); 452 } else { 453 if (idesc->id_type == DATA && remsize > 0) { 454 /* An empty block in a directory XXX */ 455 getpathname(pathbuf, idesc->id_number, 456 idesc->id_number); 457 pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", 458 pathbuf); 459 if (reply("ADJUST LENGTH") == 1) { 460 dp = ginode(idesc->id_number); 461 dp->di_size -= remsize; 462 remsize = 0; 463 printf( 464 "YOU MUST RERUN FSCK AFTERWARDS\n"); 465 rerun = 1; 466 inodirty(); 467 break; 468 } 469 } 470 } 471 sizepb *= NINDIR(&sblock); 472 remsize -= sizepb; 473 } 474 return (KEEPON); 475 } 476 477 static int 478 iblock(struct inodesc * idesc, long ilevel, u_int64_t isize) 479 { 480 daddr_t *ap, *aplim; 481 struct bufarea *bp; 482 int i, n, (*func)(struct inodesc *), nif; 483 u_int64_t sizepb; 484 char pathbuf[MAXPATHLEN + 1], buf[BUFSIZ]; 485 struct dinode *dp; 486 487 if (idesc->id_type == ADDR) { 488 func = idesc->id_func; 489 n = (*func)(idesc); 490 if ((n & KEEPON) == 0) 491 return (n); 492 } else 493 func = dirscan; 494 if (chkrange(idesc->id_blkno, fragstofsb(&sblock, idesc->id_numfrags))) 495 return (SKIP); 496 bp = getddblk(idesc->id_blkno, sblock.lfs_bsize); 497 ilevel--; 498 for (sizepb = sblock.lfs_bsize, i = 0; i < ilevel; i++) 499 sizepb *= NINDIR(&sblock); 500 if (isize > sizepb * NINDIR(&sblock)) 501 nif = NINDIR(&sblock); 502 else 503 nif = howmany(isize, sizepb); 504 if (idesc->id_func == pass1check && nif < NINDIR(&sblock)) { 505 aplim = &bp->b_un.b_indir[NINDIR(&sblock)]; 506 for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) { 507 if (*ap == 0) 508 continue; 509 (void)sprintf(buf, "PARTIALLY TRUNCATED INODE I=%u", 510 idesc->id_number); 511 if (dofix(idesc, buf)) { 512 *ap = 0; 513 dirty(bp); 514 } 515 } 516 flush(fswritefd, bp); 517 } 518 aplim = &bp->b_un.b_indir[nif]; 519 for (ap = bp->b_un.b_indir; ap < aplim; ap++) { 520 if (*ap) { 521 idesc->id_blkno = *ap; 522 if (ilevel == 0) 523 n = (*func)(idesc); 524 else 525 n = iblock(idesc, ilevel, isize); 526 if (n & STOP) { 527 bp->b_flags &= ~B_INUSE; 528 return (n); 529 } 530 } else { 531 if (idesc->id_type == DATA && isize > 0) { 532 /* An empty block in a directory XXX */ 533 getpathname(pathbuf, idesc->id_number, 534 idesc->id_number); 535 pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", 536 pathbuf); 537 if (reply("ADJUST LENGTH") == 1) { 538 dp = ginode(idesc->id_number); 539 dp->di_size -= isize; 540 isize = 0; 541 printf( 542 "YOU MUST RERUN FSCK AFTERWARDS\n"); 543 rerun = 1; 544 inodirty(); 545 bp->b_flags &= ~B_INUSE; 546 return (STOP); 547 } 548 } 549 } 550 isize -= sizepb; 551 } 552 bp->b_flags &= ~B_INUSE; 553 return (KEEPON); 554 } 555 556 /* 557 * Check that a block in a legal block number. 558 * Return 0 if in range, 1 if out of range. 559 */ 560 int 561 chkrange(daddr_t blk, int cnt) 562 { 563 if (blk < sntod(&sblock, 0)) { 564 return (1); 565 } 566 if (blk > maxfsblock) { 567 return (1); 568 } 569 if (blk + cnt < sntod(&sblock, 0)) { 570 return (1); 571 } 572 if (blk + cnt > maxfsblock) { 573 return (1); 574 } 575 return (0); 576 } 577 578 /* 579 * General purpose interface for reading inodes. 580 */ 581 struct dinode * 582 ginode(ino_t inumber) 583 { 584 return lfs_ginode(inumber); 585 } 586 587 /* 588 * Routines to maintain information about directory inodes. 589 * This is built during the first pass and used during the 590 * second and third passes. 591 * 592 * Enter inodes into the cache. 593 */ 594 void 595 cacheino(struct dinode *dp, ino_t inumber) 596 { 597 register struct inoinfo *inp; 598 struct inoinfo **inpp; 599 unsigned int blks; 600 601 blks = howmany(dp->di_size, sblock.lfs_bsize); 602 if (blks > NDADDR) 603 blks = NDADDR + NIADDR; 604 inp = (struct inoinfo *) 605 malloc(sizeof(*inp) + (blks - 1) * sizeof(daddr_t)); 606 if (inp == NULL) 607 return; 608 inpp = &inphead[inumber % numdirs]; 609 inp->i_nexthash = *inpp; 610 *inpp = inp; 611 inp->i_child = inp->i_sibling = inp->i_parentp = 0; 612 if (inumber == ROOTINO) 613 inp->i_parent = ROOTINO; 614 else 615 inp->i_parent = (ino_t)0; 616 inp->i_dotdot = (ino_t)0; 617 inp->i_number = inumber; 618 inp->i_isize = dp->di_size; 619 inp->i_numblks = blks * sizeof(daddr_t); 620 memcpy(&inp->i_blks[0], &dp->di_db[0], (size_t)inp->i_numblks); 621 if (inplast == listmax) { 622 listmax += 100; 623 inpsort = (struct inoinfo **)realloc((char *) inpsort, 624 (unsigned)listmax * sizeof(struct inoinfo *)); 625 if (inpsort == NULL) 626 errexit("cannot increase directory list"); 627 } 628 inpsort[inplast++] = inp; 629 } 630 631 /* 632 * Look up an inode cache structure. 633 */ 634 struct inoinfo * 635 getinoinfo(ino_t inumber) 636 { 637 register struct inoinfo *inp; 638 639 for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) { 640 if (inp->i_number != inumber) 641 continue; 642 return (inp); 643 } 644 errexit("cannot find inode %d\n", inumber); 645 return ((struct inoinfo *)0); 646 } 647 648 /* 649 * Clean up all the inode cache structure. 650 */ 651 void 652 inocleanup() 653 { 654 register struct inoinfo **inpp; 655 656 if (inphead == NULL) 657 return; 658 for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--) 659 free((char *)(*inpp)); 660 free((char *)inphead); 661 free((char *)inpsort); 662 inphead = inpsort = NULL; 663 } 664 665 void 666 inodirty() 667 { 668 dirty(pbp); 669 } 670 671 void 672 clri(struct inodesc *idesc, char *type, int flag) 673 { 674 register struct dinode *dp; 675 struct bufarea *bp; 676 IFILE *ifp; 677 678 dp = ginode(idesc->id_number); 679 if (flag == 1) { 680 pwarn("%s %s", type, 681 (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE"); 682 pinode(idesc->id_number); 683 } 684 if (preen || reply("CLEAR") == 1) { 685 if (preen) 686 printf(" (CLEARED)\n"); 687 n_files--; 688 (void)ckinode(dp, idesc); 689 clearinode(dp); 690 statemap[idesc->id_number] = USTATE; 691 inodirty(); 692 693 /* Send cleared inode to the free list */ 694 695 ifp = lfs_ientry(idesc->id_number, &bp); 696 ifp->if_daddr = LFS_UNUSED_DADDR; 697 ifp->if_nextfree = sblock.lfs_free; 698 sblock.lfs_free = idesc->id_number; 699 sbdirty(); 700 dirty(bp); 701 bp->b_flags &= ~B_INUSE; 702 } 703 } 704 705 int 706 findname(struct inodesc *idesc) 707 { 708 register struct direct *dirp = idesc->id_dirp; 709 710 if (dirp->d_ino != idesc->id_parent) 711 return (KEEPON); 712 memcpy(idesc->id_name, dirp->d_name, (size_t)dirp->d_namlen + 1); 713 return (STOP | FOUND); 714 } 715 716 int 717 findino(struct inodesc *idesc) 718 { 719 register struct direct *dirp = idesc->id_dirp; 720 721 if (dirp->d_ino == 0) 722 return (KEEPON); 723 if (strcmp(dirp->d_name, idesc->id_name) == 0 && 724 dirp->d_ino >= ROOTINO && dirp->d_ino < maxino) { 725 idesc->id_parent = dirp->d_ino; 726 return (STOP | FOUND); 727 } 728 return (KEEPON); 729 } 730 731 void 732 pinode(ino_t ino) 733 { 734 register struct dinode *dp; 735 register char *p; 736 struct passwd *pw; 737 time_t t; 738 739 printf(" I=%u ", ino); 740 if (ino < ROOTINO || ino >= maxino) 741 return; 742 dp = ginode(ino); 743 if (dp) { 744 printf(" OWNER="); 745 #ifndef SMALL 746 if ((pw = getpwuid((int)dp->di_uid)) != 0) 747 printf("%s ", pw->pw_name); 748 else 749 #endif 750 printf("%u ", (unsigned)dp->di_uid); 751 printf("MODE=%o\n", dp->di_mode); 752 if (preen) 753 printf("%s: ", cdevname()); 754 printf("SIZE=%llu ", (unsigned long long)dp->di_size); 755 t = dp->di_mtime; 756 p = ctime(&t); 757 printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]); 758 } 759 } 760 761 void 762 blkerror(ino_t ino, char *type, daddr_t blk) 763 { 764 765 pfatal("%d %s I=%u", blk, type, ino); 766 printf("\n"); 767 if (exitonfail) 768 exit(1); 769 switch (statemap[ino]) { 770 771 case FSTATE: 772 statemap[ino] = FCLEAR; 773 return; 774 775 case DSTATE: 776 statemap[ino] = DCLEAR; 777 return; 778 779 case FCLEAR: 780 case DCLEAR: 781 return; 782 783 default: 784 errexit("BAD STATE %d TO BLKERR", statemap[ino]); 785 /* NOTREACHED */ 786 } 787 } 788 789 /* 790 * allocate an unused inode 791 */ 792 ino_t 793 allocino(ino_t request, int type) 794 { 795 register ino_t ino; 796 register struct dinode *dp; 797 time_t t; 798 799 if (request == 0) 800 request = ROOTINO; 801 else if (statemap[request] != USTATE) 802 return (0); 803 for (ino = request; ino < maxino; ino++) 804 if (statemap[ino] == USTATE) 805 break; 806 if (ino == maxino) 807 return (0); 808 switch (type & IFMT) { 809 case IFDIR: 810 statemap[ino] = DSTATE; 811 break; 812 case IFREG: 813 case IFLNK: 814 statemap[ino] = FSTATE; 815 break; 816 default: 817 return (0); 818 } 819 dp = ginode(ino); 820 dp->di_db[0] = allocblk((long)1); 821 if (dp->di_db[0] == 0) { 822 statemap[ino] = USTATE; 823 return (0); 824 } 825 dp->di_mode = type; 826 (void)time(&t); 827 dp->di_atime = t; 828 dp->di_mtime = dp->di_ctime = dp->di_atime; 829 dp->di_size = sblock.lfs_fsize; 830 dp->di_blocks = btofsb(&sblock, sblock.lfs_fsize); 831 n_files++; 832 inodirty(); 833 if (newinofmt) 834 typemap[ino] = IFTODT(type); 835 return (ino); 836 } 837 838 /* 839 * deallocate an inode 840 */ 841 void 842 freeino(ino_t ino) 843 { 844 struct inodesc idesc; 845 struct dinode *dp; 846 847 memset(&idesc, 0, sizeof(struct inodesc)); 848 idesc.id_type = ADDR; 849 idesc.id_func = pass4check; 850 idesc.id_number = ino; 851 dp = ginode(ino); 852 (void)ckinode(dp, &idesc); 853 clearinode(dp); 854 inodirty(); 855 statemap[ino] = USTATE; 856 857 n_files--; 858 } 859