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