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