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