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