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