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