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