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