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