1/* $NetBSD: inode.c,v 1.64 2011/03/06 17:08:16 bouyer 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 35static char sccsid[] = "@(#)inode.c 8.8 (Berkeley) 4/28/95"; 36#else 37__RCSID("$NetBSD: inode.c,v 1.64 2011/03/06 17:08:16 bouyer Exp $"); 38#endif 39#endif /* not lint */ 40 41#include <sys/param.h> 42#include <sys/time.h> 43#include <sys/stat.h> 44 45#include <ufs/ufs/dinode.h> 46#include <ufs/ufs/dir.h> 47#include <ufs/ffs/fs.h> 48#include <ufs/ffs/ffs_extern.h> 49#include <ufs/ufs/ufs_bswap.h> 50 51#ifndef SMALL 52#include <err.h> 53#include <pwd.h> 54#endif 55#include <stdio.h> 56#include <stdlib.h> 57#include <string.h> 58#include <time.h> 59 60#include "fsck.h" 61#include "fsutil.h" 62#include "extern.h" 63 64static ino_t startinum; 65 66static int iblock(struct inodesc *, long, u_int64_t); 67static void swap_dinode1(union dinode *, int); 68static void swap_dinode2(union dinode *, int); 69 70int 71ckinode(union dinode *dp, struct inodesc *idesc) 72{ 73 int ret, offset, i; 74 union dinode dino; 75 u_int64_t sizepb; 76 int64_t remsize; 77 daddr_t ndb; 78 mode_t mode; 79 char pathbuf[MAXPATHLEN + 1]; 80 81 if (idesc->id_fix != IGNORE) 82 idesc->id_fix = DONTKNOW; 83 idesc->id_entryno = 0; 84 idesc->id_filesize = iswap64(DIP(dp, size)); 85 mode = iswap16(DIP(dp, mode)) & IFMT; 86 if (mode == IFBLK || mode == IFCHR || (mode == IFLNK && 87 (idesc->id_filesize < sblock->fs_maxsymlinklen || 88 (isappleufs && (idesc->id_filesize < APPLEUFS_MAXSYMLINKLEN)) || 89 (sblock->fs_maxsymlinklen == 0 && DIP(dp, blocks) == 0)))) 90 return (KEEPON); 91 if (is_ufs2) 92 dino.dp2 = dp->dp2; 93 else 94 dino.dp1 = dp->dp1; 95 ndb = howmany(iswap64(DIP(&dino, size)), sblock->fs_bsize); 96 for (i = 0; i < NDADDR; i++) { 97 if (--ndb == 0 && 98 (offset = blkoff(sblock, iswap64(DIP(&dino, size)))) != 0) 99 idesc->id_numfrags = 100 numfrags(sblock, fragroundup(sblock, offset)); 101 else 102 idesc->id_numfrags = sblock->fs_frag; 103 if (DIP(&dino, db[i]) == 0) { 104 if (idesc->id_type == DATA && ndb >= 0) { 105 /* An empty block in a directory XXX */ 106 markclean = 0; 107 getpathname(pathbuf, sizeof(pathbuf), 108 idesc->id_number, idesc->id_number); 109 pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", 110 pathbuf); 111 if (reply("ADJUST LENGTH") == 1) { 112 dp = ginode(idesc->id_number); 113 DIP_SET(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_SET(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 174static int 175iblock(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) > (size_t)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=%llu", 219 (unsigned long long)idesc->id_number); 220 if (dofix(idesc, buf)) { 221 IBLK_SET(bp, i, 0); 222 dirty(bp); 223 } else 224 markclean = 0; 225 } 226 flush(fswritefd, bp); 227 } 228 for (i = 0; i < nif; i++) { 229 if (IBLK(bp, i)) { 230 if (is_ufs2) 231 idesc->id_blkno = iswap64(bp->b_un.b_indir2[i]); 232 else 233 idesc->id_blkno = iswap32(bp->b_un.b_indir1[i]); 234 if (ilevel == 0) 235 n = (*func)(idesc); 236 else 237 n = iblock(idesc, ilevel, isize); 238 if (n & STOP) { 239 bp->b_flags &= ~B_INUSE; 240 return (n); 241 } 242 } else { 243 if (idesc->id_type == DATA && isize > 0) { 244 /* An empty block in a directory XXX */ 245 markclean = 0; 246 getpathname(pathbuf, sizeof(pathbuf), 247 idesc->id_number, idesc->id_number); 248 pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", 249 pathbuf); 250 if (reply("ADJUST LENGTH") == 1) { 251 dp = ginode(idesc->id_number); 252 DIP_SET(dp, size, 253 iswap64(iswap64(DIP(dp, size)) 254 - isize)); 255 isize = 0; 256 printf( 257 "YOU MUST RERUN FSCK AFTERWARDS\n"); 258 rerun = 1; 259 inodirty(); 260 bp->b_flags &= ~B_INUSE; 261 return(STOP); 262 } 263 } 264 } 265 isize -= sizepb; 266 } 267 bp->b_flags &= ~B_INUSE; 268 return (KEEPON); 269} 270 271/* 272 * Check that a block in a legal block number. 273 * Return 0 if in range, 1 if out of range. 274 */ 275int 276chkrange(daddr_t blk, int cnt) 277{ 278 int c; 279 280 if (cnt <= 0 || blk <= 0 || blk > maxfsblock || 281 cnt - 1 > maxfsblock - blk) 282 return (1); 283 if (cnt > sblock->fs_frag || 284 fragnum(sblock, blk) + cnt > sblock->fs_frag) { 285 if (debug) 286 printf("bad size: blk %lld, offset %d, size %d\n", 287 (long long)blk, (int)fragnum(sblock, blk), cnt); 288 } 289 c = dtog(sblock, blk); 290 if (blk < cgdmin(sblock, c)) { 291 if ((blk + cnt) > cgsblock(sblock, c)) { 292 if (debug) { 293 printf("blk %lld < cgdmin %lld;", 294 (long long)blk, 295 (long long)cgdmin(sblock, c)); 296 printf(" blk + cnt %lld > cgsbase %lld\n", 297 (long long)(blk + cnt), 298 (long long)cgsblock(sblock, c)); 299 } 300 return (1); 301 } 302 } else { 303 if ((blk + cnt) > cgbase(sblock, c+1)) { 304 if (debug) { 305 printf("blk %lld >= cgdmin %lld;", 306 (long long)blk, 307 (long long)cgdmin(sblock, c)); 308 printf(" blk + cnt %lld > sblock->fs_fpg %d\n", 309 (long long)(blk+cnt), sblock->fs_fpg); 310 } 311 return (1); 312 } 313 } 314 return (0); 315} 316 317/* 318 * General purpose interface for reading inodes. 319 */ 320union dinode * 321ginode(ino_t inumber) 322{ 323 daddr_t iblk; 324 int blkoff; 325 326 if (inumber < ROOTINO || inumber > maxino) 327 errexit("bad inode number %llu to ginode", 328 (unsigned long long)inumber); 329 if (startinum == 0 || 330 inumber < startinum || inumber >= startinum + INOPB(sblock)) { 331 iblk = ino_to_fsba(sblock, inumber); 332 if (pbp != 0) 333 pbp->b_flags &= ~B_INUSE; 334 pbp = getdatablk(iblk, sblock->fs_bsize); 335 startinum = (inumber / INOPB(sblock)) * INOPB(sblock); 336 } 337 if (is_ufs2) { 338 blkoff = (inumber % INOPB(sblock)) * DINODE2_SIZE; 339 return ((union dinode *)((caddr_t)pbp->b_un.b_buf + blkoff)); 340 } 341 blkoff = (inumber % INOPB(sblock)) * DINODE1_SIZE; 342 return ((union dinode *)((caddr_t)pbp->b_un.b_buf + blkoff)); 343} 344 345static void 346swap_dinode1(union dinode *dp, int n) 347{ 348 int i, j; 349 struct ufs1_dinode *dp1; 350 int32_t maxsymlinklen = sblock->fs_maxsymlinklen; 351 if (isappleufs) 352 maxsymlinklen = APPLEUFS_MAXSYMLINKLEN; 353 354 dp1 = (struct ufs1_dinode *)&dp->dp1; 355 for (i = 0; i < n; i++, dp1++) { 356 ffs_dinode1_swap(dp1, dp1); 357 if (((iswap16(dp1->di_mode) & IFMT) != IFLNK) || 358 doinglevel2 || 359 (maxsymlinklen < 0) || 360 (iswap64(dp1->di_size) > (uint64_t)maxsymlinklen)) { 361 for (j = 0; j < (NDADDR + NIADDR); j++) 362 dp1->di_db[j] = bswap32(dp1->di_db[j]); 363 } 364 } 365} 366 367static void 368swap_dinode2(union dinode *dp, int n) 369{ 370 int i, j; 371 struct ufs2_dinode *dp2; 372 373 dp2 = (struct ufs2_dinode *)&dp->dp2; 374 for (i = 0; i < n; i++, dp2++) { 375 ffs_dinode2_swap(dp2, dp2); 376 if ((iswap16(dp2->di_mode) & IFMT) != IFLNK) { 377 for (j = 0; j < (NDADDR + NIADDR + NXADDR); j++) 378 dp2->di_extb[j] = bswap64(dp2->di_extb[j]); 379 } 380 } 381} 382 383/* 384 * Special purpose version of ginode used to optimize first pass 385 * over all the inodes in numerical order. 386 */ 387ino_t nextino, lastinum, lastvalidinum; 388long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize; 389union dinode *inodebuf; 390 391union dinode * 392getnextinode(ino_t inumber) 393{ 394 long size; 395 daddr_t dblk; 396 static union dinode *dp; 397 union dinode *ret; 398 399 if (inumber != nextino++ || inumber > lastvalidinum) 400 errexit("bad inode number %llu to nextinode", 401 (unsigned long long)inumber); 402 403 if (inumber >= lastinum) { 404 readcnt++; 405 dblk = fsbtodb(sblock, ino_to_fsba(sblock, lastinum)); 406 if (readcnt % readpercg == 0) { 407 size = partialsize; 408 lastinum += partialcnt; 409 } else { 410 size = inobufsize; 411 lastinum += fullcnt; 412 } 413 (void)bread(fsreadfd, (caddr_t)inodebuf, dblk, size); 414 if (doswap) { 415 if (is_ufs2) 416 swap_dinode2(inodebuf, lastinum - inumber); 417 else 418 swap_dinode1(inodebuf, lastinum - inumber); 419 bwrite(fswritefd, (char *)inodebuf, dblk, size); 420 } 421 dp = (union dinode *)inodebuf; 422 } 423 ret = dp; 424 dp = (union dinode *) 425 ((char *)dp + (is_ufs2 ? DINODE2_SIZE : DINODE1_SIZE)); 426 return ret; 427} 428 429void 430setinodebuf(ino_t inum) 431{ 432 433 if (inum % sblock->fs_ipg != 0) 434 errexit("bad inode number %llu to setinodebuf", 435 (unsigned long long)inum); 436 437 lastvalidinum = inum + sblock->fs_ipg - 1; 438 startinum = 0; 439 nextino = inum; 440 lastinum = inum; 441 readcnt = 0; 442 if (inodebuf != NULL) 443 return; 444 inobufsize = blkroundup(sblock, INOBUFSIZE); 445 fullcnt = inobufsize / (is_ufs2 ? DINODE2_SIZE : DINODE1_SIZE); 446 readpercg = sblock->fs_ipg / fullcnt; 447 partialcnt = sblock->fs_ipg % fullcnt; 448 partialsize = partialcnt * (is_ufs2 ? DINODE2_SIZE : DINODE1_SIZE); 449 if (partialcnt != 0) { 450 readpercg++; 451 } else { 452 partialcnt = fullcnt; 453 partialsize = inobufsize; 454 } 455 if (inodebuf == NULL && 456 (inodebuf = malloc((unsigned)inobufsize)) == NULL) 457 errexit("Cannot allocate space for inode buffer"); 458} 459 460void 461freeinodebuf(void) 462{ 463 464 if (inodebuf != NULL) 465 free((char *)inodebuf); 466 inodebuf = NULL; 467} 468 469/* 470 * Routines to maintain information about directory inodes. 471 * This is built during the first pass and used during the 472 * second and third passes. 473 * 474 * Enter inodes into the cache. 475 */ 476void 477cacheino(union dinode *dp, ino_t inumber) 478{ 479 struct inoinfo *inp; 480 struct inoinfo **inpp, **ninpsort; 481 unsigned int i, blks, extra; 482 int64_t size; 483 484 size = iswap64(DIP(dp, size)); 485 blks = howmany(size, sblock->fs_bsize); 486 if (blks > NDADDR) 487 blks = NDADDR + NIADDR; 488 if (blks > 0) 489 extra = (blks - 1) * sizeof (int64_t); 490 else 491 extra = 0; 492 inp = malloc(sizeof(*inp) + extra); 493 if (inp == NULL) 494 return; 495 inpp = &inphead[inumber % dirhash]; 496 inp->i_nexthash = *inpp; 497 *inpp = inp; 498 inp->i_child = inp->i_sibling = 0; 499 if (inumber == ROOTINO) 500 inp->i_parent = ROOTINO; 501 else 502 inp->i_parent = (ino_t)0; 503 inp->i_dotdot = (ino_t)0; 504 inp->i_number = inumber; 505 inp->i_isize = size; 506 inp->i_numblks = blks; 507 for (i = 0; i < (blks < NDADDR ? blks : NDADDR); i++) 508 inp->i_blks[i] = DIP(dp, db[i]); 509 if (blks > NDADDR) 510 for (i = 0; i < NIADDR; i++) 511 inp->i_blks[NDADDR + i] = DIP(dp, ib[i]); 512 if (inplast == listmax) { 513 ninpsort = (struct inoinfo **)realloc((char *)inpsort, 514 (unsigned)(listmax + 100) * sizeof(struct inoinfo *)); 515 if (inpsort == NULL) 516 errexit("cannot increase directory list"); 517 inpsort = ninpsort; 518 listmax += 100; 519 } 520 inpsort[inplast++] = inp; 521} 522 523/* 524 * Look up an inode cache structure. 525 */ 526struct inoinfo * 527getinoinfo(ino_t inumber) 528{ 529 struct inoinfo *inp; 530 531 for (inp = inphead[inumber % dirhash]; inp; inp = inp->i_nexthash) { 532 if (inp->i_number != inumber) 533 continue; 534 return (inp); 535 } 536 errexit("cannot find inode %llu", (unsigned long long)inumber); 537 return ((struct inoinfo *)0); 538} 539 540/* 541 * Clean up all the inode cache structure. 542 */ 543void 544inocleanup(void) 545{ 546 struct inoinfo **inpp; 547 548 if (inphead == NULL) 549 return; 550 for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--) 551 free((char *)(*inpp)); 552 free((char *)inphead); 553 free((char *)inpsort); 554 inphead = inpsort = NULL; 555} 556 557void 558inodirty(void) 559{ 560 561 dirty(pbp); 562} 563 564void 565clri(struct inodesc *idesc, const char *type, int flag) 566{ 567 union dinode *dp; 568 569 dp = ginode(idesc->id_number); 570 if (flag == 1) { 571 pwarn("%s %s", type, 572 (iswap16(DIP(dp, mode)) & IFMT) == IFDIR ? "DIR" : "FILE"); 573 pinode(idesc->id_number); 574 } 575 if (preen || reply("CLEAR") == 1) { 576 if (preen) 577 printf(" (CLEARED)\n"); 578 n_files--; 579 /* 580 * ckinode will call id_func (actually always pass4check) 581 * which will update the block count 582 */ 583 if (idesc->id_type != SNAP) 584 update_uquot(idesc->id_number, 585 idesc->id_uid, idesc->id_gid, 0, -1); 586 (void)ckinode(dp, idesc); 587 clearinode(dp); 588 inoinfo(idesc->id_number)->ino_state = USTATE; 589 inodirty(); 590 } else 591 markclean = 0; 592} 593 594int 595findname(struct inodesc *idesc) 596{ 597 struct direct *dirp = idesc->id_dirp; 598 size_t len; 599 char *buf; 600 601 if (iswap32(dirp->d_ino) != idesc->id_parent || idesc->id_entryno < 2) { 602 idesc->id_entryno++; 603 return (KEEPON); 604 } 605 if ((len = dirp->d_namlen + 1) > MAXPATHLEN) { 606 /* XXX: We don't fix but we ignore */ 607 len = MAXPATHLEN; 608 } 609 /* this is namebuf from utilities.c */ 610 buf = __UNCONST(idesc->id_name); 611 (void)memcpy(buf, dirp->d_name, (size_t)dirp->d_namlen + 1); 612 return (STOP|FOUND); 613} 614 615int 616findino(struct inodesc *idesc) 617{ 618 struct direct *dirp = idesc->id_dirp; 619 620 if (dirp->d_ino == 0) 621 return (KEEPON); 622 if (strcmp(dirp->d_name, idesc->id_name) == 0 && 623 iswap32(dirp->d_ino) >= ROOTINO && iswap32(dirp->d_ino) <= maxino) { 624 idesc->id_parent = iswap32(dirp->d_ino); 625 return (STOP|FOUND); 626 } 627 return (KEEPON); 628} 629 630int 631clearentry(struct inodesc *idesc) 632{ 633 struct direct *dirp = idesc->id_dirp; 634 635 if (dirp->d_ino != idesc->id_parent || idesc->id_entryno < 2) { 636 idesc->id_entryno++; 637 return (KEEPON); 638 } 639 dirp->d_ino = 0; 640 return (STOP|FOUND|ALTERED); 641} 642 643void 644pinode(ino_t ino) 645{ 646 union dinode *dp; 647 struct passwd *pw; 648 649 printf(" I=%llu ", (unsigned long long)ino); 650 if (ino < ROOTINO || ino > maxino) 651 return; 652 dp = ginode(ino); 653 printf(" OWNER="); 654#ifndef SMALL 655 if (Uflag && (pw = getpwuid((int)iswap32(DIP(dp, uid)))) != 0) 656 printf("%s ", pw->pw_name); 657 else 658#endif 659 printf("%u ", (unsigned)iswap32(DIP(dp, uid))); 660 printf("MODE=%o\n", iswap16(DIP(dp, mode))); 661 if (preen) 662 printf("%s: ", cdevname()); 663 printf("SIZE=%llu ", (unsigned long long)iswap64(DIP(dp, size))); 664 printf("MTIME=%s ", print_mtime(iswap32(DIP(dp, mtime)))); 665} 666 667void 668blkerror(ino_t ino, const char *type, daddr_t blk) 669{ 670 struct inostat *info; 671 672 pfatal("%lld %s I=%llu", (long long)blk, type, (unsigned long long)ino); 673 printf("\n"); 674 info = inoinfo(ino); 675 switch (info->ino_state) { 676 677 case FSTATE: 678 info->ino_state = FCLEAR; 679 return; 680 681 case DSTATE: 682 info->ino_state = DCLEAR; 683 return; 684 685 case FCLEAR: 686 case DCLEAR: 687 return; 688 689 default: 690 errexit("BAD STATE %d TO BLKERR", info->ino_state); 691 /* NOTREACHED */ 692 } 693} 694 695/* 696 * allocate an unused inode 697 */ 698ino_t 699allocino(ino_t request, int type) 700{ 701 ino_t ino; 702 union dinode *dp; 703 struct ufs1_dinode *dp1; 704 struct ufs2_dinode *dp2; 705 time_t t; 706 struct cg *cgp = cgrp; 707 int cg; 708 struct inostat *info = NULL; 709 int nfrags; 710 711 if (request == 0) 712 request = ROOTINO; 713 else if (inoinfo(request)->ino_state != USTATE) 714 return (0); 715 for (ino = request; ino < maxino; ino++) { 716 info = inoinfo(ino); 717 if (info->ino_state == USTATE) 718 break; 719 } 720 if (ino == maxino) 721 return (0); 722 cg = ino_to_cg(sblock, ino); 723 /* If necessary, extend the inoinfo array. grow exponentially */ 724 if ((ino % sblock->fs_ipg) >= (uint64_t)inostathead[cg].il_numalloced) { 725 unsigned long newalloced, i; 726 newalloced = MIN(sblock->fs_ipg, 727 MAX(2 * inostathead[cg].il_numalloced, 10)); 728 info = calloc(newalloced, sizeof(struct inostat)); 729 if (info == NULL) { 730 pwarn("cannot alloc %lu bytes to extend inoinfo\n", 731 sizeof(struct inostat) * newalloced); 732 return 0; 733 } 734 memmove(info, inostathead[cg].il_stat, 735 inostathead[cg].il_numalloced * sizeof(*info)); 736 for (i = inostathead[cg].il_numalloced; i < newalloced; i++) { 737 info[i].ino_state = USTATE; 738 } 739 if (inostathead[cg].il_numalloced) 740 free(inostathead[cg].il_stat); 741 inostathead[cg].il_stat = info; 742 inostathead[cg].il_numalloced = newalloced; 743 info = inoinfo(ino); 744 } 745 getblk(&cgblk, cgtod(sblock, cg), sblock->fs_cgsize); 746 memcpy(cgp, cgblk.b_un.b_cg, sblock->fs_cgsize); 747 if ((doswap && !needswap) || (!doswap && needswap)) 748 ffs_cg_swap(cgblk.b_un.b_cg, cgp, sblock); 749 if (!cg_chkmagic(cgp, 0)) 750 pfatal("CG %d: ALLOCINO: BAD MAGIC NUMBER\n", cg); 751 if (doswap) 752 cgdirty(); 753 setbit(cg_inosused(cgp, 0), ino % sblock->fs_ipg); 754 cgp->cg_cs.cs_nifree--; 755 sblock->fs_cstotal.cs_nifree--; 756 sblock->fs_cs(fs, cg).cs_nifree--; 757 sbdirty(); 758 switch (type & IFMT) { 759 case IFDIR: 760 info->ino_state = DSTATE; 761 cgp->cg_cs.cs_ndir++; 762 nfrags = 1; 763 break; 764 case IFREG: 765 info->ino_state = FSTATE; 766 nfrags = sblock->fs_frag; 767 break; 768 case IFLNK: 769 info->ino_state = FSTATE; 770 nfrags = 1; 771 break; 772 default: 773 return (0); 774 } 775 cgdirty(); 776 dp = ginode(ino); 777 if (is_ufs2) { 778 dp2 = &dp->dp2; 779 dp2->di_db[0] = iswap64(allocblk(nfrags)); 780 if (dp2->di_db[0] == 0) { 781 info->ino_state = USTATE; 782 return (0); 783 } 784 dp2->di_mode = iswap16(type); 785 dp2->di_flags = 0; 786 (void)time(&t); 787 dp2->di_atime = iswap64(t); 788 dp2->di_mtime = dp2->di_ctime = dp2->di_atime; 789 dp2->di_size = iswap64(lfragtosize(sblock, nfrags)); 790 dp2->di_blocks = iswap64(btodb(lfragtosize(sblock, nfrags))); 791 } else { 792 dp1 = &dp->dp1; 793 dp1->di_db[0] = iswap32(allocblk(nfrags)); 794 if (dp1->di_db[0] == 0) { 795 info->ino_state = USTATE; 796 return (0); 797 } 798 dp1->di_mode = iswap16(type); 799 dp1->di_flags = 0; 800 (void)time(&t); 801 dp1->di_atime = iswap32(t); 802 dp1->di_mtime = dp1->di_ctime = dp1->di_atime; 803 dp1->di_size = iswap64(lfragtosize(sblock, nfrags)); 804 dp1->di_blocks = iswap32(btodb(lfragtosize(sblock, nfrags))); 805 } 806 n_files++; 807 inodirty(); 808 if (newinofmt) 809 info->ino_type = IFTODT(type); 810 return (ino); 811} 812 813/* 814 * deallocate an inode 815 */ 816void 817freeino(ino_t ino) 818{ 819 struct inodesc idesc; 820 union dinode *dp; 821 struct cg *cgp = cgrp; 822 int cg; 823 824 cg = ino_to_cg(sblock, ino); 825 getblk(&cgblk, cgtod(sblock, cg), sblock->fs_cgsize); 826 memcpy(cgp, cgblk.b_un.b_cg, sblock->fs_cgsize); 827 if ((doswap && !needswap) || (!doswap && needswap)) 828 ffs_cg_swap(cgblk.b_un.b_cg, cgp, sblock); 829 if (!cg_chkmagic(cgp, 0)) { 830 pwarn("CG %d: FREEINO: BAD MAGIC NUMBER\n", cg); 831 cgp = NULL; 832 } 833 834 memset(&idesc, 0, sizeof(struct inodesc)); 835 idesc.id_func = pass4check; 836 idesc.id_number = ino; 837 dp = ginode(ino); 838 idesc.id_uid = iswap32(DIP(dp, uid)); 839 idesc.id_gid = iswap32(DIP(dp, gid)); 840 if (iswap32(DIP(dp, flags)) & SF_SNAPSHOT) 841 idesc.id_type = SNAP; 842 else 843 idesc.id_type = ADDR; 844 (void)ckinode(dp, &idesc); 845 clearinode(dp); 846 inodirty(); 847 inoinfo(ino)->ino_state = USTATE; 848 if (idesc.id_type != SNAP) 849 update_uquot(idesc.id_number, 850 idesc.id_uid, idesc.id_gid, 0, -1); 851 n_files--; 852 if (cgp) { 853 clrbit(cg_inosused(cgp, 0), ino % sblock->fs_ipg); 854 cgp->cg_cs.cs_nifree++; 855 sblock->fs_cstotal.cs_nifree++; 856 sblock->fs_cs(fs, cg).cs_nifree++; 857 sbdirty(); 858 cgdirty(); 859 } 860} 861 862/* read a data block from inode */ 863ssize_t 864readblk(union dinode *dp, off_t offset, struct bufarea **bp) 865{ 866 daddr_t blkno = lblkno(sblock, offset); 867 daddr_t iblkno; 868 int type = IFMT & iswap16(DIP(dp, mode)); 869 ssize_t filesize = iswap64(DIP(dp, size)); 870 int ilevel; 871 daddr_t nblks; 872 const daddr_t naddrperblk = sblock->fs_bsize / 873 (is_ufs2 ? sizeof(uint64_t) : sizeof(uint32_t)); 874 struct bufarea *ibp; 875 876 *bp = NULL; 877 offset &= ~(sblock->fs_bsize - 1); 878 879 if (type != IFREG) 880 return 0; 881 if (offset >= filesize) 882 return 0; /* short read */ 883 if (blkno < NDADDR) { 884 blkno = is_ufs2 ? iswap64(dp->dp2.di_db[blkno]) : 885 iswap32(dp->dp1.di_db[blkno]); 886 if (blkno == 0) 887 return 0; 888 *bp = getdatablk(blkno, sblock->fs_bsize); 889 return (bp != NULL) ? sblock->fs_bsize : 0; 890 } 891 blkno -= NDADDR; 892 /* find indir level */ 893 for (ilevel = 1, nblks = naddrperblk; 894 ilevel <= NIADDR; 895 ilevel++, nblks *= naddrperblk) { 896 if (blkno < nblks) 897 break; 898 else 899 blkno -= nblks; 900 } 901 if (ilevel > NIADDR) 902 errexit("bad ofsset %" PRIu64 " to readblk", offset); 903 904 /* get the first indirect block */ 905 iblkno = is_ufs2 ? iswap64(dp->dp2.di_ib[ilevel - 1]) : 906 iswap32(dp->dp1.di_ib[ilevel - 1]); 907 if (iblkno == 0) 908 return 0; 909 ibp = getdatablk(iblkno, sblock->fs_bsize); 910 /* walk indirect blocks up to the data block */ 911 for (; ilevel >0 ; ilevel--) { 912 nblks = nblks / naddrperblk; 913 if (is_ufs2) 914 iblkno = iswap64(ibp->b_un.b_indir2[blkno / nblks]); 915 else 916 iblkno = iswap32(ibp->b_un.b_indir1[blkno / nblks]); 917 if (iblkno == 0) 918 return 0; 919 blkno = blkno % nblks; 920 ibp->b_flags &= ~B_INUSE; 921 ibp = getdatablk(iblkno, sblock->fs_bsize); 922 } 923 *bp = ibp; 924 return sblock->fs_bsize; 925} 926 927static struct bufarea * getnewblk(daddr_t *); 928static struct bufarea * 929getnewblk(daddr_t *blkno) 930{ 931 struct bufarea *bp; 932 *blkno = allocblk(sblock->fs_frag); 933 if (*blkno == 0) 934 return NULL; 935 bp = getdatablk(*blkno, sblock->fs_bsize); 936 memset(bp->b_un.b_buf, 0, sblock->fs_bsize); 937 return bp; 938} 939 940/* expand given inode by one full fs block */ 941struct bufarea * 942expandfile(union dinode *dp) 943{ 944 uint64_t filesize = iswap64(DIP(dp, size)); 945 daddr_t newblk, blkno, iblkno, nblks; 946 daddr_t di_blocks; 947 int ilevel; 948 const daddr_t naddrperblk = sblock->fs_bsize / 949 (is_ufs2 ? sizeof(uint64_t) : sizeof(uint32_t)); 950 struct bufarea *ibp, *bp = NULL; 951 952 di_blocks = is_ufs2 ? iswap64(dp->dp2.di_blocks) : 953 iswap32(dp->dp1.di_blocks); 954 /* compute location of new block */ 955 blkno = lblkno(sblock, filesize); 956 957 if (blkno < NDADDR) { 958 /* easy way: allocate a direct block */ 959 if ((bp = getnewblk(&newblk)) == NULL) { 960 return NULL; 961 } 962 di_blocks += btodb(sblock->fs_bsize); 963 964 if (is_ufs2) { 965 dp->dp2.di_db[blkno] = iswap64(newblk); 966 } else { 967 dp->dp1.di_db[blkno] = iswap32(newblk); 968 } 969 goto out; 970 } 971 blkno -= NDADDR; 972 /* find indir level */ 973 for (ilevel = 1, nblks = naddrperblk; 974 ilevel <= NIADDR; 975 ilevel++, nblks *= naddrperblk) { 976 if (blkno < nblks) 977 break; 978 else 979 blkno -= nblks; 980 } 981 if (ilevel > NIADDR) 982 errexit("bad filesize %" PRIu64 " to expandfile", filesize); 983 984 /* get the first indirect block, allocating if needed */ 985 if ((is_ufs2 ? iswap64(dp->dp2.di_ib[ilevel - 1]) : 986 iswap32(dp->dp1.di_ib[ilevel - 1])) == 0) { 987 if ((ibp = getnewblk(&newblk)) == NULL) 988 return 0; 989 di_blocks += btodb(sblock->fs_bsize); 990 if (is_ufs2) 991 dp->dp2.di_ib[ilevel - 1] = iswap64(newblk); 992 else 993 dp->dp1.di_ib[ilevel - 1] = iswap32(newblk); 994 } else { 995 ibp = getdatablk(is_ufs2 ? iswap64(dp->dp2.di_ib[ilevel - 1]) : 996 iswap32(dp->dp1.di_ib[ilevel - 1]), sblock->fs_bsize); 997 } 998 /* walk indirect blocks up to the data block */ 999 for (; ilevel >0 ; ilevel--) { 1000 nblks = nblks / naddrperblk; 1001 if (is_ufs2) 1002 iblkno = iswap64(ibp->b_un.b_indir2[blkno / nblks]); 1003 else 1004 iblkno = iswap32(ibp->b_un.b_indir1[blkno / nblks]); 1005 if (iblkno == 0) { 1006 if ((bp = getnewblk(&newblk)) == NULL) 1007 return NULL; 1008 di_blocks += btodb(sblock->fs_bsize); 1009 if (is_ufs2) 1010 ibp->b_un.b_indir2[blkno / nblks] = 1011 iswap64(newblk); 1012 else 1013 ibp->b_un.b_indir1[blkno / nblks] = 1014 iswap32(newblk); 1015 dirty(ibp); 1016 ibp->b_flags &= ~B_INUSE; 1017 ibp = bp; 1018 } else { 1019 ibp->b_flags &= ~B_INUSE; 1020 ibp = getdatablk(iblkno, sblock->fs_bsize); 1021 bp = NULL; 1022 } 1023 blkno = blkno % nblks; 1024 } 1025 if (bp == NULL) { 1026 errexit("INTERNAL ERROR: " 1027 "expandfile() failed to allocate a new block\n"); 1028 } 1029 1030out: 1031 filesize += sblock->fs_bsize; 1032 if (is_ufs2) { 1033 dp->dp2.di_size = iswap64(filesize); 1034 dp->dp2.di_blocks = iswap64(di_blocks); 1035 } else { 1036 dp->dp1.di_size = iswap64(filesize); 1037 dp->dp1.di_blocks = iswap32(di_blocks); 1038 } 1039 inodirty(); 1040 return bp; 1041} 1042