1 /* $NetBSD: utilities.c,v 1.59 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 35 static char sccsid[] = "@(#)utilities.c 8.6 (Berkeley) 5/19/95"; 36 #else 37 __RCSID("$NetBSD: utilities.c,v 1.59 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 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 #include <ufs/ufs/quota2.h> 50 51 #include <ctype.h> 52 #include <err.h> 53 #include <errno.h> 54 #include <stdio.h> 55 #include <stdlib.h> 56 #include <string.h> 57 #include <unistd.h> 58 #include <signal.h> 59 60 #include "fsutil.h" 61 #include "fsck.h" 62 #include "extern.h" 63 #include "exitvalues.h" 64 65 long diskreads, totalreads; /* Disk cache statistics */ 66 67 static void rwerror(const char *, daddr_t); 68 69 extern volatile sig_atomic_t returntosingle; 70 71 int 72 ftypeok(union dinode *dp) 73 { 74 switch (iswap16(DIP(dp, mode)) & IFMT) { 75 76 case IFDIR: 77 case IFREG: 78 case IFBLK: 79 case IFCHR: 80 case IFLNK: 81 case IFSOCK: 82 case IFIFO: 83 return (1); 84 85 default: 86 if (debug) 87 printf("bad file type 0%o\n", iswap16(DIP(dp, mode))); 88 return (0); 89 } 90 } 91 92 int 93 reply(const char *question) 94 { 95 int persevere; 96 char c; 97 98 if (preen) 99 pfatal("INTERNAL ERROR: GOT TO reply()"); 100 persevere = !strcmp(question, "CONTINUE"); 101 printf("\n"); 102 if (!persevere && (nflag || fswritefd < 0)) { 103 printf("%s? no\n\n", question); 104 resolved = 0; 105 return (0); 106 } 107 if (yflag || (persevere && nflag)) { 108 printf("%s? yes\n\n", question); 109 return (1); 110 } 111 do { 112 printf("%s? [yn] ", question); 113 (void) fflush(stdout); 114 c = getc(stdin); 115 while (c != '\n' && getc(stdin) != '\n') { 116 if (feof(stdin)) { 117 resolved = 0; 118 return (0); 119 } 120 } 121 } while (c != 'y' && c != 'Y' && c != 'n' && c != 'N'); 122 printf("\n"); 123 if (c == 'y' || c == 'Y') 124 return (1); 125 resolved = 0; 126 return (0); 127 } 128 129 /* 130 * Malloc buffers and set up cache. 131 */ 132 void 133 bufinit(void) 134 { 135 struct bufarea *bp; 136 long bufcnt, i; 137 char *bufp; 138 139 pbp = pdirbp = (struct bufarea *)0; 140 bufp = malloc((unsigned int)sblock->fs_bsize); 141 if (bufp == 0) 142 errexit("cannot allocate buffer pool"); 143 cgblk.b_un.b_buf = bufp; 144 initbarea(&cgblk); 145 bufp = malloc((unsigned int)APPLEUFS_LABEL_SIZE); 146 if (bufp == 0) 147 errexit("cannot allocate buffer pool"); 148 appleufsblk.b_un.b_buf = bufp; 149 initbarea(&appleufsblk); 150 bufhead.b_next = bufhead.b_prev = &bufhead; 151 bufcnt = MAXBUFSPACE / sblock->fs_bsize; 152 if (bufcnt < MINBUFS) 153 bufcnt = MINBUFS; 154 for (i = 0; i < bufcnt; i++) { 155 bp = malloc(sizeof(struct bufarea)); 156 bufp = malloc((unsigned int)sblock->fs_bsize); 157 if (bp == NULL || bufp == NULL) { 158 if (i >= MINBUFS) { 159 if (bp) 160 free(bp); 161 if (bufp) 162 free(bufp); 163 break; 164 } 165 errexit("cannot allocate buffer pool"); 166 } 167 bp->b_un.b_buf = bufp; 168 bp->b_prev = &bufhead; 169 bp->b_next = bufhead.b_next; 170 bufhead.b_next->b_prev = bp; 171 bufhead.b_next = bp; 172 initbarea(bp); 173 } 174 bufhead.b_size = i; /* save number of buffers */ 175 } 176 177 /* 178 * Manage a cache of directory blocks. 179 */ 180 struct bufarea * 181 getdatablk(daddr_t blkno, long size) 182 { 183 struct bufarea *bp; 184 185 for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next) 186 if (bp->b_bno == fsbtodb(sblock, blkno)) 187 goto foundit; 188 for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev) 189 if ((bp->b_flags & B_INUSE) == 0) 190 break; 191 if (bp == &bufhead) 192 errexit("deadlocked buffer pool"); 193 /* fall through */ 194 foundit: 195 getblk(bp, blkno, size); 196 bp->b_prev->b_next = bp->b_next; 197 bp->b_next->b_prev = bp->b_prev; 198 bp->b_prev = &bufhead; 199 bp->b_next = bufhead.b_next; 200 bufhead.b_next->b_prev = bp; 201 bufhead.b_next = bp; 202 bp->b_flags |= B_INUSE; 203 return (bp); 204 } 205 206 void 207 getblk(struct bufarea *bp, daddr_t blk, long size) 208 { 209 daddr_t dblk; 210 211 dblk = fsbtodb(sblock, blk); 212 totalreads++; 213 if (bp->b_bno != dblk) { 214 flush(fswritefd, bp); 215 diskreads++; 216 bp->b_errs = bread(fsreadfd, bp->b_un.b_buf, dblk, size); 217 bp->b_bno = dblk; 218 bp->b_size = size; 219 } 220 } 221 222 void 223 flush(int fd, struct bufarea *bp) 224 { 225 int i, j; 226 struct csum *ccsp; 227 228 if (!bp->b_dirty) 229 return; 230 if (bp->b_errs != 0) 231 pfatal("WRITING %sZERO'ED BLOCK %lld TO DISK\n", 232 (bp->b_errs == bp->b_size / dev_bsize) ? "" : "PARTIALLY ", 233 (long long)bp->b_bno); 234 bp->b_dirty = 0; 235 bp->b_errs = 0; 236 bwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size); 237 if (bp != &sblk) 238 return; 239 for (i = 0, j = 0; i < sblock->fs_cssize; i += sblock->fs_bsize, j++) { 240 int size = sblock->fs_cssize - i < sblock->fs_bsize ? 241 sblock->fs_cssize - i : sblock->fs_bsize; 242 ccsp = (struct csum *)((char *)sblock->fs_csp + i); 243 if (needswap) 244 ffs_csum_swap(ccsp, ccsp, size); 245 bwrite(fswritefd, (char *)ccsp, 246 fsbtodb(sblock, sblock->fs_csaddr + j * sblock->fs_frag), 247 size); 248 if (needswap) 249 ffs_csum_swap(ccsp, ccsp, size); 250 } 251 } 252 253 static void 254 rwerror(const char *mesg, daddr_t blk) 255 { 256 257 if (preen == 0) 258 printf("\n"); 259 pfatal("CANNOT %s: BLK %lld", mesg, (long long)blk); 260 if (reply("CONTINUE") == 0) 261 exit(FSCK_EXIT_CHECK_FAILED); 262 } 263 264 void 265 ckfini(void) 266 { 267 struct bufarea *bp, *nbp; 268 int ofsmodified, cnt = 0; 269 270 if (fswritefd < 0) { 271 (void)close(fsreadfd); 272 return; 273 } 274 flush(fswritefd, &sblk); 275 if (havesb && bflag != 0 && 276 (preen || reply("UPDATE STANDARD SUPERBLOCK"))) { 277 if (preen) 278 pwarn("UPDATING STANDARD SUPERBLOCK\n"); 279 if (!is_ufs2 && (sblock->fs_old_flags & FS_FLAGS_UPDATED) == 0) 280 sblk.b_bno = SBLOCK_UFS1 / dev_bsize; 281 else 282 sblk.b_bno = sblock->fs_sblockloc / dev_bsize; 283 sbdirty(); 284 flush(fswritefd, &sblk); 285 } 286 flush(fswritefd, &appleufsblk); 287 free(appleufsblk.b_un.b_buf); 288 flush(fswritefd, &cgblk); 289 free(cgblk.b_un.b_buf); 290 for (bp = bufhead.b_prev; bp && bp != &bufhead; bp = nbp) { 291 cnt++; 292 flush(fswritefd, bp); 293 nbp = bp->b_prev; 294 free(bp->b_un.b_buf); 295 free((char *)bp); 296 } 297 if (bufhead.b_size != cnt) 298 errexit("Panic: lost %d buffers", bufhead.b_size - cnt); 299 pbp = pdirbp = (struct bufarea *)0; 300 if (markclean && (sblock->fs_clean & FS_ISCLEAN) == 0) { 301 /* 302 * Mark the file system as clean, and sync the superblock. 303 */ 304 if (preen) 305 pwarn("MARKING FILE SYSTEM CLEAN\n"); 306 else if (!reply("MARK FILE SYSTEM CLEAN")) 307 markclean = 0; 308 if (markclean) { 309 sblock->fs_clean = FS_ISCLEAN; 310 sblock->fs_pendingblocks = 0; 311 sblock->fs_pendinginodes = 0; 312 sbdirty(); 313 ofsmodified = fsmodified; 314 flush(fswritefd, &sblk); 315 #if LITE2BORKEN 316 fsmodified = ofsmodified; 317 #endif 318 if (!preen) 319 printf( 320 "\n***** FILE SYSTEM MARKED CLEAN *****\n"); 321 } 322 } 323 if (debug) 324 printf("cache missed %ld of %ld (%d%%)\n", diskreads, 325 totalreads, (int)(diskreads * 100 / totalreads)); 326 cleanup_wapbl(); 327 (void)close(fsreadfd); 328 (void)close(fswritefd); 329 } 330 331 int 332 bread(int fd, char *buf, daddr_t blk, long size) 333 { 334 char *cp; 335 int i, errs; 336 off_t offset; 337 338 offset = blk; 339 offset *= dev_bsize; 340 if ((pread(fd, buf, (int)size, offset) == size) && 341 read_wapbl(buf, size, blk) == 0) 342 return (0); 343 rwerror("READ", blk); 344 errs = 0; 345 memset(buf, 0, (size_t)size); 346 printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:"); 347 for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) { 348 if (pread(fd, cp, (int)secsize, offset + i) != secsize) { 349 if (secsize != dev_bsize && dev_bsize != 1) 350 printf(" %lld (%lld),", 351 (long long)((blk*dev_bsize + i) / secsize), 352 (long long)(blk + i / dev_bsize)); 353 else 354 printf(" %lld,", 355 (long long)(blk + i / dev_bsize)); 356 errs++; 357 } 358 } 359 printf("\n"); 360 return (errs); 361 } 362 363 void 364 bwrite(int fd, char *buf, daddr_t blk, long size) 365 { 366 int i; 367 char *cp; 368 off_t offset; 369 370 if (fd < 0) 371 return; 372 offset = blk; 373 offset *= dev_bsize; 374 if (pwrite(fd, buf, (int)size, offset) == size) { 375 fsmodified = 1; 376 return; 377 } 378 rwerror("WRITE", blk); 379 printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:"); 380 for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize) 381 if (pwrite(fd, cp, (int)dev_bsize, offset + i) != dev_bsize) 382 printf(" %lld,", (long long)(blk + i / dev_bsize)); 383 printf("\n"); 384 return; 385 } 386 387 /* 388 * allocate a data block with the specified number of fragments 389 */ 390 daddr_t 391 allocblk(long frags) 392 { 393 int i, j, k, cg, baseblk; 394 struct cg *cgp = cgrp; 395 396 if (frags <= 0 || frags > sblock->fs_frag) 397 return (0); 398 for (i = 0; i < maxfsblock - sblock->fs_frag; i += sblock->fs_frag) { 399 for (j = 0; j <= sblock->fs_frag - frags; j++) { 400 if (testbmap(i + j)) 401 continue; 402 for (k = 1; k < frags; k++) 403 if (testbmap(i + j + k)) 404 break; 405 if (k < frags) { 406 j += k; 407 continue; 408 } 409 cg = dtog(sblock, i + j); 410 getblk(&cgblk, cgtod(sblock, cg), sblock->fs_cgsize); 411 memcpy(cgp, cgblk.b_un.b_cg, sblock->fs_cgsize); 412 if ((doswap && !needswap) || (!doswap && needswap)) 413 ffs_cg_swap(cgblk.b_un.b_cg, cgp, sblock); 414 if (!cg_chkmagic(cgp, 0)) 415 pfatal("CG %d: ALLOCBLK: BAD MAGIC NUMBER\n", 416 cg); 417 baseblk = dtogd(sblock, i + j); 418 for (k = 0; k < frags; k++) { 419 setbmap(i + j + k); 420 clrbit(cg_blksfree(cgp, 0), baseblk + k); 421 } 422 n_blks += frags; 423 if (frags == sblock->fs_frag) { 424 cgp->cg_cs.cs_nbfree--; 425 sblock->fs_cstotal.cs_nbfree--; 426 sblock->fs_cs(fs, cg).cs_nbfree--; 427 ffs_clusteracct(sblock, cgp, 428 fragstoblks(sblock, baseblk), -1); 429 } else { 430 cgp->cg_cs.cs_nffree -= frags; 431 sblock->fs_cstotal.cs_nffree -= frags; 432 sblock->fs_cs(fs, cg).cs_nffree -= frags; 433 } 434 sbdirty(); 435 cgdirty(); 436 return (i + j); 437 } 438 } 439 return (0); 440 } 441 442 /* 443 * Free a previously allocated block 444 */ 445 void 446 freeblk(daddr_t blkno, long frags) 447 { 448 struct inodesc idesc; 449 450 memset(&idesc, 0, sizeof(idesc)); 451 idesc.id_blkno = blkno; 452 idesc.id_numfrags = frags; 453 (void)pass4check(&idesc); 454 } 455 456 /* 457 * Find a pathname 458 */ 459 void 460 getpathname(char *namebuf, size_t namebuflen, ino_t curdir, ino_t ino) 461 { 462 int len; 463 char *cp; 464 struct inodesc idesc; 465 static int busy = 0; 466 struct inostat *info; 467 468 if (curdir == ino && ino == ROOTINO) { 469 (void)strlcpy(namebuf, "/", namebuflen); 470 return; 471 } 472 info = inoinfo(curdir); 473 if (busy || (info->ino_state != DSTATE && info->ino_state != DFOUND)) { 474 (void)strlcpy(namebuf, "?", namebuflen); 475 return; 476 } 477 busy = 1; 478 memset(&idesc, 0, sizeof(struct inodesc)); 479 idesc.id_type = DATA; 480 idesc.id_fix = IGNORE; 481 cp = &namebuf[MAXPATHLEN - 1]; 482 *cp = '\0'; 483 if (curdir != ino) { 484 idesc.id_parent = curdir; 485 goto namelookup; 486 } 487 while (ino != ROOTINO) { 488 idesc.id_number = ino; 489 idesc.id_func = findino; 490 idesc.id_name = ".."; 491 if ((ckinode(ginode(ino), &idesc) & FOUND) == 0) 492 break; 493 namelookup: 494 idesc.id_number = idesc.id_parent; 495 idesc.id_parent = ino; 496 idesc.id_func = findname; 497 idesc.id_name = namebuf; 498 if ((ckinode(ginode(idesc.id_number), &idesc)&FOUND) == 0) 499 break; 500 len = strlen(namebuf); 501 cp -= len; 502 memmove(cp, namebuf, (size_t)len); 503 *--cp = '/'; 504 if (cp < &namebuf[FFS_MAXNAMLEN]) 505 break; 506 ino = idesc.id_number; 507 } 508 busy = 0; 509 if (ino != ROOTINO) 510 *--cp = '?'; 511 memmove(namebuf, cp, (size_t)(&namebuf[MAXPATHLEN] - cp)); 512 } 513 514 void 515 catch(int sig) 516 { 517 if (!doinglevel2) { 518 markclean = 0; 519 ckfini(); 520 } 521 _exit(FSCK_EXIT_SIGNALLED); 522 } 523 524 /* 525 * When preening, allow a single quit to signal 526 * a special exit after filesystem checks complete 527 * so that reboot sequence may be interrupted. 528 */ 529 void 530 catchquit(int sig) 531 { 532 static const char msg[] = 533 "returning to single-user after file system check\n"; 534 int serrno = errno; 535 536 (void)write(STDOUT_FILENO, msg, sizeof(msg) - 1); 537 returntosingle = 1; 538 (void)signal(SIGQUIT, SIG_DFL); 539 errno = serrno; 540 } 541 542 /* 543 * Ignore a single quit signal; wait and flush just in case. 544 * Used by child processes in preen. 545 */ 546 void 547 voidquit(int sig) 548 { 549 int serrno = errno; 550 551 sleep(1); 552 (void)signal(SIGQUIT, SIG_IGN); 553 (void)signal(SIGQUIT, SIG_DFL); 554 errno = serrno; 555 } 556 557 /* 558 * determine whether an inode should be fixed. 559 */ 560 int 561 dofix(struct inodesc *idesc, const char *msg) 562 { 563 564 switch (idesc->id_fix) { 565 566 case DONTKNOW: 567 if (idesc->id_type == DATA) 568 direrror(idesc->id_number, msg); 569 else 570 pwarn("%s", msg); 571 if (preen) { 572 printf(" (SALVAGED)\n"); 573 idesc->id_fix = FIX; 574 return (ALTERED); 575 } 576 if (reply("SALVAGE") == 0) { 577 idesc->id_fix = NOFIX; 578 return (0); 579 } 580 idesc->id_fix = FIX; 581 return (ALTERED); 582 583 case FIX: 584 return (ALTERED); 585 586 case NOFIX: 587 case IGNORE: 588 return (0); 589 590 default: 591 errexit("UNKNOWN INODESC FIX MODE %d", idesc->id_fix); 592 } 593 /* NOTREACHED */ 594 return (0); 595 } 596 597 void 598 copyback_cg(struct bufarea *blk) 599 { 600 601 memcpy(blk->b_un.b_cg, cgrp, sblock->fs_cgsize); 602 if (needswap) 603 ffs_cg_swap(cgrp, blk->b_un.b_cg, sblock); 604 } 605 606 void 607 infohandler(int sig) 608 { 609 got_siginfo = 1; 610 } 611 612 /* 613 * Look up state information for an inode. 614 */ 615 struct inostat * 616 inoinfo(ino_t inum) 617 { 618 static struct inostat unallocated = { USTATE, 0, 0 }; 619 struct inostatlist *ilp; 620 int iloff; 621 622 if (inum > maxino) 623 errexit("inoinfo: inumber %llu out of range", 624 (unsigned long long)inum); 625 ilp = &inostathead[inum / sblock->fs_ipg]; 626 iloff = inum % sblock->fs_ipg; 627 if (iloff >= ilp->il_numalloced) 628 return (&unallocated); 629 return (&ilp->il_stat[iloff]); 630 } 631 632 void 633 sb_oldfscompat_read(struct fs *fs, struct fs **fssave) 634 { 635 if ((fs->fs_magic != FS_UFS1_MAGIC) || 636 (fs->fs_old_flags & FS_FLAGS_UPDATED)) 637 return; 638 639 /* Save a copy of fields that may be modified for compatibility */ 640 if (fssave) { 641 if (!*fssave) 642 *fssave = malloc(sizeof(struct fs)); 643 if (!*fssave) 644 errexit("cannot allocate space for compat store"); 645 memmove(*fssave, fs, sizeof(struct fs)); 646 647 if (debug) 648 printf("detected ufs1 superblock not yet updated for ufs2 kernels\n"); 649 650 if (doswap) { 651 uint16_t postbl[256]; 652 int i, n; 653 654 if (fs->fs_old_postblformat == FS_42POSTBLFMT) 655 n = 256; 656 else 657 n = 128; 658 659 /* extract the postbl from the unswapped superblock */ 660 if (!needswap) 661 ffs_sb_swap(*fssave, *fssave); 662 memmove(postbl, (&(*fssave)->fs_old_postbl_start), 663 n * sizeof(postbl[0])); 664 if (!needswap) 665 ffs_sb_swap(*fssave, *fssave); 666 667 /* Now swap it */ 668 for (i=0; i < n; i++) 669 postbl[i] = bswap16(postbl[i]); 670 671 /* And put it back such that it will get correctly 672 * unscrambled if it is swapped again on the way out 673 */ 674 if (needswap) 675 ffs_sb_swap(*fssave, *fssave); 676 memmove((&(*fssave)->fs_old_postbl_start), postbl, 677 n * sizeof(postbl[0])); 678 if (needswap) 679 ffs_sb_swap(*fssave, *fssave); 680 } 681 682 } 683 684 /* These fields will be overwritten by their 685 * original values in fs_oldfscompat_write, so it is harmless 686 * to modify them here. 687 */ 688 fs->fs_cstotal.cs_ndir = 689 fs->fs_old_cstotal.cs_ndir; 690 fs->fs_cstotal.cs_nbfree = 691 fs->fs_old_cstotal.cs_nbfree; 692 fs->fs_cstotal.cs_nifree = 693 fs->fs_old_cstotal.cs_nifree; 694 fs->fs_cstotal.cs_nffree = 695 fs->fs_old_cstotal.cs_nffree; 696 697 fs->fs_maxbsize = fs->fs_bsize; 698 fs->fs_time = fs->fs_old_time; 699 fs->fs_size = fs->fs_old_size; 700 fs->fs_dsize = fs->fs_old_dsize; 701 fs->fs_csaddr = fs->fs_old_csaddr; 702 fs->fs_sblockloc = SBLOCK_UFS1; 703 704 fs->fs_flags = fs->fs_old_flags; 705 706 if (fs->fs_old_postblformat == FS_42POSTBLFMT) { 707 fs->fs_old_nrpos = 8; 708 fs->fs_old_npsect = fs->fs_old_nsect; 709 fs->fs_old_interleave = 1; 710 fs->fs_old_trackskew = 0; 711 } 712 } 713 714 void 715 sb_oldfscompat_write(struct fs *fs, struct fs *fssave) 716 { 717 if ((fs->fs_magic != FS_UFS1_MAGIC) || 718 (fs->fs_old_flags & FS_FLAGS_UPDATED)) 719 return; 720 721 fs->fs_old_flags = fs->fs_flags; 722 fs->fs_old_time = fs->fs_time; 723 fs->fs_old_cstotal.cs_ndir = fs->fs_cstotal.cs_ndir; 724 fs->fs_old_cstotal.cs_nbfree = fs->fs_cstotal.cs_nbfree; 725 fs->fs_old_cstotal.cs_nifree = fs->fs_cstotal.cs_nifree; 726 fs->fs_old_cstotal.cs_nffree = fs->fs_cstotal.cs_nffree; 727 728 fs->fs_flags = fssave->fs_flags; 729 730 if (fs->fs_old_postblformat == FS_42POSTBLFMT) { 731 fs->fs_old_nrpos = fssave->fs_old_nrpos; 732 fs->fs_old_npsect = fssave->fs_old_npsect; 733 fs->fs_old_interleave = fssave->fs_old_interleave; 734 fs->fs_old_trackskew = fssave->fs_old_trackskew; 735 } 736 737 memmove(&fs->fs_old_postbl_start, &fssave->fs_old_postbl_start, 738 ((fs->fs_old_postblformat == FS_42POSTBLFMT) ? 739 512 : 256)); 740 } 741 742 struct uquot * 743 find_uquot(struct uquot_hash *uq_hash, uint32_t uid, int alloc) 744 { 745 struct uquot *uq; 746 SLIST_FOREACH(uq, &uq_hash[uid & q2h_hash_mask], uq_entries) { 747 if (uq->uq_uid == uid) 748 return uq; 749 } 750 if (!alloc) 751 return NULL; 752 uq = malloc(sizeof(struct uquot)); 753 if (uq == NULL) 754 errexit("cannot allocate quota entry"); 755 memset(uq, 0, sizeof(struct uquot)); 756 uq->uq_uid = uid; 757 SLIST_INSERT_HEAD(&uq_hash[uid & q2h_hash_mask], uq, uq_entries); 758 return uq; 759 } 760 761 void 762 remove_uquot(struct uquot_hash *uq_hash, struct uquot *uq) 763 { 764 SLIST_REMOVE(&uq_hash[uq->uq_uid & q2h_hash_mask], 765 uq, uquot, uq_entries); 766 } 767 768 void 769 update_uquot(ino_t inum, uid_t uid, gid_t gid, int64_t bchange, int64_t ichange) 770 { 771 /* simple uquot cache: remember the last used */ 772 static struct uquot *uq_u = NULL; 773 static struct uquot *uq_g = NULL; 774 775 if (inum < ROOTINO) 776 return; 777 if (is_journal_inode(inum)) 778 return; 779 if (is_quota_inode(inum)) 780 return; 781 782 if (uquot_user_hash == NULL) 783 return; 784 785 if (uq_u == NULL || uq_u->uq_uid != uid) 786 uq_u = find_uquot(uquot_user_hash, uid, 1); 787 uq_u->uq_b += bchange; 788 uq_u->uq_i += ichange; 789 if (uq_g == NULL || uq_g->uq_uid != gid) 790 uq_g = find_uquot(uquot_group_hash, gid, 1); 791 uq_g->uq_b += bchange; 792 uq_g->uq_i += ichange; 793 } 794 795 int 796 is_quota_inode(ino_t inum) 797 { 798 799 if ((sblock->fs_flags & FS_DOQUOTA2) == 0) 800 return 0; 801 802 if (sblock->fs_quota_magic != Q2_HEAD_MAGIC) 803 return 0; 804 805 if (sblock->fs_quotafile[USRQUOTA] == inum) 806 return 1; 807 808 if (sblock->fs_quotafile[GRPQUOTA] == inum) 809 return 1; 810 811 return 0; 812 } 813