1 /* $NetBSD: inode.c,v 1.51 2005/01/20 15:29:40 xtraeme Exp $ */ 2 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 #include <sys/cdefs.h> 33 #ifndef lint 34 #if 0 35 static char sccsid[] = "@(#)inode.c 8.8 (Berkeley) 4/28/95"; 36 #else 37 __RCSID("$NetBSD: inode.c,v 1.51 2005/01/20 15:29:40 xtraeme Exp $"); 38 #endif 39 #endif /* not lint */ 40 41 #include <sys/param.h> 42 #include <sys/time.h> 43 44 #include <ufs/ufs/dinode.h> 45 #include <ufs/ufs/dir.h> 46 #include <ufs/ffs/fs.h> 47 #include <ufs/ffs/ffs_extern.h> 48 #include <ufs/ufs/ufs_bswap.h> 49 50 #ifndef SMALL 51 #include <err.h> 52 #include <pwd.h> 53 #endif 54 #include <stdio.h> 55 #include <stdlib.h> 56 #include <string.h> 57 #include <time.h> 58 59 #include "fsck.h" 60 #include "fsutil.h" 61 #include "extern.h" 62 63 static ino_t startinum; 64 65 static int iblock(struct inodesc *, long, u_int64_t); 66 static void swap_dinode1(union dinode *, int); 67 static void swap_dinode2(union dinode *, int); 68 69 int 70 ckinode(union dinode *dp, struct inodesc *idesc) 71 { 72 int ret, offset, i; 73 union dinode dino; 74 u_int64_t sizepb; 75 int64_t remsize; 76 daddr_t ndb; 77 mode_t mode; 78 char pathbuf[MAXPATHLEN + 1]; 79 80 if (idesc->id_fix != IGNORE) 81 idesc->id_fix = DONTKNOW; 82 idesc->id_entryno = 0; 83 idesc->id_filesize = iswap64(DIP(dp, size)); 84 mode = iswap16(DIP(dp, mode)) & IFMT; 85 if (mode == IFBLK || mode == IFCHR || (mode == IFLNK && 86 (idesc->id_filesize < sblock->fs_maxsymlinklen || 87 (isappleufs && (idesc->id_filesize < APPLEUFS_MAXSYMLINKLEN)) || 88 (sblock->fs_maxsymlinklen == 0 && DIP(dp, blocks) == 0)))) 89 return (KEEPON); 90 if (is_ufs2) 91 dino.dp2 = dp->dp2; 92 else 93 dino.dp1 = dp->dp1; 94 ndb = howmany(iswap64(DIP(&dino, size)), sblock->fs_bsize); 95 for (i = 0; i < NDADDR; i++) { 96 if (--ndb == 0 && 97 (offset = blkoff(sblock, iswap64(DIP(&dino, size)))) != 0) 98 idesc->id_numfrags = 99 numfrags(sblock, fragroundup(sblock, offset)); 100 else 101 idesc->id_numfrags = sblock->fs_frag; 102 if (DIP(&dino, db[i]) == 0) { 103 if (idesc->id_type == DATA && ndb >= 0) { 104 /* An empty block in a directory XXX */ 105 markclean = 0; 106 getpathname(pathbuf, sizeof(pathbuf), 107 idesc->id_number, idesc->id_number); 108 pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS I", 109 pathbuf); 110 abort(); 111 if (reply("ADJUST LENGTH") == 1) { 112 dp = ginode(idesc->id_number); 113 DIP(dp, size) = iswap64(i * 114 sblock->fs_bsize); 115 printf( 116 "YOU MUST RERUN FSCK AFTERWARDS\n"); 117 rerun = 1; 118 inodirty(); 119 } 120 } 121 continue; 122 } 123 if (is_ufs2) 124 idesc->id_blkno = iswap64(dino.dp2.di_db[i]); 125 else 126 idesc->id_blkno = iswap32(dino.dp1.di_db[i]); 127 if (idesc->id_type != DATA) 128 ret = (*idesc->id_func)(idesc); 129 else 130 ret = dirscan(idesc); 131 if (ret & STOP) 132 return (ret); 133 } 134 idesc->id_numfrags = sblock->fs_frag; 135 remsize = iswap64(DIP(&dino, size)) - sblock->fs_bsize * NDADDR; 136 sizepb = sblock->fs_bsize; 137 for (i = 0; i < NIADDR; i++) { 138 if (DIP(&dino, ib[i])) { 139 if (is_ufs2) 140 idesc->id_blkno = iswap64(dino.dp2.di_ib[i]); 141 else 142 idesc->id_blkno = iswap32(dino.dp1.di_ib[i]); 143 ret = iblock(idesc, i + 1, remsize); 144 if (ret & STOP) 145 return (ret); 146 } else { 147 if (idesc->id_type == DATA && remsize > 0) { 148 /* An empty block in a directory XXX */ 149 markclean = 0; 150 getpathname(pathbuf, sizeof(pathbuf), 151 idesc->id_number, idesc->id_number); 152 pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", 153 pathbuf); 154 if (reply("ADJUST LENGTH") == 1) { 155 dp = ginode(idesc->id_number); 156 DIP(dp, size) = 157 iswap64(iswap64(DIP(dp, size)) 158 - remsize); 159 remsize = 0; 160 printf( 161 "YOU MUST RERUN FSCK AFTERWARDS\n"); 162 rerun = 1; 163 inodirty(); 164 break; 165 } 166 } 167 } 168 sizepb *= NINDIR(sblock); 169 remsize -= sizepb; 170 } 171 return (KEEPON); 172 } 173 174 static int 175 iblock(struct inodesc *idesc, long ilevel, u_int64_t isize) 176 { 177 struct bufarea *bp; 178 int i, n, (*func) (struct inodesc *), nif; 179 u_int64_t sizepb; 180 char buf[BUFSIZ]; 181 char pathbuf[MAXPATHLEN + 1]; 182 union dinode *dp; 183 184 if (idesc->id_type != DATA) { 185 func = idesc->id_func; 186 if (((n = (*func)(idesc)) & KEEPON) == 0) 187 return (n); 188 } else 189 func = dirscan; 190 if (chkrange(idesc->id_blkno, idesc->id_numfrags)) 191 return (SKIP); 192 bp = getdatablk(idesc->id_blkno, sblock->fs_bsize); 193 ilevel--; 194 for (sizepb = sblock->fs_bsize, i = 0; i < ilevel; i++) 195 sizepb *= NINDIR(sblock); 196 if (howmany(isize, sizepb) > NINDIR(sblock)) 197 nif = NINDIR(sblock); 198 else 199 nif = howmany(isize, sizepb); 200 if (do_blkswap) { /* swap byte order of the whole blk */ 201 if (is_ufs2) { 202 for (i = 0; i < nif; i++) 203 bp->b_un.b_indir2[i] = 204 bswap64(bp->b_un.b_indir2[i]); 205 } else { 206 for (i = 0; i < nif; i++) 207 bp->b_un.b_indir1[i] = 208 bswap32(bp->b_un.b_indir1[i]); 209 } 210 dirty(bp); 211 flush(fswritefd, bp); 212 } 213 if (idesc->id_func == pass1check && nif < NINDIR(sblock)) { 214 for (i = nif; i < NINDIR(sblock); i++) { 215 if (IBLK(bp, i) == 0) 216 continue; 217 (void)snprintf(buf, sizeof(buf), 218 "PARTIALLY TRUNCATED INODE I=%u", idesc->id_number); 219 if (dofix(idesc, buf)) { 220 IBLK(bp, i) = 0; 221 dirty(bp); 222 } else 223 markclean= 0; 224 } 225 flush(fswritefd, bp); 226 } 227 for (i = 0; i < nif; i++) { 228 if (IBLK(bp, i)) { 229 if (is_ufs2) 230 idesc->id_blkno = iswap64(bp->b_un.b_indir2[i]); 231 else 232 idesc->id_blkno = iswap32(bp->b_un.b_indir1[i]); 233 if (ilevel == 0) 234 n = (*func)(idesc); 235 else 236 n = iblock(idesc, ilevel, isize); 237 if (n & STOP) { 238 bp->b_flags &= ~B_INUSE; 239 return (n); 240 } 241 } else { 242 if (idesc->id_type == DATA && isize > 0) { 243 /* An empty block in a directory XXX */ 244 markclean= 0; 245 getpathname(pathbuf, sizeof(pathbuf), 246 idesc->id_number, idesc->id_number); 247 pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", 248 pathbuf); 249 if (reply("ADJUST LENGTH") == 1) { 250 dp = ginode(idesc->id_number); 251 DIP(dp, size) = 252 iswap64(iswap64(DIP(dp, size)) 253 - isize); 254 isize = 0; 255 printf( 256 "YOU MUST RERUN FSCK AFTERWARDS\n"); 257 rerun = 1; 258 inodirty(); 259 bp->b_flags &= ~B_INUSE; 260 return(STOP); 261 } 262 } 263 } 264 isize -= sizepb; 265 } 266 bp->b_flags &= ~B_INUSE; 267 return (KEEPON); 268 } 269 270 /* 271 * Check that a block in a legal block number. 272 * Return 0 if in range, 1 if out of range. 273 */ 274 int 275 chkrange(daddr_t blk, int cnt) 276 { 277 int c; 278 279 if (cnt <= 0 || blk <= 0 || blk > maxfsblock || 280 cnt - 1 > maxfsblock - blk) 281 return (1); 282 if (cnt > sblock->fs_frag || 283 fragnum(sblock, blk) + cnt > sblock->fs_frag) { 284 if (debug) 285 printf("bad size: blk %lld, offset %d, size %d\n", 286 (long long)blk, (int)fragnum(sblock, blk), cnt); 287 } 288 c = dtog(sblock, blk); 289 if (blk < cgdmin(sblock, c)) { 290 if ((blk + cnt) > cgsblock(sblock, c)) { 291 if (debug) { 292 printf("blk %lld < cgdmin %lld;", 293 (long long)blk, 294 (long long)cgdmin(sblock, c)); 295 printf(" blk + cnt %lld > cgsbase %lld\n", 296 (long long)(blk + cnt), 297 (long long)cgsblock(sblock, c)); 298 } 299 return (1); 300 } 301 } else { 302 if ((blk + cnt) > cgbase(sblock, c+1)) { 303 if (debug) { 304 printf("blk %lld >= cgdmin %lld;", 305 (long long)blk, 306 (long long)cgdmin(sblock, c)); 307 printf(" blk + cnt %lld > sblock->fs_fpg %d\n", 308 (long long)(blk+cnt), sblock->fs_fpg); 309 } 310 return (1); 311 } 312 } 313 return (0); 314 } 315 316 /* 317 * General purpose interface for reading inodes. 318 */ 319 union dinode * 320 ginode(ino_t inumber) 321 { 322 daddr_t iblk; 323 int blkoff; 324 325 if (inumber < ROOTINO || inumber > maxino) 326 errx(EEXIT, "bad inode number %d to ginode", inumber); 327 if (startinum == 0 || 328 inumber < startinum || inumber >= startinum + INOPB(sblock)) { 329 iblk = ino_to_fsba(sblock, inumber); 330 if (pbp != 0) 331 pbp->b_flags &= ~B_INUSE; 332 pbp = getdatablk(iblk, sblock->fs_bsize); 333 startinum = (inumber / INOPB(sblock)) * INOPB(sblock); 334 } 335 if (is_ufs2) { 336 blkoff = (inumber % INOPB(sblock)) * DINODE2_SIZE; 337 return ((union dinode *)((caddr_t)pbp->b_un.b_buf + blkoff)); 338 } 339 blkoff = (inumber % INOPB(sblock)) * DINODE1_SIZE; 340 return ((union dinode *)((caddr_t)pbp->b_un.b_buf + blkoff)); 341 } 342 343 static void 344 swap_dinode1(union dinode *dp, int n) 345 { 346 int i, j; 347 struct ufs1_dinode *dp1; 348 int32_t maxsymlinklen = sblock->fs_maxsymlinklen; 349 if (isappleufs) 350 maxsymlinklen = APPLEUFS_MAXSYMLINKLEN; 351 352 dp1 = (struct ufs1_dinode *)&dp->dp1; 353 for (i = 0; i < n; i++, dp1++) { 354 ffs_dinode1_swap(dp1, dp1); 355 if (((iswap16(dp1->di_mode) & IFMT) != IFLNK) || 356 doinglevel2 || 357 (maxsymlinklen < 0) || 358 (iswap64(dp1->di_size) > maxsymlinklen)) { 359 for (j = 0; j < (NDADDR + NIADDR); j++) 360 dp1->di_db[j] = bswap32(dp1->di_db[j]); 361 } 362 } 363 } 364 365 static void 366 swap_dinode2(union dinode *dp, int n) 367 { 368 int i, j; 369 struct ufs2_dinode *dp2; 370 371 dp2 = (struct ufs2_dinode *)&dp->dp2; 372 for (i = 0; i < n; i++, dp2++) { 373 ffs_dinode2_swap(dp2, dp2); 374 if ((iswap16(dp2->di_mode) & IFMT) != IFLNK) { 375 for (j = 0; j < (NDADDR + NIADDR + NXADDR); j++) 376 dp2->di_extb[j] = bswap64(dp2->di_extb[j]); 377 } 378 } 379 } 380 381 /* 382 * Special purpose version of ginode used to optimize first pass 383 * over all the inodes in numerical order. 384 */ 385 ino_t nextino, lastinum, lastvalidinum; 386 long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize; 387 union dinode *inodebuf; 388 389 union dinode * 390 getnextinode(ino_t inumber) 391 { 392 long size; 393 daddr_t dblk; 394 static union dinode *dp; 395 union dinode *ret; 396 397 if (inumber != nextino++ || inumber > lastvalidinum) { 398 abort(); 399 errx(EEXIT, "bad inode number %d to nextinode", inumber); 400 } 401 402 if (inumber >= lastinum) { 403 readcnt++; 404 dblk = fsbtodb(sblock, ino_to_fsba(sblock, lastinum)); 405 if (readcnt % readpercg == 0) { 406 size = partialsize; 407 lastinum += partialcnt; 408 } else { 409 size = inobufsize; 410 lastinum += fullcnt; 411 } 412 (void)bread(fsreadfd, (caddr_t)inodebuf, dblk, size); 413 if (doswap) { 414 if (is_ufs2) 415 swap_dinode2(inodebuf, lastinum - inumber); 416 else 417 swap_dinode1(inodebuf, lastinum - inumber); 418 bwrite(fswritefd, (char *)inodebuf, dblk, size); 419 } 420 dp = (union dinode *)inodebuf; 421 } 422 ret = dp; 423 dp = (union dinode *) 424 ((char *)dp + (is_ufs2 ? DINODE2_SIZE : DINODE1_SIZE)); 425 return ret; 426 } 427 428 void 429 setinodebuf(ino_t inum) 430 { 431 432 if (inum % sblock->fs_ipg != 0) 433 errx(EEXIT, "bad inode number %d to setinodebuf", inum); 434 435 lastvalidinum = inum + sblock->fs_ipg - 1; 436 startinum = 0; 437 nextino = inum; 438 lastinum = inum; 439 readcnt = 0; 440 if (inodebuf != NULL) 441 return; 442 inobufsize = blkroundup(sblock, INOBUFSIZE); 443 fullcnt = inobufsize / (is_ufs2 ? DINODE2_SIZE : DINODE1_SIZE); 444 readpercg = sblock->fs_ipg / fullcnt; 445 partialcnt = sblock->fs_ipg % fullcnt; 446 partialsize = partialcnt * (is_ufs2 ? DINODE2_SIZE : DINODE1_SIZE); 447 if (partialcnt != 0) { 448 readpercg++; 449 } else { 450 partialcnt = fullcnt; 451 partialsize = inobufsize; 452 } 453 if (inodebuf == NULL && 454 (inodebuf = malloc((unsigned)inobufsize)) == NULL) 455 errx(EEXIT, "Cannot allocate space for inode buffer"); 456 } 457 458 void 459 freeinodebuf(void) 460 { 461 462 if (inodebuf != NULL) 463 free((char *)inodebuf); 464 inodebuf = NULL; 465 } 466 467 /* 468 * Routines to maintain information about directory inodes. 469 * This is built during the first pass and used during the 470 * second and third passes. 471 * 472 * Enter inodes into the cache. 473 */ 474 void 475 cacheino(union dinode *dp, ino_t inumber) 476 { 477 struct inoinfo *inp; 478 struct inoinfo **inpp, **ninpsort; 479 unsigned int blks; 480 int i; 481 int64_t size; 482 483 size = iswap64(DIP(dp, size)); 484 blks = howmany(size, sblock->fs_bsize); 485 if (blks > NDADDR) 486 blks = NDADDR + NIADDR; 487 488 inp = (struct inoinfo *) malloc(sizeof(*inp) + (blks - 1) 489 * sizeof (int64_t)); 490 if (inp == NULL) 491 return; 492 inpp = &inphead[inumber % dirhash]; 493 inp->i_nexthash = *inpp; 494 *inpp = inp; 495 inp->i_child = inp->i_sibling = 0; 496 if (inumber == ROOTINO) 497 inp->i_parent = ROOTINO; 498 else 499 inp->i_parent = (ino_t)0; 500 inp->i_dotdot = (ino_t)0; 501 inp->i_number = inumber; 502 inp->i_isize = size; 503 inp->i_numblks = blks; 504 for (i = 0; i < (blks < NDADDR ? blks : NDADDR); i++) 505 inp->i_blks[i] = DIP(dp, db[i]); 506 if (blks > NDADDR) 507 for (i = 0; i < NIADDR; i++) 508 inp->i_blks[NDADDR + i] = DIP(dp, ib[i]); 509 if (inplast == listmax) { 510 ninpsort = (struct inoinfo **)realloc((char *)inpsort, 511 (unsigned)(listmax + 100) * sizeof(struct inoinfo *)); 512 if (inpsort == NULL) 513 errx(EEXIT, "cannot increase directory list"); 514 inpsort = ninpsort; 515 listmax += 100; 516 } 517 inpsort[inplast++] = inp; 518 } 519 520 /* 521 * Look up an inode cache structure. 522 */ 523 struct inoinfo * 524 getinoinfo(ino_t inumber) 525 { 526 struct inoinfo *inp; 527 528 for (inp = inphead[inumber % dirhash]; inp; inp = inp->i_nexthash) { 529 if (inp->i_number != inumber) 530 continue; 531 return (inp); 532 } 533 errx(EEXIT, "cannot find inode %d", inumber); 534 return ((struct inoinfo *)0); 535 } 536 537 /* 538 * Clean up all the inode cache structure. 539 */ 540 void 541 inocleanup(void) 542 { 543 struct inoinfo **inpp; 544 545 if (inphead == NULL) 546 return; 547 for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--) 548 free((char *)(*inpp)); 549 free((char *)inphead); 550 free((char *)inpsort); 551 inphead = inpsort = NULL; 552 } 553 554 void 555 inodirty(void) 556 { 557 558 dirty(pbp); 559 } 560 561 void 562 clri(struct inodesc *idesc, char *type, int flag) 563 { 564 union dinode *dp; 565 566 dp = ginode(idesc->id_number); 567 if (flag == 1) { 568 pwarn("%s %s", type, 569 (iswap16(DIP(dp, mode)) & IFMT) == IFDIR ? "DIR" : "FILE"); 570 pinode(idesc->id_number); 571 } 572 if (preen || reply("CLEAR") == 1) { 573 if (preen) 574 printf(" (CLEARED)\n"); 575 n_files--; 576 (void)ckinode(dp, idesc); 577 clearinode(dp); 578 inoinfo(idesc->id_number)->ino_state = USTATE; 579 inodirty(); 580 } else 581 markclean= 0; 582 } 583 584 int 585 findname(struct inodesc *idesc) 586 { 587 struct direct *dirp = idesc->id_dirp; 588 589 if (iswap32(dirp->d_ino) != idesc->id_parent || idesc->id_entryno < 2) { 590 idesc->id_entryno++; 591 return (KEEPON); 592 } 593 memmove(idesc->id_name, dirp->d_name, (size_t)dirp->d_namlen + 1); 594 return (STOP|FOUND); 595 } 596 597 int 598 findino(struct inodesc *idesc) 599 { 600 struct direct *dirp = idesc->id_dirp; 601 602 if (dirp->d_ino == 0) 603 return (KEEPON); 604 if (strcmp(dirp->d_name, idesc->id_name) == 0 && 605 iswap32(dirp->d_ino) >= ROOTINO && iswap32(dirp->d_ino) <= maxino) { 606 idesc->id_parent = iswap32(dirp->d_ino); 607 return (STOP|FOUND); 608 } 609 return (KEEPON); 610 } 611 612 int 613 clearentry(struct inodesc *idesc) 614 { 615 struct direct *dirp = idesc->id_dirp; 616 617 if (dirp->d_ino != idesc->id_parent || idesc->id_entryno < 2) { 618 idesc->id_entryno++; 619 return (KEEPON); 620 } 621 dirp->d_ino = 0; 622 return (STOP|FOUND|ALTERED); 623 } 624 625 void 626 pinode(ino_t ino) 627 { 628 union dinode *dp; 629 char *p; 630 struct passwd *pw; 631 time_t t; 632 633 printf(" I=%u ", ino); 634 if (ino < ROOTINO || ino > maxino) 635 return; 636 dp = ginode(ino); 637 printf(" OWNER="); 638 #ifndef SMALL 639 if ((pw = getpwuid((int)iswap32(DIP(dp, uid)))) != 0) 640 printf("%s ", pw->pw_name); 641 else 642 #endif 643 printf("%u ", (unsigned)iswap32(DIP(dp, uid))); 644 printf("MODE=%o\n", iswap16(DIP(dp, mode))); 645 if (preen) 646 printf("%s: ", cdevname()); 647 printf("SIZE=%llu ", (unsigned long long)iswap64(DIP(dp, size))); 648 t = iswap32(DIP(dp, mtime)); 649 p = ctime(&t); 650 printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]); 651 } 652 653 void 654 blkerror(ino_t ino, char *type, daddr_t blk) 655 { 656 struct inostat *info; 657 658 pfatal("%lld %s I=%u", (long long)blk, type, ino); 659 printf("\n"); 660 info = inoinfo(ino); 661 switch (info->ino_state) { 662 663 case FSTATE: 664 info->ino_state = FCLEAR; 665 return; 666 667 case DSTATE: 668 info->ino_state = DCLEAR; 669 return; 670 671 case FCLEAR: 672 case DCLEAR: 673 return; 674 675 default: 676 errx(EEXIT, "BAD STATE %d TO BLKERR", info->ino_state); 677 /* NOTREACHED */ 678 } 679 } 680 681 /* 682 * allocate an unused inode 683 */ 684 ino_t 685 allocino(ino_t request, int type) 686 { 687 ino_t ino; 688 union dinode *dp; 689 struct ufs1_dinode *dp1; 690 struct ufs2_dinode *dp2; 691 time_t t; 692 struct cg *cgp = cgrp; 693 int cg; 694 struct inostat *info; 695 696 if (request == 0) 697 request = ROOTINO; 698 else if (inoinfo(request)->ino_state != USTATE) 699 return (0); 700 for (ino = request; ino < maxino; ino++) { 701 info = inoinfo(ino); 702 if (info->ino_state == USTATE) 703 break; 704 } 705 if (ino == maxino) 706 return (0); 707 cg = ino_to_cg(sblock, ino); 708 /* If necessary, extend the inoinfo array. grow exponentially */ 709 if ((ino % sblock->fs_ipg) >= inostathead[cg].il_numalloced) { 710 unsigned long newalloced, i; 711 newalloced = MIN(sblock->fs_ipg, 712 MAX(2 * inostathead[cg].il_numalloced, 10)); 713 info = calloc(newalloced, sizeof(struct inostat)); 714 if (info == NULL) { 715 pwarn("cannot alloc %lu bytes to extend inoinfo\n", 716 sizeof(struct inostat) * newalloced); 717 return 0; 718 } 719 memmove(info, inostathead[cg].il_stat, 720 inostathead[cg].il_numalloced * sizeof(*info)); 721 for (i = inostathead[cg].il_numalloced; i < newalloced; i++) { 722 info[i].ino_state = USTATE; 723 } 724 if (inostathead[cg].il_numalloced) 725 free(inostathead[cg].il_stat); 726 inostathead[cg].il_stat = info; 727 inostathead[cg].il_numalloced = newalloced; 728 info = inoinfo(ino); 729 } 730 getblk(&cgblk, cgtod(sblock, cg), sblock->fs_cgsize); 731 memcpy(cgp, cgblk.b_un.b_cg, sblock->fs_cgsize); 732 if ((doswap && !needswap) || (!doswap && needswap)) 733 ffs_cg_swap(cgblk.b_un.b_cg, cgp, sblock); 734 if (!cg_chkmagic(cgp, 0)) 735 pfatal("CG %d: ALLOCINO: BAD MAGIC NUMBER\n", cg); 736 if (doswap) 737 cgdirty(); 738 setbit(cg_inosused(cgp, 0), ino % sblock->fs_ipg); 739 cgp->cg_cs.cs_nifree--; 740 switch (type & IFMT) { 741 case IFDIR: 742 info->ino_state = DSTATE; 743 cgp->cg_cs.cs_ndir++; 744 break; 745 case IFREG: 746 case IFLNK: 747 info->ino_state = FSTATE; 748 break; 749 default: 750 return (0); 751 } 752 cgdirty(); 753 dp = ginode(ino); 754 if (is_ufs2) { 755 dp2 = &dp->dp2; 756 dp2->di_db[0] = iswap64(allocblk(1)); 757 if (dp2->di_db[0] == 0) { 758 info->ino_state = USTATE; 759 return (0); 760 } 761 dp2->di_mode = iswap16(type); 762 dp2->di_flags = 0; 763 (void)time(&t); 764 dp2->di_atime = iswap64(t); 765 dp2->di_mtime = dp2->di_ctime = dp2->di_atime; 766 dp2->di_size = iswap64(sblock->fs_fsize); 767 dp2->di_blocks = iswap64(btodb(sblock->fs_fsize)); 768 } else { 769 dp1 = &dp->dp1; 770 dp1->di_db[0] = iswap32(allocblk(1)); 771 if (dp1->di_db[0] == 0) { 772 info->ino_state = USTATE; 773 return (0); 774 } 775 dp1->di_mode = iswap16(type); 776 dp1->di_flags = 0; 777 (void)time(&t); 778 dp1->di_atime = iswap32(t); 779 dp1->di_mtime = dp1->di_ctime = dp1->di_atime; 780 dp1->di_size = iswap64(sblock->fs_fsize); 781 dp1->di_blocks = iswap32(btodb(sblock->fs_fsize)); 782 } 783 n_files++; 784 inodirty(); 785 if (newinofmt) 786 info->ino_type = IFTODT(type); 787 return (ino); 788 } 789 790 /* 791 * deallocate an inode 792 */ 793 void 794 freeino(ino_t ino) 795 { 796 struct inodesc idesc; 797 union dinode *dp; 798 799 memset(&idesc, 0, sizeof(struct inodesc)); 800 idesc.id_type = ADDR; 801 idesc.id_func = pass4check; 802 idesc.id_number = ino; 803 dp = ginode(ino); 804 (void)ckinode(dp, &idesc); 805 clearinode(dp); 806 inodirty(); 807 inoinfo(ino)->ino_state = USTATE; 808 n_files--; 809 } 810