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