1 /* $OpenBSD: ufs.c,v 1.27 2019/08/03 15:22:17 deraadt Exp $ */ 2 /* $NetBSD: ufs.c,v 1.16 1996/09/30 16:01:22 ws Exp $ */ 3 4 /*- 5 * Copyright (c) 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * The Mach Operating System project at Carnegie-Mellon University. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * 36 * Copyright (c) 1990, 1991 Carnegie Mellon University 37 * All Rights Reserved. 38 * 39 * Author: David Golub 40 * 41 * Permission to use, copy, modify and distribute this software and its 42 * documentation is hereby granted, provided that both the copyright 43 * notice and this permission notice appear in all copies of the 44 * software, derivative works or modified versions, and any portions 45 * thereof, and that both notices appear in supporting documentation. 46 * 47 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 48 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 49 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 50 * 51 * Carnegie Mellon requests users of this software to return to 52 * 53 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 54 * School of Computer Science 55 * Carnegie Mellon University 56 * Pittsburgh PA 15213-3890 57 * 58 * any improvements or extensions that they make and grant Carnegie the 59 * rights to redistribute these changes. 60 */ 61 62 /* 63 * Stand-alone file reading package. 64 */ 65 66 #include <sys/param.h> 67 #include <sys/time.h> 68 #include <sys/stat.h> 69 #include <ufs/ffs/fs.h> 70 #include <ufs/ufs/dinode.h> 71 #include <ufs/ufs/dir.h> 72 #include <lib/libkern/libkern.h> 73 74 #include "stand.h" 75 #include "ufs.h" 76 77 /* 78 * In-core open file. 79 */ 80 struct file { 81 off_t f_seekp; /* seek pointer */ 82 struct fs *f_fs; /* pointer to super-block */ 83 struct ufs1_dinode f_di; /* copy of on-disk inode */ 84 ufsino_t f_ino; /* our inode number */ 85 int f_nindir[NIADDR]; 86 /* number of blocks mapped by 87 indirect block at level i */ 88 char *f_blk[NIADDR]; /* buffer for indirect block at 89 level i */ 90 size_t f_blksize[NIADDR]; 91 /* size of buffer */ 92 daddr32_t f_blkno[NIADDR];/* disk address of block in buffer */ 93 char *f_buf; /* buffer for data block */ 94 size_t f_buf_size; /* size of data block */ 95 daddr32_t f_buf_blkno; /* block number of data block */ 96 }; 97 98 static int read_inode(ufsino_t, struct open_file *); 99 static int chmod_inode(ufsino_t, struct open_file *, mode_t); 100 static int block_map(struct open_file *, daddr32_t, daddr32_t *); 101 static int buf_read_file(struct open_file *, char **, size_t *); 102 static int search_directory(char *, struct open_file *, ufsino_t *); 103 static int ufs_close_internal(struct file *); 104 #ifdef COMPAT_UFS 105 static void ffs_oldfscompat(struct fs *); 106 #endif 107 108 /* 109 * Read a new inode into a file structure. 110 */ 111 static int 112 read_inode(ufsino_t inumber, struct open_file *f) 113 { 114 struct file *fp = (struct file *)f->f_fsdata; 115 struct fs *fs = fp->f_fs; 116 char *buf; 117 size_t rsize; 118 int rc; 119 120 /* 121 * Read inode and save it. 122 */ 123 buf = alloc(fs->fs_bsize); 124 twiddle(); 125 rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 126 fsbtodb(fs, (daddr32_t)ino_to_fsba(fs, inumber)), fs->fs_bsize, 127 buf, &rsize); 128 if (rc) 129 goto out; 130 if (rsize != (size_t)fs->fs_bsize) { 131 rc = EIO; 132 goto out; 133 } 134 135 { 136 struct ufs1_dinode *dp; 137 138 dp = (struct ufs1_dinode *)buf; 139 fp->f_di = dp[ino_to_fsbo(fs, inumber)]; 140 } 141 142 /* 143 * Clear out the old buffers 144 */ 145 { 146 int level; 147 148 for (level = 0; level < NIADDR; level++) 149 fp->f_blkno[level] = -1; 150 fp->f_buf_blkno = -1; 151 fp->f_seekp = 0; 152 } 153 out: 154 free(buf, fs->fs_bsize); 155 return (rc); 156 } 157 158 /* 159 * Read a new inode into a file structure. 160 */ 161 static int 162 chmod_inode(ufsino_t inumber, struct open_file *f, mode_t mode) 163 { 164 struct file *fp = (struct file *)f->f_fsdata; 165 struct fs *fs = fp->f_fs; 166 char *buf; 167 size_t rsize; 168 int rc; 169 170 /* 171 * Read inode and save it. 172 */ 173 buf = alloc(fs->fs_bsize); 174 twiddle(); 175 rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 176 fsbtodb(fs, (daddr32_t)ino_to_fsba(fs, inumber)), fs->fs_bsize, 177 buf, &rsize); 178 if (rc) 179 goto out; 180 if (rsize != (size_t)fs->fs_bsize) { 181 rc = EIO; 182 goto out; 183 } 184 185 { 186 struct ufs1_dinode *dp; 187 188 dp = &((struct ufs1_dinode *)buf)[ino_to_fsbo(fs, inumber)]; 189 dp->di_mode = mode; 190 } 191 192 twiddle(); 193 rc = (f->f_dev->dv_strategy)(f->f_devdata, F_WRITE, 194 fsbtodb(fs, (daddr32_t)ino_to_fsba(fs, inumber)), fs->fs_bsize, 195 buf, NULL); 196 197 out: 198 free(buf, fs->fs_bsize); 199 return (rc); 200 } 201 202 /* 203 * Given an offset in a file, find the disk block number that 204 * contains that block. 205 */ 206 static int 207 block_map(struct open_file *f, daddr32_t file_block, daddr32_t *disk_block_p) 208 { 209 struct file *fp = (struct file *)f->f_fsdata; 210 daddr32_t ind_block_num, *ind_p; 211 struct fs *fs = fp->f_fs; 212 int level, idx, rc; 213 214 /* 215 * Index structure of an inode: 216 * 217 * di_db[0..NDADDR-1] hold block numbers for blocks 218 * 0..NDADDR-1 219 * 220 * di_ib[0] index block 0 is the single indirect block 221 * holds block numbers for blocks 222 * NDADDR .. NDADDR + NINDIR(fs)-1 223 * 224 * di_ib[1] index block 1 is the double indirect block 225 * holds block numbers for INDEX blocks for blocks 226 * NDADDR + NINDIR(fs) .. 227 * NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1 228 * 229 * di_ib[2] index block 2 is the triple indirect block 230 * holds block numbers for double-indirect 231 * blocks for blocks 232 * NDADDR + NINDIR(fs) + NINDIR(fs)**2 .. 233 * NDADDR + NINDIR(fs) + NINDIR(fs)**2 234 * + NINDIR(fs)**3 - 1 235 */ 236 237 if (file_block < NDADDR) { 238 /* Direct block. */ 239 *disk_block_p = fp->f_di.di_db[file_block]; 240 return (0); 241 } 242 243 file_block -= NDADDR; 244 245 /* 246 * nindir[0] = NINDIR 247 * nindir[1] = NINDIR**2 248 * nindir[2] = NINDIR**3 249 * etc 250 */ 251 for (level = 0; level < NIADDR; level++) { 252 if (file_block < fp->f_nindir[level]) 253 break; 254 file_block -= fp->f_nindir[level]; 255 } 256 if (level == NIADDR) { 257 /* Block number too high */ 258 return (EFBIG); 259 } 260 261 ind_block_num = fp->f_di.di_ib[level]; 262 263 for (; level >= 0; level--) { 264 if (ind_block_num == 0) { 265 *disk_block_p = 0; /* missing */ 266 return (0); 267 } 268 269 if (fp->f_blkno[level] != ind_block_num) { 270 if (fp->f_blk[level] == NULL) 271 fp->f_blk[level] = 272 alloc(fs->fs_bsize); 273 twiddle(); 274 rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 275 fsbtodb(fp->f_fs, ind_block_num), fs->fs_bsize, 276 fp->f_blk[level], &fp->f_blksize[level]); 277 if (rc) 278 return (rc); 279 if (fp->f_blksize[level] != (size_t)fs->fs_bsize) 280 return (EIO); 281 fp->f_blkno[level] = ind_block_num; 282 } 283 284 ind_p = (daddr32_t *)fp->f_blk[level]; 285 286 if (level > 0) { 287 idx = file_block / fp->f_nindir[level - 1]; 288 file_block %= fp->f_nindir[level - 1]; 289 } else 290 idx = file_block; 291 292 ind_block_num = ind_p[idx]; 293 } 294 295 *disk_block_p = ind_block_num; 296 return (0); 297 } 298 299 /* 300 * Read a portion of a file into an internal buffer. Return 301 * the location in the buffer and the amount in the buffer. 302 */ 303 static int 304 buf_read_file(struct open_file *f, char **buf_p, size_t *size_p) 305 { 306 struct file *fp = (struct file *)f->f_fsdata; 307 struct fs *fs = fp->f_fs; 308 daddr32_t file_block, disk_block; 309 size_t block_size; 310 long off; 311 int rc; 312 313 off = blkoff(fs, fp->f_seekp); 314 file_block = lblkno(fs, fp->f_seekp); 315 block_size = dblksize(fs, &fp->f_di, (u_int64_t)file_block); 316 317 if (file_block != fp->f_buf_blkno) { 318 rc = block_map(f, file_block, &disk_block); 319 if (rc) 320 return (rc); 321 322 if (fp->f_buf == NULL) 323 fp->f_buf = alloc(fs->fs_bsize); 324 325 if (disk_block == 0) { 326 bzero(fp->f_buf, block_size); 327 fp->f_buf_size = block_size; 328 } else { 329 twiddle(); 330 rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 331 fsbtodb(fs, disk_block), 332 block_size, fp->f_buf, &fp->f_buf_size); 333 if (rc) 334 return (rc); 335 } 336 337 fp->f_buf_blkno = file_block; 338 } 339 340 /* 341 * Return address of byte in buffer corresponding to 342 * offset, and size of remainder of buffer after that 343 * byte. 344 */ 345 *buf_p = fp->f_buf + off; 346 *size_p = block_size - off; 347 348 /* 349 * But truncate buffer at end of file. 350 */ 351 if (*size_p > fp->f_di.di_size - fp->f_seekp) 352 *size_p = fp->f_di.di_size - fp->f_seekp; 353 354 return (0); 355 } 356 357 /* 358 * Search a directory for a name and return its 359 * i_number. 360 */ 361 static int 362 search_directory(char *name, struct open_file *f, ufsino_t *inumber_p) 363 { 364 struct file *fp = (struct file *)f->f_fsdata; 365 int namlen, length, rc; 366 struct direct *dp, *edp; 367 size_t buf_size; 368 char *buf; 369 370 length = strlen(name); 371 372 fp->f_seekp = 0; 373 while ((u_int64_t)fp->f_seekp < fp->f_di.di_size) { 374 rc = buf_read_file(f, &buf, &buf_size); 375 if (rc) 376 return (rc); 377 378 dp = (struct direct *)buf; 379 edp = (struct direct *)(buf + buf_size); 380 while (dp < edp) { 381 if (dp->d_ino == 0) 382 goto next; 383 #if BYTE_ORDER == LITTLE_ENDIAN 384 if (fp->f_fs->fs_maxsymlinklen <= 0) 385 namlen = dp->d_type; 386 else 387 #endif 388 namlen = dp->d_namlen; 389 if (namlen == length && 390 !strcmp(name, dp->d_name)) { 391 /* found entry */ 392 *inumber_p = dp->d_ino; 393 return (0); 394 } 395 next: 396 dp = (struct direct *)((char *)dp + dp->d_reclen); 397 } 398 fp->f_seekp += buf_size; 399 } 400 return (ENOENT); 401 } 402 403 /* 404 * Open a file. 405 */ 406 int 407 ufs_open(char *path, struct open_file *f) 408 { 409 char namebuf[MAXPATHLEN+1], *cp, *ncp, *buf = NULL; 410 ufsino_t inumber, parent_inumber; 411 int rc, c, nlinks = 0; 412 struct file *fp; 413 size_t buf_size; 414 struct fs *fs; 415 416 /* allocate file system specific data structure */ 417 fp = alloc(sizeof(struct file)); 418 bzero(fp, sizeof(struct file)); 419 f->f_fsdata = (void *)fp; 420 421 /* allocate space and read super block */ 422 fs = alloc(SBSIZE); 423 fp->f_fs = fs; 424 twiddle(); 425 rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 426 SBLOCK, SBSIZE, (char *)fs, &buf_size); 427 if (rc) 428 goto out; 429 430 if (buf_size != SBSIZE || fs->fs_magic != FS_MAGIC || 431 (size_t)fs->fs_bsize > MAXBSIZE || 432 (size_t)fs->fs_bsize < sizeof(struct fs)) { 433 rc = EINVAL; 434 goto out; 435 } 436 #ifdef COMPAT_UFS 437 ffs_oldfscompat(fs); 438 #endif 439 440 /* 441 * Calculate indirect block levels. 442 */ 443 { 444 int mult; 445 int level; 446 447 mult = 1; 448 for (level = 0; level < NIADDR; level++) { 449 mult *= NINDIR(fs); 450 fp->f_nindir[level] = mult; 451 } 452 } 453 454 inumber = ROOTINO; 455 if ((rc = read_inode(inumber, f)) != 0) 456 goto out; 457 458 cp = path; 459 while (*cp) { 460 461 /* 462 * Remove extra separators 463 */ 464 while (*cp == '/') 465 cp++; 466 if (*cp == '\0') 467 break; 468 469 /* 470 * Check that current node is a directory. 471 */ 472 if ((fp->f_di.di_mode & IFMT) != IFDIR) { 473 rc = ENOTDIR; 474 goto out; 475 } 476 477 /* 478 * Get next component of path name. 479 */ 480 { 481 int len = 0; 482 483 ncp = cp; 484 while ((c = *cp) != '\0' && c != '/') { 485 if (++len > MAXNAMLEN) { 486 rc = ENOENT; 487 goto out; 488 } 489 cp++; 490 } 491 *cp = '\0'; 492 } 493 494 /* 495 * Look up component in current directory. 496 * Save directory inumber in case we find a 497 * symbolic link. 498 */ 499 parent_inumber = inumber; 500 rc = search_directory(ncp, f, &inumber); 501 *cp = c; 502 if (rc) 503 goto out; 504 505 /* 506 * Open next component. 507 */ 508 if ((rc = read_inode(inumber, f)) != 0) 509 goto out; 510 511 /* 512 * Check for symbolic link. 513 */ 514 if ((fp->f_di.di_mode & IFMT) == IFLNK) { 515 u_int64_t link_len = fp->f_di.di_size; 516 size_t len; 517 518 len = strlen(cp); 519 520 if (link_len + len > MAXPATHLEN || 521 ++nlinks > MAXSYMLINKS) { 522 rc = ENOENT; 523 goto out; 524 } 525 526 bcopy(cp, &namebuf[link_len], len + 1); 527 528 if (link_len < (u_int64_t)fs->fs_maxsymlinklen) { 529 bcopy(fp->f_di.di_shortlink, namebuf, link_len); 530 } else { 531 /* 532 * Read file for symbolic link 533 */ 534 daddr32_t disk_block; 535 fs = fp->f_fs; 536 537 if (!buf) 538 buf = alloc(fs->fs_bsize); 539 rc = block_map(f, (daddr32_t)0, &disk_block); 540 if (rc) 541 goto out; 542 543 twiddle(); 544 rc = (f->f_dev->dv_strategy)(f->f_devdata, 545 F_READ, fsbtodb(fs, disk_block), 546 fs->fs_bsize, buf, &buf_size); 547 if (rc) 548 goto out; 549 550 bcopy(buf, namebuf, link_len); 551 } 552 553 /* 554 * If relative pathname, restart at parent directory. 555 * If absolute pathname, restart at root. 556 */ 557 cp = namebuf; 558 if (*cp != '/') 559 inumber = parent_inumber; 560 else 561 inumber = ROOTINO; 562 563 if ((rc = read_inode(inumber, f)) != 0) 564 goto out; 565 } 566 } 567 568 /* 569 * Found terminal component. 570 */ 571 fp->f_ino = inumber; 572 rc = 0; 573 out: 574 if (buf) 575 free(buf, fs->fs_bsize); 576 if (rc) 577 (void)ufs_close_internal(fp); 578 579 return (rc); 580 } 581 582 int 583 ufs_close(struct open_file *f) 584 { 585 struct file *fp = (struct file *)f->f_fsdata; 586 587 f->f_fsdata = NULL; 588 if (fp == NULL) 589 return (0); 590 591 return (ufs_close_internal(fp)); 592 } 593 594 static int 595 ufs_close_internal(struct file *fp) 596 { 597 int level; 598 599 for (level = 0; level < NIADDR; level++) { 600 if (fp->f_blk[level]) 601 free(fp->f_blk[level], fp->f_fs->fs_bsize); 602 } 603 if (fp->f_buf) 604 free(fp->f_buf, fp->f_fs->fs_bsize); 605 free(fp->f_fs, SBSIZE); 606 free(fp, sizeof(struct file)); 607 return (0); 608 } 609 610 /* 611 * Copy a portion of a file into kernel memory. 612 * Cross block boundaries when necessary. 613 */ 614 int 615 ufs_read(struct open_file *f, void *start, size_t size, size_t *resid) 616 { 617 struct file *fp = (struct file *)f->f_fsdata; 618 char *buf, *addr = start; 619 size_t csize, buf_size; 620 int rc = 0; 621 622 while (size != 0) { 623 if ((u_int64_t)fp->f_seekp >= fp->f_di.di_size) 624 break; 625 626 rc = buf_read_file(f, &buf, &buf_size); 627 if (rc) 628 break; 629 630 csize = size; 631 if (csize > buf_size) 632 csize = buf_size; 633 634 bcopy(buf, addr, csize); 635 636 fp->f_seekp += csize; 637 addr += csize; 638 size -= csize; 639 } 640 if (resid) 641 *resid = size; 642 return (rc); 643 } 644 645 /* 646 * Not implemented. 647 */ 648 int 649 ufs_write(struct open_file *f, void *start, size_t size, size_t *resid) 650 { 651 652 return (EROFS); 653 } 654 655 off_t 656 ufs_seek(struct open_file *f, off_t offset, int where) 657 { 658 struct file *fp = (struct file *)f->f_fsdata; 659 660 switch (where) { 661 case SEEK_SET: 662 fp->f_seekp = offset; 663 break; 664 case SEEK_CUR: 665 fp->f_seekp += offset; 666 break; 667 case SEEK_END: 668 fp->f_seekp = fp->f_di.di_size - offset; 669 break; 670 default: 671 return (-1); 672 } 673 return (fp->f_seekp); 674 } 675 676 int 677 ufs_stat(struct open_file *f, struct stat *sb) 678 { 679 struct file *fp = (struct file *)f->f_fsdata; 680 681 /* only important stuff */ 682 sb->st_mode = fp->f_di.di_mode; 683 sb->st_uid = fp->f_di.di_uid; 684 sb->st_gid = fp->f_di.di_gid; 685 sb->st_size = fp->f_di.di_size; 686 return (0); 687 } 688 689 int 690 ufs_fchmod(struct open_file *f, mode_t mode) 691 { 692 struct file *fp = (struct file *)f->f_fsdata; 693 694 return chmod_inode(fp->f_ino, f, mode); 695 } 696 697 #ifndef NO_READDIR 698 int 699 ufs_readdir(struct open_file *f, char *name) 700 { 701 struct file *fp = (struct file *)f->f_fsdata; 702 struct direct *dp, *edp; 703 size_t buf_size; 704 int rc, namlen; 705 char *buf; 706 707 if (name == NULL) 708 fp->f_seekp = 0; 709 else { 710 /* end of dir */ 711 if ((u_int64_t)fp->f_seekp >= fp->f_di.di_size) { 712 *name = '\0'; 713 return -1; 714 } 715 716 do { 717 if ((rc = buf_read_file(f, &buf, &buf_size)) != 0) 718 return rc; 719 720 dp = (struct direct *)buf; 721 edp = (struct direct *)(buf + buf_size); 722 while (dp < edp && dp->d_ino == 0) 723 dp = (struct direct *)((char *)dp + dp->d_reclen); 724 fp->f_seekp += buf_size - 725 ((u_int8_t *)edp - (u_int8_t *)dp); 726 } while (dp >= edp); 727 728 #if BYTE_ORDER == LITTLE_ENDIAN 729 if (fp->f_fs->fs_maxsymlinklen <= 0) 730 namlen = dp->d_type; 731 else 732 #endif 733 namlen = dp->d_namlen; 734 strncpy(name, dp->d_name, namlen + 1); 735 736 fp->f_seekp += dp->d_reclen; 737 } 738 739 return 0; 740 } 741 #endif 742 743 #ifdef COMPAT_UFS 744 /* 745 * Sanity checks for old file systems. 746 * 747 * XXX - goes away some day. 748 */ 749 static void 750 ffs_oldfscompat(struct fs *fs) 751 { 752 int i; 753 754 fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect); /* XXX */ 755 fs->fs_interleave = max(fs->fs_interleave, 1); /* XXX */ 756 if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 757 fs->fs_nrpos = 8; /* XXX */ 758 if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ 759 quad_t sizepb = fs->fs_bsize; /* XXX */ 760 /* XXX */ 761 fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1; /* XXX */ 762 for (i = 0; i < NIADDR; i++) { /* XXX */ 763 sizepb *= NINDIR(fs); /* XXX */ 764 fs->fs_maxfilesize += sizepb; /* XXX */ 765 } /* XXX */ 766 fs->fs_qbmask = ~fs->fs_bmask; /* XXX */ 767 fs->fs_qfmask = ~fs->fs_fmask; /* XXX */ 768 } /* XXX */ 769 } 770 #endif 771