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