1 /* $NetBSD: utilities.c,v 1.54 2007/02/08 21:36:58 drochner 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.54 2007/02/08 21:36:58 drochner 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 #include <signal.h> 58 59 #include "fsutil.h" 60 #include "fsck.h" 61 #include "extern.h" 62 63 long diskreads, totalreads; /* Disk cache statistics */ 64 65 static void rwerror(const char *, daddr_t); 66 67 extern int returntosingle; 68 69 int 70 ftypeok(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 90 int 91 reply(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 */ 130 void 131 bufinit(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 errx(EEXIT, "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 errx(EEXIT, "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 errx(EEXIT, "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 */ 178 struct bufarea * 179 getdatablk(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 errx(EEXIT, "deadlocked buffer pool"); 191 /* fall through */ 192 foundit: 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 204 void 205 getblk(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 220 void 221 flush(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 251 static void 252 rwerror(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(EEXIT); 260 } 261 262 void 263 ckfini(void) 264 { 265 struct bufarea *bp, *nbp; 266 int ofsmodified, cnt = 0; 267 268 if (fswritefd < 0) { 269 (void)close(fsreadfd); 270 return; 271 } 272 flush(fswritefd, &sblk); 273 if (havesb && bflag != 0 && 274 (preen || reply("UPDATE STANDARD SUPERBLOCK"))) { 275 if (preen) 276 pwarn("UPDATING STANDARD SUPERBLOCK\n"); 277 if (!is_ufs2 && (sblock->fs_old_flags & FS_FLAGS_UPDATED) == 0) 278 sblk.b_bno = SBLOCK_UFS1 / dev_bsize; 279 else 280 sblk.b_bno = sblock->fs_sblockloc / dev_bsize; 281 sbdirty(); 282 flush(fswritefd, &sblk); 283 } 284 flush(fswritefd, &appleufsblk); 285 free(appleufsblk.b_un.b_buf); 286 flush(fswritefd, &cgblk); 287 free(cgblk.b_un.b_buf); 288 for (bp = bufhead.b_prev; bp && bp != &bufhead; bp = nbp) { 289 cnt++; 290 flush(fswritefd, bp); 291 nbp = bp->b_prev; 292 free(bp->b_un.b_buf); 293 free((char *)bp); 294 } 295 if (bufhead.b_size != cnt) 296 errx(EEXIT, "Panic: lost %d buffers", bufhead.b_size - cnt); 297 pbp = pdirbp = (struct bufarea *)0; 298 if (markclean && (sblock->fs_clean & FS_ISCLEAN) == 0) { 299 /* 300 * Mark the file system as clean, and sync the superblock. 301 */ 302 if (preen) 303 pwarn("MARKING FILE SYSTEM CLEAN\n"); 304 else if (!reply("MARK FILE SYSTEM CLEAN")) 305 markclean = 0; 306 if (markclean) { 307 sblock->fs_clean = FS_ISCLEAN; 308 sblock->fs_pendingblocks = 0; 309 sblock->fs_pendinginodes = 0; 310 sbdirty(); 311 ofsmodified = fsmodified; 312 flush(fswritefd, &sblk); 313 #if LITE2BORKEN 314 fsmodified = ofsmodified; 315 #endif 316 if (!preen) 317 printf( 318 "\n***** FILE SYSTEM MARKED CLEAN *****\n"); 319 } 320 } 321 if (debug) 322 printf("cache missed %ld of %ld (%d%%)\n", diskreads, 323 totalreads, (int)(diskreads * 100 / totalreads)); 324 (void)close(fsreadfd); 325 (void)close(fswritefd); 326 } 327 328 int 329 bread(int fd, char *buf, daddr_t blk, long size) 330 { 331 char *cp; 332 int i, errs; 333 off_t offset; 334 335 offset = blk; 336 offset *= dev_bsize; 337 if (pread(fd, buf, (int)size, offset) == size) 338 return (0); 339 rwerror("READ", blk); 340 errs = 0; 341 memset(buf, 0, (size_t)size); 342 printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:"); 343 for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) { 344 if (pread(fd, cp, (int)secsize, offset + i) != secsize) { 345 if (secsize != dev_bsize && dev_bsize != 1) 346 printf(" %lld (%lld),", 347 (long long)((blk*dev_bsize + i) / secsize), 348 (long long)(blk + i / dev_bsize)); 349 else 350 printf(" %lld,", 351 (long long)(blk + i / dev_bsize)); 352 errs++; 353 } 354 } 355 printf("\n"); 356 return (errs); 357 } 358 359 void 360 bwrite(int fd, char *buf, daddr_t blk, long size) 361 { 362 int i; 363 char *cp; 364 off_t offset; 365 366 if (fd < 0) 367 return; 368 offset = blk; 369 offset *= dev_bsize; 370 if (pwrite(fd, buf, (int)size, offset) == size) { 371 fsmodified = 1; 372 return; 373 } 374 rwerror("WRITE", blk); 375 printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:"); 376 for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize) 377 if (pwrite(fd, cp, (int)dev_bsize, offset + i) != dev_bsize) 378 printf(" %lld,", (long long)(blk + i / dev_bsize)); 379 printf("\n"); 380 return; 381 } 382 383 /* 384 * allocate a data block with the specified number of fragments 385 */ 386 daddr_t 387 allocblk(long frags) 388 { 389 int i, j, k, cg, baseblk; 390 struct cg *cgp = cgrp; 391 392 if (frags <= 0 || frags > sblock->fs_frag) 393 return (0); 394 for (i = 0; i < maxfsblock - sblock->fs_frag; i += sblock->fs_frag) { 395 for (j = 0; j <= sblock->fs_frag - frags; j++) { 396 if (testbmap(i + j)) 397 continue; 398 for (k = 1; k < frags; k++) 399 if (testbmap(i + j + k)) 400 break; 401 if (k < frags) { 402 j += k; 403 continue; 404 } 405 cg = dtog(sblock, i + j); 406 getblk(&cgblk, cgtod(sblock, cg), sblock->fs_cgsize); 407 memcpy(cgp, cgblk.b_un.b_cg, sblock->fs_cgsize); 408 if ((doswap && !needswap) || (!doswap && needswap)) 409 ffs_cg_swap(cgblk.b_un.b_cg, cgp, sblock); 410 if (!cg_chkmagic(cgp, 0)) 411 pfatal("CG %d: ALLOCBLK: BAD MAGIC NUMBER\n", 412 cg); 413 baseblk = dtogd(sblock, i + j); 414 for (k = 0; k < frags; k++) { 415 setbmap(i + j + k); 416 clrbit(cg_blksfree(cgp, 0), baseblk + k); 417 } 418 n_blks += frags; 419 if (frags == sblock->fs_frag) 420 cgp->cg_cs.cs_nbfree--; 421 else 422 cgp->cg_cs.cs_nffree -= frags; 423 cgdirty(); 424 return (i + j); 425 } 426 } 427 return (0); 428 } 429 430 /* 431 * Free a previously allocated block 432 */ 433 void 434 freeblk(daddr_t blkno, long frags) 435 { 436 struct inodesc idesc; 437 438 idesc.id_blkno = blkno; 439 idesc.id_numfrags = frags; 440 (void)pass4check(&idesc); 441 } 442 443 /* 444 * Find a pathname 445 */ 446 void 447 getpathname(char *namebuf, size_t namebuflen, ino_t curdir, ino_t ino) 448 { 449 int len; 450 char *cp; 451 struct inodesc idesc; 452 static int busy = 0; 453 struct inostat *info; 454 455 if (curdir == ino && ino == ROOTINO) { 456 (void)strlcpy(namebuf, "/", namebuflen); 457 return; 458 } 459 info = inoinfo(curdir); 460 if (busy || (info->ino_state != DSTATE && info->ino_state != DFOUND)) { 461 (void)strlcpy(namebuf, "?", namebuflen); 462 return; 463 } 464 busy = 1; 465 memset(&idesc, 0, sizeof(struct inodesc)); 466 idesc.id_type = DATA; 467 idesc.id_fix = IGNORE; 468 cp = &namebuf[MAXPATHLEN - 1]; 469 *cp = '\0'; 470 if (curdir != ino) { 471 idesc.id_parent = curdir; 472 goto namelookup; 473 } 474 while (ino != ROOTINO) { 475 idesc.id_number = ino; 476 idesc.id_func = findino; 477 idesc.id_name = ".."; 478 if ((ckinode(ginode(ino), &idesc) & FOUND) == 0) 479 break; 480 namelookup: 481 idesc.id_number = idesc.id_parent; 482 idesc.id_parent = ino; 483 idesc.id_func = findname; 484 idesc.id_name = namebuf; 485 if ((ckinode(ginode(idesc.id_number), &idesc)&FOUND) == 0) 486 break; 487 len = strlen(namebuf); 488 cp -= len; 489 memmove(cp, namebuf, (size_t)len); 490 *--cp = '/'; 491 if (cp < &namebuf[FFS_MAXNAMLEN]) 492 break; 493 ino = idesc.id_number; 494 } 495 busy = 0; 496 if (ino != ROOTINO) 497 *--cp = '?'; 498 memmove(namebuf, cp, (size_t)(&namebuf[MAXPATHLEN] - cp)); 499 } 500 501 void 502 catch(int sig) 503 { 504 if (!doinglevel2) { 505 markclean = 0; 506 ckfini(); 507 } 508 exit(12); 509 } 510 511 /* 512 * When preening, allow a single quit to signal 513 * a special exit after filesystem checks complete 514 * so that reboot sequence may be interrupted. 515 */ 516 void 517 catchquit(int sig) 518 { 519 int errsave = errno; 520 521 printf("returning to single-user after file system check\n"); 522 returntosingle = 1; 523 (void)signal(SIGQUIT, SIG_DFL); 524 errno = errsave; 525 } 526 527 /* 528 * Ignore a single quit signal; wait and flush just in case. 529 * Used by child processes in preen. 530 */ 531 void 532 voidquit(int sig) 533 { 534 int errsave = errno; 535 536 sleep(1); 537 (void)signal(SIGQUIT, SIG_IGN); 538 (void)signal(SIGQUIT, SIG_DFL); 539 errno = errsave; 540 } 541 542 /* 543 * determine whether an inode should be fixed. 544 */ 545 int 546 dofix(struct inodesc *idesc, const char *msg) 547 { 548 549 switch (idesc->id_fix) { 550 551 case DONTKNOW: 552 if (idesc->id_type == DATA) 553 direrror(idesc->id_number, msg); 554 else 555 pwarn("%s", msg); 556 if (preen) { 557 printf(" (SALVAGED)\n"); 558 idesc->id_fix = FIX; 559 return (ALTERED); 560 } 561 if (reply("SALVAGE") == 0) { 562 idesc->id_fix = NOFIX; 563 return (0); 564 } 565 idesc->id_fix = FIX; 566 return (ALTERED); 567 568 case FIX: 569 return (ALTERED); 570 571 case NOFIX: 572 case IGNORE: 573 return (0); 574 575 default: 576 errx(EEXIT, "UNKNOWN INODESC FIX MODE %d", idesc->id_fix); 577 } 578 /* NOTREACHED */ 579 return (0); 580 } 581 582 void 583 copyback_cg(struct bufarea *blk) 584 { 585 586 memcpy(blk->b_un.b_cg, cgrp, sblock->fs_cgsize); 587 if (needswap) 588 ffs_cg_swap(cgrp, blk->b_un.b_cg, sblock); 589 } 590 591 void 592 infohandler(int sig) 593 { 594 got_siginfo = 1; 595 } 596 597 /* 598 * Look up state information for an inode. 599 */ 600 struct inostat * 601 inoinfo(ino_t inum) 602 { 603 static struct inostat unallocated = { USTATE, 0, 0 }; 604 struct inostatlist *ilp; 605 int iloff; 606 607 if (inum > maxino) 608 errx(EEXIT, "inoinfo: inumber %llu out of range", 609 (unsigned long long)inum); 610 ilp = &inostathead[inum / sblock->fs_ipg]; 611 iloff = inum % sblock->fs_ipg; 612 if (iloff >= ilp->il_numalloced) 613 return (&unallocated); 614 return (&ilp->il_stat[iloff]); 615 } 616 617 void 618 sb_oldfscompat_read(struct fs *fs, struct fs **fssave) 619 { 620 if ((fs->fs_magic != FS_UFS1_MAGIC) || 621 (fs->fs_old_flags & FS_FLAGS_UPDATED)) 622 return; 623 624 /* Save a copy of fields that may be modified for compatibility */ 625 if (fssave) { 626 if (!*fssave) 627 *fssave = malloc(sizeof(struct fs)); 628 if (!*fssave) 629 errx(EEXIT, "cannot allocate space for compat store"); 630 memmove(*fssave, fs, sizeof(struct fs)); 631 632 if (debug) 633 printf("detected ufs1 superblock not yet updated for ufs2 kernels\n"); 634 635 if (doswap) { 636 uint16_t postbl[256]; 637 int i, n; 638 639 if (fs->fs_old_postblformat == FS_42POSTBLFMT) 640 n = 256; 641 else 642 n = 128; 643 644 /* extract the postbl from the unswapped superblock */ 645 if (!needswap) 646 ffs_sb_swap(*fssave, *fssave); 647 memmove(postbl, (&(*fssave)->fs_old_postbl_start), 648 n * sizeof(postbl[0])); 649 if (!needswap) 650 ffs_sb_swap(*fssave, *fssave); 651 652 /* Now swap it */ 653 for (i=0; i < n; i++) 654 postbl[i] = bswap16(postbl[i]); 655 656 /* And put it back such that it will get correctly 657 * unscrambled if it is swapped again on the way out 658 */ 659 if (needswap) 660 ffs_sb_swap(*fssave, *fssave); 661 memmove((&(*fssave)->fs_old_postbl_start), postbl, 662 n * sizeof(postbl[0])); 663 if (needswap) 664 ffs_sb_swap(*fssave, *fssave); 665 } 666 667 } 668 669 /* These fields will be overwritten by their 670 * original values in fs_oldfscompat_write, so it is harmless 671 * to modify them here. 672 */ 673 fs->fs_cstotal.cs_ndir = 674 fs->fs_old_cstotal.cs_ndir; 675 fs->fs_cstotal.cs_nbfree = 676 fs->fs_old_cstotal.cs_nbfree; 677 fs->fs_cstotal.cs_nifree = 678 fs->fs_old_cstotal.cs_nifree; 679 fs->fs_cstotal.cs_nffree = 680 fs->fs_old_cstotal.cs_nffree; 681 682 fs->fs_maxbsize = fs->fs_bsize; 683 fs->fs_time = fs->fs_old_time; 684 fs->fs_size = fs->fs_old_size; 685 fs->fs_dsize = fs->fs_old_dsize; 686 fs->fs_csaddr = fs->fs_old_csaddr; 687 fs->fs_sblockloc = SBLOCK_UFS1; 688 689 fs->fs_flags = fs->fs_old_flags; 690 691 if (fs->fs_old_postblformat == FS_42POSTBLFMT) { 692 fs->fs_old_nrpos = 8; 693 fs->fs_old_npsect = fs->fs_old_nsect; 694 fs->fs_old_interleave = 1; 695 fs->fs_old_trackskew = 0; 696 } 697 } 698 699 void 700 sb_oldfscompat_write(struct fs *fs, struct fs *fssave) 701 { 702 if ((fs->fs_magic != FS_UFS1_MAGIC) || 703 (fs->fs_old_flags & FS_FLAGS_UPDATED)) 704 return; 705 706 fs->fs_old_flags = fs->fs_flags; 707 fs->fs_old_time = fs->fs_time; 708 fs->fs_old_cstotal.cs_ndir = fs->fs_cstotal.cs_ndir; 709 fs->fs_old_cstotal.cs_nbfree = fs->fs_cstotal.cs_nbfree; 710 fs->fs_old_cstotal.cs_nifree = fs->fs_cstotal.cs_nifree; 711 fs->fs_old_cstotal.cs_nffree = fs->fs_cstotal.cs_nffree; 712 713 fs->fs_flags = fssave->fs_flags; 714 715 if (fs->fs_old_postblformat == FS_42POSTBLFMT) { 716 fs->fs_old_nrpos = fssave->fs_old_nrpos; 717 fs->fs_old_npsect = fssave->fs_old_npsect; 718 fs->fs_old_interleave = fssave->fs_old_interleave; 719 fs->fs_old_trackskew = fssave->fs_old_trackskew; 720 } 721 722 memmove(&fs->fs_old_postbl_start, &fssave->fs_old_postbl_start, 723 ((fs->fs_old_postblformat == FS_42POSTBLFMT) ? 724 512 : 256)); 725 } 726