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