1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/param.h> 29 #include <sys/systm.h> 30 #include <sys/kmem.h> 31 #include <sys/user.h> 32 #include <sys/proc.h> 33 #include <sys/cred.h> 34 #include <sys/disp.h> 35 #include <sys/buf.h> 36 #include <sys/vfs.h> 37 #include <sys/vnode.h> 38 #include <sys/fdio.h> 39 #include <sys/file.h> 40 #include <sys/uio.h> 41 #include <sys/conf.h> 42 #undef NFSCLIENT 43 #include <sys/statvfs.h> 44 #include <sys/mount.h> 45 #include <sys/pathname.h> 46 #include <sys/cmn_err.h> 47 #include <sys/debug.h> 48 #include <sys/sysmacros.h> 49 #include <sys/conf.h> 50 #include <sys/mkdev.h> 51 #include <sys/swap.h> 52 #include <sys/sunddi.h> 53 #include <sys/sunldi.h> 54 #include <sys/dktp/fdisk.h> 55 #include <sys/fs/pc_label.h> 56 #include <sys/fs/pc_fs.h> 57 #include <sys/fs/pc_dir.h> 58 #include <sys/fs/pc_node.h> 59 #include <fs/fs_subr.h> 60 #include <sys/modctl.h> 61 #include <sys/vol.h> 62 #include <sys/dkio.h> 63 #include <sys/open.h> 64 #include <sys/mntent.h> 65 #include <sys/policy.h> 66 67 /* 68 * The majority of PC media use a 512 sector size, but 69 * occasionally you will run across a 1k sector size. 70 * For media with a 1k sector size, fd_strategy() requires 71 * the I/O size to be a 1k multiple; so when the sector size 72 * is not yet known, always read 1k. 73 */ 74 #define PC_SAFESECSIZE (PC_SECSIZE * 2) 75 76 static int pcfs_pseudo_floppy(dev_t); 77 78 static int pcfsinit(int, char *); 79 static int pcfs_mount(struct vfs *, struct vnode *, struct mounta *, 80 struct cred *); 81 static int pcfs_unmount(struct vfs *, int, struct cred *); 82 static int pcfs_root(struct vfs *, struct vnode **); 83 static int pcfs_statvfs(struct vfs *, struct statvfs64 *); 84 static int pc_syncfsnodes(struct pcfs *); 85 static int pcfs_sync(struct vfs *, short, struct cred *); 86 static int pcfs_vget(struct vfs *vfsp, struct vnode **vpp, struct fid *fidp); 87 88 static int pc_getfattype(struct vnode *, int, daddr_t *, int *); 89 static int pc_readfat(struct pcfs *fsp, uchar_t *fatp, daddr_t start, 90 size_t fatsize); 91 static int pc_writefat(struct pcfs *fsp, daddr_t start); 92 93 /* 94 * pcfs mount options table 95 */ 96 97 static char *nohidden_cancel[] = {MNTOPT_PCFS_HIDDEN, NULL}; 98 static char *hidden_cancel[] = {MNTOPT_PCFS_NOHIDDEN, NULL}; 99 static char *nofoldcase_cancel[] = {MNTOPT_PCFS_FOLDCASE, NULL}; 100 static char *foldcase_cancel[] = {MNTOPT_PCFS_NOFOLDCASE, NULL}; 101 102 static mntopt_t mntopts[] = { 103 /* 104 * option name cancel option default arg flags 105 * opt data 106 */ 107 { MNTOPT_PCFS_NOHIDDEN, nohidden_cancel, NULL, 0, 108 NULL }, 109 { MNTOPT_PCFS_HIDDEN, hidden_cancel, NULL, MO_DEFAULT, 110 NULL }, 111 { MNTOPT_PCFS_NOFOLDCASE, nofoldcase_cancel, NULL, MO_DEFAULT, 112 NULL }, 113 { MNTOPT_PCFS_FOLDCASE, foldcase_cancel, NULL, 0, 114 NULL } 115 }; 116 117 static mntopts_t pcfs_mntopts = { 118 sizeof (mntopts) / sizeof (mntopt_t), 119 mntopts 120 }; 121 122 int pcfsdebuglevel = 0; 123 124 /* 125 * pcfslock: protects the list of mounted pc filesystems "pc_mounttab. 126 * pcfs_lock: (inside per filesystem structure "pcfs") 127 * per filesystem lock. Most of the vfsops and vnodeops are 128 * protected by this lock. 129 * pcnodes_lock: protects the pcnode hash table "pcdhead", "pcfhead". 130 * 131 * Lock hierarchy: pcfslock > pcfs_lock > pcnodes_lock 132 */ 133 kmutex_t pcfslock; 134 krwlock_t pcnodes_lock; /* protect the pcnode hash table "pcdhead", "pcfhead" */ 135 136 static int pcfstype; 137 138 static vfsdef_t vfw = { 139 VFSDEF_VERSION, 140 "pcfs", 141 pcfsinit, 142 VSW_HASPROTO|VSW_CANREMOUNT|VSW_STATS, 143 &pcfs_mntopts 144 }; 145 146 extern struct mod_ops mod_fsops; 147 148 static struct modlfs modlfs = { 149 &mod_fsops, 150 "PC filesystem v%I%", 151 &vfw 152 }; 153 154 static struct modlinkage modlinkage = { 155 MODREV_1, 156 &modlfs, 157 NULL 158 }; 159 160 int 161 _init(void) 162 { 163 int error; 164 165 #if !defined(lint) 166 /* make sure the on-disk structures are sane */ 167 ASSERT(sizeof (struct pcdir) == 32); 168 ASSERT(sizeof (struct pcdir_lfn) == 32); 169 #endif 170 mutex_init(&pcfslock, NULL, MUTEX_DEFAULT, NULL); 171 rw_init(&pcnodes_lock, NULL, RW_DEFAULT, NULL); 172 error = mod_install(&modlinkage); 173 if (error) { 174 mutex_destroy(&pcfslock); 175 rw_destroy(&pcnodes_lock); 176 } 177 return (error); 178 } 179 180 int 181 _fini(void) 182 { 183 int error; 184 185 error = mod_remove(&modlinkage); 186 if (error) 187 return (error); 188 mutex_destroy(&pcfslock); 189 rw_destroy(&pcnodes_lock); 190 /* 191 * Tear down the operations vectors 192 */ 193 (void) vfs_freevfsops_by_type(pcfstype); 194 vn_freevnodeops(pcfs_fvnodeops); 195 vn_freevnodeops(pcfs_dvnodeops); 196 return (0); 197 } 198 199 int 200 _info(struct modinfo *modinfop) 201 { 202 return (mod_info(&modlinkage, modinfop)); 203 } 204 205 /* ARGSUSED1 */ 206 static int 207 pcfsinit(int fstype, char *name) 208 { 209 static const fs_operation_def_t pcfs_vfsops_template[] = { 210 VFSNAME_MOUNT, pcfs_mount, 211 VFSNAME_UNMOUNT, pcfs_unmount, 212 VFSNAME_ROOT, pcfs_root, 213 VFSNAME_STATVFS, pcfs_statvfs, 214 VFSNAME_SYNC, (fs_generic_func_p) pcfs_sync, 215 VFSNAME_VGET, pcfs_vget, 216 NULL, NULL 217 }; 218 int error; 219 220 error = vfs_setfsops(fstype, pcfs_vfsops_template, NULL); 221 if (error != 0) { 222 cmn_err(CE_WARN, "pcfsinit: bad vfs ops template"); 223 return (error); 224 } 225 226 error = vn_make_ops("pcfs", pcfs_fvnodeops_template, &pcfs_fvnodeops); 227 if (error != 0) { 228 (void) vfs_freevfsops_by_type(fstype); 229 cmn_err(CE_WARN, "pcfsinit: bad file vnode ops template"); 230 return (error); 231 } 232 233 error = vn_make_ops("pcfsd", pcfs_dvnodeops_template, &pcfs_dvnodeops); 234 if (error != 0) { 235 (void) vfs_freevfsops_by_type(fstype); 236 vn_freevnodeops(pcfs_fvnodeops); 237 cmn_err(CE_WARN, "pcfsinit: bad dir vnode ops template"); 238 return (error); 239 } 240 241 pcfstype = fstype; 242 (void) pc_init(); 243 return (0); 244 } 245 246 static struct pcfs *pc_mounttab = NULL; 247 248 extern struct pcfs_args pc_tz; 249 250 /* 251 * Define some special logical drives we use internal to this file. 252 */ 253 #define BOOT_PARTITION_DRIVE 99 254 #define PRIMARY_DOS_DRIVE 1 255 256 /* 257 * pc_mount system call 258 */ 259 static int 260 pcfs_mount( 261 struct vfs *vfsp, 262 struct vnode *mvp, 263 struct mounta *uap, 264 struct cred *cr) 265 { 266 struct pcfs *fsp; 267 struct vnode *bvp; 268 struct vnode *devvp; 269 struct pathname special; 270 daddr_t dosstart; 271 dev_t pseudodev; 272 dev_t xdev; 273 char *spnp; 274 char *data = uap->dataptr; 275 int datalen = uap->datalen; 276 int dos_ldrive = 0; 277 int error; 278 int fattype; 279 int spnlen; 280 int wantbootpart = 0; 281 struct vioc_info info; 282 int rval; /* set but not used */ 283 minor_t minor; 284 int oflag, aflag; 285 286 if ((error = secpolicy_fs_mount(cr, mvp, vfsp)) != 0) 287 return (error); 288 289 PC_DPRINTF0(4, "pcfs_mount\n"); 290 if (mvp->v_type != VDIR) { 291 return (ENOTDIR); 292 } 293 mutex_enter(&mvp->v_lock); 294 if ((uap->flags & MS_REMOUNT) == 0 && 295 (uap->flags & MS_OVERLAY) == 0 && 296 (mvp->v_count != 1 || (mvp->v_flag & VROOT))) { 297 mutex_exit(&mvp->v_lock); 298 return (EBUSY); 299 } 300 mutex_exit(&mvp->v_lock); 301 302 /* 303 * The caller is responsible for making sure to always 304 * pass in sizeof(struct pcfs_args) (or the old one). 305 * Doing this is the only way to know an EINVAL return 306 * from mount(2) is due to the "not a DOS filesystem" 307 * EINVAL that pc_verify/pc_getfattype could return. 308 */ 309 if ((datalen != sizeof (struct pcfs_args)) && 310 (datalen != sizeof (struct old_pcfs_args))) { 311 return (EINVAL); 312 } else { 313 struct pcfs_args tmp_tz; 314 int hidden = 0; 315 int foldcase = 0; 316 317 tmp_tz.flags = 0; 318 if (copyin(data, &tmp_tz, datalen)) { 319 return (EFAULT); 320 } 321 if (datalen == sizeof (struct pcfs_args)) { 322 hidden = tmp_tz.flags & PCFS_MNT_HIDDEN; 323 foldcase = tmp_tz.flags & PCFS_MNT_FOLDCASE; 324 } 325 326 if (hidden) 327 vfs_setmntopt(vfsp, MNTOPT_PCFS_HIDDEN, NULL, 0); 328 if (foldcase) 329 vfs_setmntopt(vfsp, MNTOPT_PCFS_FOLDCASE, NULL, 0); 330 /* 331 * more than one pc filesystem can be mounted on x86 332 * so the pc_tz structure is now a critical region 333 */ 334 mutex_enter(&pcfslock); 335 if (pc_mounttab == NULL) 336 bcopy(&tmp_tz, &pc_tz, sizeof (struct pcfs_args)); 337 mutex_exit(&pcfslock); 338 } 339 /* 340 * Resolve path name of special file being mounted. 341 */ 342 if (error = pn_get(uap->spec, UIO_USERSPACE, &special)) { 343 return (error); 344 } 345 if (error = 346 lookupname(special.pn_path, UIO_SYSSPACE, FOLLOW, NULLVPP, &bvp)) { 347 /* 348 * look for suffix to special 349 * which indicates a request to mount the solaris boot 350 * partition, or a DOS logical drive on the hard disk 351 */ 352 spnlen = special.pn_pathlen; 353 354 if (spnlen > 5) { 355 spnp = special.pn_path + spnlen - 5; 356 if (*spnp++ == ':' && *spnp++ == 'b' && 357 *spnp++ == 'o' && *spnp++ == 'o' && 358 *spnp++ == 't') { 359 /* 360 * Looks as if they want to mount 361 * the Solaris boot partition 362 */ 363 wantbootpart = 1; 364 dos_ldrive = BOOT_PARTITION_DRIVE; 365 spnp = special.pn_path + spnlen - 5; 366 *spnp = '\0'; 367 error = lookupname(special.pn_path, 368 UIO_SYSSPACE, FOLLOW, NULLVPP, &bvp); 369 } 370 } 371 372 if (!wantbootpart) { 373 spnp = special.pn_path + spnlen - 1; 374 if (spnlen > 2 && *spnp >= 'c' && *spnp <= 'z') { 375 spnlen--; 376 dos_ldrive = *spnp-- - 'c' + 1; 377 } else if (spnlen > 2 && *spnp >= '0' && *spnp <= '9') { 378 spnlen--; 379 dos_ldrive = *spnp-- - '0'; 380 if (spnlen > 2 && *spnp >= '0' && 381 *spnp <= '9') { 382 spnlen--; 383 dos_ldrive += 10 * (*spnp-- - '0'); 384 } 385 } 386 if (spnlen > 1 && dos_ldrive && dos_ldrive <= 24 && 387 *spnp == ':') { 388 /* 389 * remove suffix so that we have a real 390 * device name 391 */ 392 *spnp = '\0'; 393 error = lookupname(special.pn_path, 394 UIO_SYSSPACE, FOLLOW, NULLVPP, &bvp); 395 } 396 } 397 if (error) { 398 pn_free(&special); 399 return (error); 400 } 401 } 402 pn_free(&special); 403 if (bvp->v_type != VBLK) { 404 VN_RELE(bvp); 405 return (ENOTBLK); 406 } 407 xdev = bvp->v_rdev; 408 /* 409 * Verify caller's permission to open the device special file. 410 */ 411 if ((vfsp->vfs_flag & VFS_RDONLY) != 0 || 412 ((uap->flags & MS_RDONLY) != 0)) { 413 oflag = FREAD; 414 aflag = VREAD; 415 } else { 416 oflag = FREAD | FWRITE; 417 aflag = VREAD | VWRITE; 418 } 419 if ((error = VOP_ACCESS(bvp, aflag, 0, cr)) != 0 || 420 (error = secpolicy_spec_open(cr, bvp, oflag)) != 0) { 421 VN_RELE(bvp); 422 return (error); 423 } 424 425 VN_RELE(bvp); 426 if (getmajor(xdev) >= devcnt) { 427 return (ENXIO); 428 } 429 /* 430 * Ensure that this device (or logical drive) isn't already mounted, 431 * unless this is a REMOUNT request 432 */ 433 if (dos_ldrive) { 434 mutex_enter(&pcfslock); 435 for (fsp = pc_mounttab; fsp; fsp = fsp->pcfs_nxt) 436 if (fsp->pcfs_xdev == xdev && 437 fsp->pcfs_ldrv == dos_ldrive) { 438 mutex_exit(&pcfslock); 439 if (uap->flags & MS_REMOUNT) { 440 return (0); 441 } else { 442 return (EBUSY); 443 } 444 } 445 /* 446 * Assign a unique device number for the vfs 447 * The old way (getudev() + a constantly incrementing 448 * major number) was wrong because it changes vfs_dev 449 * across mounts and reboots, which breaks nfs file handles. 450 * UFS just uses the real dev_t. We can't do that because 451 * of the way pcfs opens fdisk partitons (the :c and :d 452 * partitions are on the same dev_t). Though that _might_ 453 * actually be ok, since the file handle contains an 454 * absolute block number, it's probably better to make them 455 * different. So I think we should retain the original 456 * dev_t, but come up with a different minor number based 457 * on the logical drive that will _always_ come up the same. 458 * For now, we steal the upper 6 bits. 459 */ 460 #ifdef notdef 461 /* what should we do here? */ 462 if (((getminor(xdev) >> 12) & 0x3F) != 0) 463 printf("whoops - upper bits used!\n"); 464 #endif 465 minor = ((dos_ldrive << 12) | getminor(xdev)) & MAXMIN32; 466 pseudodev = makedevice(getmajor(xdev), minor); 467 if (vfs_devmounting(pseudodev, vfsp)) { 468 mutex_exit(&pcfslock); 469 return (EBUSY); 470 } 471 if (vfs_devismounted(pseudodev)) { 472 mutex_exit(&pcfslock); 473 if (uap->flags & MS_REMOUNT) { 474 return (0); 475 } else { 476 return (EBUSY); 477 } 478 } 479 mutex_exit(&pcfslock); 480 } else { 481 if (vfs_devmounting(xdev, vfsp)) { 482 return (EBUSY); 483 } 484 if (vfs_devismounted(xdev)) 485 if (uap->flags & MS_REMOUNT) { 486 return (0); 487 } else { 488 return (EBUSY); 489 } 490 pseudodev = xdev; 491 } 492 493 if (uap->flags & MS_RDONLY) { 494 vfsp->vfs_flag |= VFS_RDONLY; 495 vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0); 496 } 497 498 /* 499 * Mount the filesystem 500 */ 501 devvp = makespecvp(xdev, VBLK); 502 if (IS_SWAPVP(devvp)) { 503 VN_RELE(devvp); 504 return (EBUSY); 505 } 506 507 /* 508 * special handling for PCMCIA memory card 509 * with pseudo floppies organization 510 */ 511 if (dos_ldrive == 0 && pcfs_pseudo_floppy(xdev)) { 512 dosstart = (daddr_t)0; 513 fattype = PCFS_PCMCIA_NO_CIS; 514 } else { 515 if (error = pc_getfattype(devvp, dos_ldrive, &dosstart, 516 &fattype)) { 517 VN_RELE(devvp); 518 return (error); 519 } 520 } 521 522 (void) VOP_PUTPAGE(devvp, (offset_t)0, (uint_t)0, B_INVAL, cr); 523 fsp = kmem_zalloc((uint_t)sizeof (struct pcfs), KM_SLEEP); 524 fsp->pcfs_vfs = vfsp; 525 fsp->pcfs_flags = fattype; 526 fsp->pcfs_devvp = devvp; 527 fsp->pcfs_xdev = xdev; 528 fsp->pcfs_ldrv = dos_ldrive; 529 fsp->pcfs_dosstart = dosstart; 530 mutex_init(&fsp->pcfs_lock, NULL, MUTEX_DEFAULT, NULL); 531 532 /* set the "nocheck" flag if volmgt is managing this volume */ 533 info.vii_pathlen = 0; 534 info.vii_devpath = 0; 535 error = cdev_ioctl(fsp->pcfs_xdev, VOLIOCINFO, (intptr_t)&info, 536 FKIOCTL|FREAD, kcred, &rval); 537 if (error == 0) { 538 fsp->pcfs_flags |= PCFS_NOCHK; 539 } 540 541 if (vfs_optionisset(vfsp, MNTOPT_PCFS_HIDDEN, NULL)) 542 fsp->pcfs_flags |= PCFS_HIDDEN; 543 if (vfs_optionisset(vfsp, MNTOPT_PCFS_FOLDCASE, NULL)) 544 fsp->pcfs_flags |= PCFS_FOLDCASE; 545 vfsp->vfs_dev = pseudodev; 546 vfsp->vfs_fstype = pcfstype; 547 vfs_make_fsid(&vfsp->vfs_fsid, pseudodev, pcfstype); 548 vfsp->vfs_data = (caddr_t)fsp; 549 vfsp->vfs_bcount = 0; 550 551 error = pc_verify(fsp); 552 if (error) { 553 VN_RELE(devvp); 554 mutex_destroy(&fsp->pcfs_lock); 555 kmem_free(fsp, (uint_t)sizeof (struct pcfs)); 556 return (error); 557 } 558 vfsp->vfs_bsize = fsp->pcfs_clsize; 559 560 mutex_enter(&pcfslock); 561 fsp->pcfs_nxt = pc_mounttab; 562 pc_mounttab = fsp; 563 mutex_exit(&pcfslock); 564 return (0); 565 } 566 567 /* 568 * vfs operations 569 */ 570 571 /* ARGSUSED */ 572 static int 573 pcfs_unmount( 574 struct vfs *vfsp, 575 int flag, 576 struct cred *cr) 577 { 578 struct pcfs *fsp, *fsp1; 579 580 if (secpolicy_fs_unmount(cr, vfsp) != 0) 581 return (EPERM); 582 583 /* 584 * forced unmount is not supported by this file system 585 * and thus, ENOTSUP, is being returned. 586 */ 587 if (flag & MS_FORCE) 588 return (ENOTSUP); 589 590 PC_DPRINTF0(4, "pcfs_unmount\n"); 591 fsp = VFSTOPCFS(vfsp); 592 /* 593 * We don't have to lock fsp because the VVFSLOCK in vfs layer will 594 * prevent lookuppn from crossing the mount point. 595 */ 596 if (fsp->pcfs_nrefs) { 597 return (EBUSY); 598 } 599 600 /* 601 * Allow an unmount (regardless of state) if the fs instance has 602 * been marked as beyond recovery. 603 */ 604 if (fsp->pcfs_flags & PCFS_IRRECOV) { 605 mutex_enter(&pcfslock); 606 rw_enter(&pcnodes_lock, RW_WRITER); 607 pc_diskchanged(fsp); 608 rw_exit(&pcnodes_lock); 609 mutex_exit(&pcfslock); 610 } 611 612 /* now there should be no pcp node on pcfhead or pcdhead. */ 613 614 mutex_enter(&pcfslock); 615 if (fsp == pc_mounttab) { 616 pc_mounttab = fsp->pcfs_nxt; 617 } else { 618 for (fsp1 = pc_mounttab; fsp1 != NULL; fsp1 = fsp1->pcfs_nxt) 619 if (fsp1->pcfs_nxt == fsp) 620 fsp1->pcfs_nxt = fsp->pcfs_nxt; 621 } 622 623 if (fsp->pcfs_fatp != (uchar_t *)0) { 624 pc_invalfat(fsp); 625 } 626 mutex_exit(&pcfslock); 627 628 VN_RELE(fsp->pcfs_devvp); 629 mutex_destroy(&fsp->pcfs_lock); 630 kmem_free(fsp, (uint_t)sizeof (struct pcfs)); 631 return (0); 632 } 633 634 /* 635 * find root of pcfs 636 */ 637 static int 638 pcfs_root( 639 struct vfs *vfsp, 640 struct vnode **vpp) 641 { 642 struct pcfs *fsp; 643 struct pcnode *pcp; 644 int error; 645 646 fsp = VFSTOPCFS(vfsp); 647 if (error = pc_lockfs(fsp, 0, 0)) 648 return (error); 649 pcp = pc_getnode(fsp, (daddr_t)0, 0, (struct pcdir *)0); 650 PC_DPRINTF2(9, "pcfs_root(0x%p) pcp= 0x%p\n", 651 (void *)vfsp, (void *)pcp); 652 pc_unlockfs(fsp); 653 *vpp = PCTOV(pcp); 654 pcp->pc_flags |= PC_EXTERNAL; 655 return (0); 656 } 657 658 /* 659 * Get file system statistics. 660 */ 661 static int 662 pcfs_statvfs( 663 struct vfs *vfsp, 664 struct statvfs64 *sp) 665 { 666 struct pcfs *fsp; 667 int error; 668 dev32_t d32; 669 670 fsp = VFSTOPCFS(vfsp); 671 error = pc_getfat(fsp); 672 if (error) 673 return (error); 674 bzero(sp, sizeof (*sp)); 675 sp->f_bsize = sp->f_frsize = fsp->pcfs_clsize; 676 sp->f_blocks = (fsblkcnt64_t)fsp->pcfs_ncluster; 677 sp->f_bavail = sp->f_bfree = (fsblkcnt64_t)pc_freeclusters(fsp); 678 sp->f_files = (fsfilcnt64_t)-1; 679 sp->f_ffree = (fsfilcnt64_t)-1; 680 sp->f_favail = (fsfilcnt64_t)-1; 681 #ifdef notdef 682 (void) cmpldev(&d32, fsp->pcfs_devvp->v_rdev); 683 #endif /* notdef */ 684 (void) cmpldev(&d32, vfsp->vfs_dev); 685 sp->f_fsid = d32; 686 (void) strcpy(sp->f_basetype, vfssw[vfsp->vfs_fstype].vsw_name); 687 sp->f_flag = vf_to_stf(vfsp->vfs_flag); 688 sp->f_namemax = PCFNAMESIZE; 689 return (0); 690 } 691 692 static int 693 pc_syncfsnodes(struct pcfs *fsp) 694 { 695 struct pchead *hp; 696 struct pcnode *pcp; 697 int error; 698 699 PC_DPRINTF0(7, "pcfs_syncfsnodes\n"); 700 if (error = pc_lockfs(fsp, 0, 0)) 701 return (error); 702 703 if (!(error = pc_syncfat(fsp))) { 704 hp = pcfhead; 705 while (hp < & pcfhead [ NPCHASH ]) { 706 rw_enter(&pcnodes_lock, RW_READER); 707 pcp = hp->pch_forw; 708 while (pcp != (struct pcnode *)hp) { 709 if (VFSTOPCFS(PCTOV(pcp) -> v_vfsp) == fsp) 710 if (error = pc_nodesync(pcp)) 711 break; 712 pcp = pcp -> pc_forw; 713 } 714 rw_exit(&pcnodes_lock); 715 if (error) 716 break; 717 hp++; 718 } 719 } 720 pc_unlockfs(fsp); 721 return (error); 722 } 723 724 /* 725 * Flush any pending I/O. 726 */ 727 /*ARGSUSED*/ 728 static int 729 pcfs_sync( 730 struct vfs *vfsp, 731 short flag, 732 struct cred *cr) 733 { 734 struct pcfs *fsp; 735 int error = 0; 736 737 /* this prevents the filesystem from being umounted. */ 738 mutex_enter(&pcfslock); 739 if (vfsp != NULL) { 740 fsp = VFSTOPCFS(vfsp); 741 if (!(fsp->pcfs_flags & PCFS_IRRECOV)) { 742 error = pc_syncfsnodes(fsp); 743 } else { 744 rw_enter(&pcnodes_lock, RW_WRITER); 745 pc_diskchanged(fsp); 746 rw_exit(&pcnodes_lock); 747 error = EIO; 748 } 749 } else { 750 fsp = pc_mounttab; 751 while (fsp != NULL) { 752 if (fsp->pcfs_flags & PCFS_IRRECOV) { 753 rw_enter(&pcnodes_lock, RW_WRITER); 754 pc_diskchanged(fsp); 755 rw_exit(&pcnodes_lock); 756 error = EIO; 757 break; 758 } 759 error = pc_syncfsnodes(fsp); 760 if (error) break; 761 fsp = fsp->pcfs_nxt; 762 } 763 } 764 mutex_exit(&pcfslock); 765 return (error); 766 } 767 768 int 769 pc_lockfs(struct pcfs *fsp, int diskchanged, int releasing) 770 { 771 if ((fsp->pcfs_flags & PCFS_IRRECOV) && !releasing) 772 return (EIO); 773 774 if ((fsp->pcfs_flags & PCFS_LOCKED) && (fsp->pcfs_owner == curthread)) { 775 fsp->pcfs_count++; 776 } else { 777 mutex_enter(&fsp->pcfs_lock); 778 if (fsp->pcfs_flags & PCFS_LOCKED) 779 panic("pc_lockfs"); 780 /* 781 * We check the IRRECOV bit again just in case somebody 782 * snuck past the initial check but then got held up before 783 * they could grab the lock. (And in the meantime someone 784 * had grabbed the lock and set the bit) 785 */ 786 if (!diskchanged && !(fsp->pcfs_flags & PCFS_IRRECOV)) { 787 int err; 788 if ((err = pc_getfat(fsp))) 789 return (err); 790 } 791 fsp->pcfs_flags |= PCFS_LOCKED; 792 fsp->pcfs_owner = curthread; 793 fsp->pcfs_count++; 794 } 795 return (0); 796 } 797 798 void 799 pc_unlockfs(struct pcfs *fsp) 800 { 801 802 if ((fsp->pcfs_flags & PCFS_LOCKED) == 0) 803 panic("pc_unlockfs"); 804 if (--fsp->pcfs_count < 0) 805 panic("pc_unlockfs: count"); 806 if (fsp->pcfs_count == 0) { 807 fsp->pcfs_flags &= ~PCFS_LOCKED; 808 fsp->pcfs_owner = 0; 809 mutex_exit(&fsp->pcfs_lock); 810 } 811 } 812 813 /* 814 * isDosDrive() 815 * Boolean function. Give it the systid field for an fdisk partition 816 * and it decides if that's a systid that describes a DOS drive. We 817 * use systid values defined in sys/dktp/fdisk.h. 818 */ 819 static int 820 isDosDrive(uchar_t checkMe) 821 { 822 return ((checkMe == DOSOS12) || (checkMe == DOSOS16) || 823 (checkMe == DOSHUGE) || (checkMe == FDISK_WINDOWS) || 824 (checkMe == FDISK_EXT_WIN) || (checkMe == FDISK_FAT95) || 825 (checkMe == DIAGPART)); 826 } 827 828 /* 829 * isDosExtended() 830 * Boolean function. Give it the systid field for an fdisk partition 831 * and it decides if that's a systid that describes an extended DOS 832 * partition. 833 */ 834 static int 835 isDosExtended(uchar_t checkMe) 836 { 837 return ((checkMe == EXTDOS) || (checkMe == FDISK_EXTLBA)); 838 } 839 840 /* 841 * isBootPart() 842 * Boolean function. Give it the systid field for an fdisk partition 843 * and it decides if that's a systid that describes a Solaris boot 844 * partition. 845 */ 846 static int 847 isBootPart(uchar_t checkMe) 848 { 849 return (checkMe == X86BOOT); 850 } 851 852 /* 853 * noLogicalDrive() 854 * Display error message about not being able to find a logical 855 * drive. 856 */ 857 static void 858 noLogicalDrive(int requested) 859 { 860 if (requested == BOOT_PARTITION_DRIVE) { 861 cmn_err(CE_NOTE, "!pcfs: no boot partition"); 862 } else { 863 cmn_err(CE_NOTE, "!pcfs: no such logical drive"); 864 } 865 } 866 867 /* 868 * findTheDrive() 869 * Discover offset of the requested logical drive, and return 870 * that offset (startSector), the systid of that drive (sysid), 871 * and a buffer pointer (bp), with the buffer contents being 872 * the first sector of the logical drive (i.e., the sector that 873 * contains the BPB for that drive). 874 */ 875 static int 876 findTheDrive(dev_t dev, int askedFor, int *error, buf_t **bp, 877 daddr_t *startSector, uchar_t *sysid) 878 { 879 struct ipart dosp[FD_NUMPART]; /* incore fdisk partition structure */ 880 struct mboot *dosp_ptr; /* boot structure pointer */ 881 daddr_t lastseek = 0; /* Disk block we sought previously */ 882 daddr_t diskblk = 0; /* Disk block to get */ 883 daddr_t xstartsect; /* base of Extended DOS partition */ 884 int logicalDriveCount = 0; /* Count of logical drives seen */ 885 int extendedPart = -1; /* index of extended dos partition */ 886 int primaryPart = -1; /* index of primary dos partition */ 887 int bootPart = -1; /* index of a Solaris boot partition */ 888 int xnumsect = -1; /* length of extended DOS partition */ 889 int driveIndex; /* computed FDISK table index */ 890 int i; 891 /* 892 * Count of drives in the current extended partition's 893 * FDISK table, and indexes of the drives themselves. 894 */ 895 int extndDrives[FD_NUMPART]; 896 int numDrives = 0; 897 898 /* 899 * Count of drives (beyond primary) in master boot record's 900 * FDISK table, and indexes of the drives themselves. 901 */ 902 int extraDrives[FD_NUMPART]; 903 int numExtraDrives = 0; 904 905 /* 906 * Copy from disk block into memory aligned structure for fdisk usage. 907 */ 908 dosp_ptr = (struct mboot *)(*bp)->b_un.b_addr; 909 bcopy(dosp_ptr->parts, dosp, sizeof (struct ipart) * FD_NUMPART); 910 911 /* 912 * Get a summary of what is in the Master FDISK table. 913 * Normally we expect to find one partition marked as a DOS drive. 914 * This partition is the one Windows calls the primary dos partition. 915 * If the machine has any logical drives then we also expect 916 * to find a partition marked as an extended DOS partition. 917 * 918 * Sometimes we'll find multiple partitions marked as DOS drives. 919 * The Solaris fdisk program allows these partitions 920 * to be created, but Windows fdisk no longer does. We still need 921 * to support these, though, since Windows does. We also need to fix 922 * our fdisk to behave like the Windows version. 923 * 924 * It turns out that some off-the-shelf media have *only* an 925 * Extended partition, so we need to deal with that case as well. 926 * 927 * Only a single (the first) Extended or Boot Partition will 928 * be recognized. Any others will be ignored. 929 */ 930 for (i = 0; i < FD_NUMPART; i++) { 931 PC_DPRINTF1(2, "findTheDrive: found partition type %02x", 932 dosp[i].systid); 933 934 if (isDosDrive(dosp[i].systid)) { 935 if (primaryPart < 0) { 936 logicalDriveCount++; 937 primaryPart = i; 938 } else { 939 extraDrives[numExtraDrives++] = i; 940 } 941 continue; 942 } 943 if ((extendedPart < 0) && isDosExtended(dosp[i].systid)) { 944 extendedPart = i; 945 continue; 946 } 947 if ((bootPart < 0) && isBootPart(dosp[i].systid)) { 948 bootPart = i; 949 continue; 950 } 951 } 952 953 if (askedFor == BOOT_PARTITION_DRIVE) { 954 if (bootPart < 0) { 955 noLogicalDrive(askedFor); 956 *error = EINVAL; 957 return (0); 958 } 959 *sysid = dosp[bootPart].systid; 960 *startSector = ltohi(dosp[bootPart].relsect); 961 return (1); 962 } 963 964 if (askedFor == PRIMARY_DOS_DRIVE && primaryPart >= 0) { 965 *sysid = dosp[primaryPart].systid; 966 *startSector = ltohi(dosp[primaryPart].relsect); 967 return (1); 968 } 969 970 /* 971 * We are not looking for the C: drive (or the primary drive 972 * was not found), so we had better have an extended partition 973 * or extra drives in the Master FDISK table. 974 */ 975 if ((extendedPart < 0) && (numExtraDrives == 0)) { 976 cmn_err(CE_NOTE, "!pcfs: no extended dos partition"); 977 noLogicalDrive(askedFor); 978 *error = EINVAL; 979 return (0); 980 } 981 982 if (extendedPart >= 0) { 983 diskblk = xstartsect = ltohi(dosp[extendedPart].relsect); 984 xnumsect = ltohi(dosp[extendedPart].numsect); 985 do { 986 /* 987 * If the seek would not cause us to change 988 * position on the drive, then we're out of 989 * extended partitions to examine. 990 */ 991 if (diskblk == lastseek) 992 break; 993 logicalDriveCount += numDrives; 994 /* 995 * Seek the next extended partition, and find 996 * logical drives within it. 997 */ 998 brelse(*bp); 999 *bp = bread(dev, diskblk, PC_SAFESECSIZE); 1000 if ((*bp)->b_flags & B_ERROR) { 1001 PC_DPRINTF0(1, "pc_getfattype: read error\n"); 1002 *error = EIO; 1003 return (0); 1004 } 1005 lastseek = diskblk; 1006 dosp_ptr = (struct mboot *)(*bp)->b_un.b_addr; 1007 if (ltohs(dosp_ptr->signature) != MBB_MAGIC) { 1008 cmn_err(CE_NOTE, "!pcfs: " 1009 "extended partition signature err"); 1010 *error = EINVAL; 1011 return (0); 1012 } 1013 bcopy(dosp_ptr->parts, dosp, 1014 sizeof (struct ipart) * FD_NUMPART); 1015 /* 1016 * Count up drives, and track where the next 1017 * extended partition is in case we need it. We 1018 * are expecting only one extended partition. If 1019 * there is more than one we'll only go to the 1020 * first one we see, but warn about ignoring. 1021 */ 1022 numDrives = 0; 1023 for (i = 0; i < FD_NUMPART; i++) { 1024 if (isDosDrive(dosp[i].systid)) { 1025 extndDrives[numDrives++] = i; 1026 continue; 1027 } else if (isDosExtended(dosp[i].systid)) { 1028 if (diskblk != lastseek) { 1029 /* 1030 * Already found an extended 1031 * partition in this table. 1032 */ 1033 cmn_err(CE_NOTE, 1034 "!pcfs: ignoring unexpected" 1035 " additional extended" 1036 " partition"); 1037 continue; 1038 } 1039 diskblk = xstartsect + 1040 ltohi(dosp[i].relsect); 1041 continue; 1042 } 1043 } 1044 } while (askedFor > logicalDriveCount + numDrives); 1045 1046 if (askedFor <= logicalDriveCount + numDrives) { 1047 /* 1048 * The number of logical drives we've found thus 1049 * far is enough to get us to the one we were 1050 * searching for. 1051 */ 1052 driveIndex = logicalDriveCount + numDrives - askedFor; 1053 *sysid = dosp[extndDrives[driveIndex]].systid; 1054 *startSector = 1055 ltohi(dosp[extndDrives[driveIndex]].relsect) + 1056 lastseek; 1057 if (*startSector > (xstartsect + xnumsect)) { 1058 cmn_err(CE_NOTE, "!pcfs: extended partition " 1059 "values bad"); 1060 *error = EINVAL; 1061 return (0); 1062 } 1063 return (1); 1064 } else { 1065 /* 1066 * We ran out of extended dos partition 1067 * drives. The only hope now is to go 1068 * back to extra drives defined in the master 1069 * fdisk table. But we overwrote that table 1070 * already, so we must load it in again. 1071 */ 1072 logicalDriveCount += numDrives; 1073 brelse(*bp); 1074 *bp = bread(dev, (daddr_t)0, PC_SAFESECSIZE); 1075 if ((*bp)->b_flags & B_ERROR) { 1076 PC_DPRINTF0(1, "pc_getfattype: read error\n"); 1077 *error = EIO; 1078 return (0); 1079 } 1080 dosp_ptr = (struct mboot *)(*bp)->b_un.b_addr; 1081 bcopy(dosp_ptr->parts, dosp, 1082 sizeof (struct ipart) * FD_NUMPART); 1083 } 1084 } 1085 /* 1086 * Still haven't found the drive, is it an extra 1087 * drive defined in the main FDISK table? 1088 */ 1089 if (askedFor <= logicalDriveCount + numExtraDrives) { 1090 driveIndex = logicalDriveCount + numExtraDrives - askedFor; 1091 *sysid = dosp[extraDrives[driveIndex]].systid; 1092 *startSector = ltohi(dosp[extraDrives[driveIndex]].relsect); 1093 return (1); 1094 } 1095 /* 1096 * Still haven't found the drive, and there is 1097 * nowhere else to look. 1098 */ 1099 noLogicalDrive(askedFor); 1100 *error = EINVAL; 1101 return (0); 1102 } 1103 1104 /* 1105 * FAT12/FAT16 specific consistency checks. 1106 */ 1107 static int 1108 check_bpb_fat16(struct bootsec *bpb) 1109 { 1110 if (pcfsdebuglevel >= 5) { 1111 PC_DPRINTF1(5, "check_bpb_fat: RootEntCount = %d", 1112 ltohs(bpb->rdirents[0])); 1113 PC_DPRINTF1(5, "check_bpb_fat16: TotSec16 = %d", 1114 ltohs(bpb->numsect[0])); 1115 PC_DPRINTF1(5, "check_bpb_fat16: FATSz16 = %d", 1116 ltohs(bpb->fatsec)); 1117 PC_DPRINTF1(5, "check_bpb_fat16: TotSec32 = %d", 1118 ltohi(bpb->totalsec)); 1119 } 1120 return (ltohs(bpb->rdirents[0]) > 0 && /* RootEntCnt > 0 */ 1121 ((ltohs(bpb->numsect[0]) == 0 && /* TotSec16 == 0 */ 1122 ltohi(bpb->totalsec) > 0) || /* TotSec32 > 0 */ 1123 ltohs(bpb->numsect[0]) > 0) && /* TotSec16 > 0 */ 1124 ltohs(bpb->fatsec) > 0); /* FatSz16 > 0 */ 1125 } 1126 1127 /* 1128 * FAT32 specific consistency checks. 1129 */ 1130 static int 1131 check_bpb_fat32(struct fat32_bootsec *bpb) 1132 { 1133 if (pcfsdebuglevel >= 5) { 1134 PC_DPRINTF1(5, "check_bpb_fat32: RootEntCount = %d", 1135 ltohs(bpb->f_bs.rdirents[0])); 1136 PC_DPRINTF1(5, "check_bpb_fat32: TotSec16 = %d", 1137 ltohs(bpb->f_bs.numsect[0])); 1138 PC_DPRINTF1(5, "check_bpb_fat32: FATSz16 = %d", 1139 ltohs(bpb->f_bs.fatsec)); 1140 PC_DPRINTF1(5, "check_bpb_fat32: TotSec32 = %d", 1141 ltohi(bpb->f_bs.totalsec)); 1142 PC_DPRINTF1(5, "check_bpb_fat32: FATSz32 = %d", 1143 ltohi(bpb->f_fatlength)); 1144 } 1145 return (ltohs(bpb->f_bs.rdirents[0]) == 0 && 1146 ltohs(bpb->f_bs.numsect[0]) == 0 && 1147 ltohs(bpb->f_bs.fatsec) == 0 && 1148 ltohi(bpb->f_bs.totalsec) > 0 && 1149 ltohi(bpb->f_fatlength) > 0); 1150 } 1151 1152 /* 1153 * Calculate the number of clusters in order to determine 1154 * the type of FAT we are looking at. This is the only 1155 * recommended way of determining FAT type, though there 1156 * are other hints in the data, this is the best way. 1157 */ 1158 static ulong_t 1159 bpb_to_numclusters(uchar_t *cp) 1160 { 1161 struct fat32_bootsec *bpb; 1162 1163 ulong_t rootdirsectors; 1164 ulong_t FATsz; 1165 ulong_t TotSec; 1166 ulong_t DataSec; 1167 ulong_t CountOfClusters; 1168 char FileSysType[9]; 1169 1170 /* 1171 * Cast it to FAT32 bpb. If it turns out to be FAT12/16, its 1172 * OK, we won't try accessing the data beyond the FAT16 header 1173 * boundary. 1174 */ 1175 bpb = (struct fat32_bootsec *)cp; 1176 1177 if (pcfsdebuglevel >= 5) { 1178 if (ltohs(bpb->f_bs.rdirents[0]) != 0) { 1179 (void) memcpy(FileSysType, &cp[54], 8); 1180 FileSysType[8] = 0; 1181 PC_DPRINTF1(5, "debug_bpb: FAT12/FAT16 FileSysType = " 1182 "%s", FileSysType); 1183 } 1184 } 1185 1186 rootdirsectors = ((ltohs(bpb->f_bs.rdirents[0]) * 32) + 1187 (ltohs(bpb->f_bs.bps[0]) - 1)) / ltohs(bpb->f_bs.bps[0]); 1188 1189 if (ltohs(bpb->f_bs.fatsec) != 0) 1190 FATsz = ltohs(bpb->f_bs.fatsec); 1191 else 1192 FATsz = ltohi(bpb->f_fatlength); 1193 1194 if (ltohs(bpb->f_bs.numsect[0]) != 0) 1195 TotSec = ltohs(bpb->f_bs.numsect[0]); 1196 else 1197 TotSec = ltohi(bpb->f_bs.totalsec); 1198 1199 DataSec = TotSec - (ltohs(bpb->f_bs.res_sec[0]) + 1200 (bpb->f_bs.nfat * FATsz) + rootdirsectors); 1201 1202 CountOfClusters = DataSec / bpb->f_bs.spcl; 1203 1204 PC_DPRINTF1(5, "debug_bpb: CountOfClusters = %ld", CountOfClusters); 1205 1206 return (CountOfClusters); 1207 1208 } 1209 1210 static int 1211 fattype(ulong_t CountOfClusters) 1212 { 1213 /* 1214 * From Microsoft: 1215 * In the following example, when it says <, it does not mean <=. 1216 * Note also that the numbers are correct. The first number for 1217 * FAT12 is 4085; the second number for FAT16 is 65525. These numbers 1218 * and the '<' signs are not wrong. 1219 */ 1220 1221 /* Watch for edge cases */ 1222 if ((CountOfClusters >= 4085 && CountOfClusters <= 4095) || 1223 (CountOfClusters >= 65525 && CountOfClusters <= 65535)) { 1224 PC_DPRINTF1(5, "debug_bpb: Cannot determine FAT yet - %ld", 1225 CountOfClusters); 1226 return (-1); /* Cannot be determined yet */ 1227 } else if (CountOfClusters < 4085) { 1228 /* Volume is FAT12 */ 1229 PC_DPRINTF0(5, "debug_bpb: This must be FAT12"); 1230 return (0); 1231 } else if (CountOfClusters < 65525) { 1232 /* Volume is FAT16 */ 1233 PC_DPRINTF0(5, "debug_bpb: This must be FAT16"); 1234 return (PCFS_FAT16); 1235 } else { 1236 /* Volume is FAT32 */ 1237 PC_DPRINTF0(5, "debug_bpb: This must be FAT32"); 1238 return (PCFS_FAT32); 1239 } 1240 } 1241 1242 #define VALID_SECSIZE(s) (s == 512 || s == 1024 || s == 2048 || s == 4096) 1243 1244 #define VALID_SPCL(s) (s == 1 || s == 2 || s == 4 || s == 8 || s == 16 ||\ 1245 s == 32 || s == 64 || s == 128) 1246 1247 static int 1248 secondaryBPBChecks(uchar_t *cp) 1249 { 1250 struct bootsec *bpb = (struct bootsec *)cp; 1251 struct fat32_bootsec *f32bpb = (struct fat32_bootsec *)cp; 1252 1253 /* 1254 * Perform secondary checks to try and determine what sort 1255 * of FAT partition we have based on other, less reliable, 1256 * data in the BPB header. 1257 */ 1258 if (ltohs(bpb->fatsec) != 0) { 1259 /* 1260 * Must be FAT12 or FAT16, check the 1261 * FilSysType string (not 100% reliable). 1262 */ 1263 if (!memcmp((cp + PCFS_TYPESTRING_OFFSET16), "FAT12", 5)) { 1264 PC_DPRINTF0(5, "secondaryBPBCheck says: FAT12"); 1265 return (0); /* FAT12 */ 1266 } else if (!memcmp((cp + PCFS_TYPESTRING_OFFSET16), "FAT16", 1267 5)) { 1268 PC_DPRINTF0(5, "secondaryBPBCheck says: FAT16"); 1269 return (PCFS_FAT16); 1270 } else { 1271 /* 1272 * Try to use the BPB_Media byte 1273 * 1274 * If the media byte indicates a floppy we'll 1275 * assume FAT12, otherwise we'll assume FAT16. 1276 */ 1277 switch (bpb->mediadesriptor) { 1278 case SS8SPT: 1279 case DS8SPT: 1280 case SS9SPT: 1281 case DS9SPT: 1282 case DS18SPT: 1283 case DS9_15SPT: 1284 PC_DPRINTF0(5, 1285 "secondaryBPBCheck says: FAT12"); 1286 return (0); /* FAT12 */ 1287 case MD_FIXED: 1288 PC_DPRINTF0(5, 1289 "secondaryBPBCheck says: FAT16"); 1290 return (PCFS_FAT16); 1291 default: 1292 cmn_err(CE_NOTE, 1293 "!pcfs: unknown FAT type"); 1294 return (-1); 1295 } 1296 } 1297 } else if (ltohi(f32bpb->f_fatlength) > 0) { 1298 PC_DPRINTF0(5, "secondaryBPBCheck says: FAT32"); 1299 return (PCFS_FAT32); 1300 } else { 1301 /* We don't know */ 1302 PC_DPRINTF0(5, "secondaryBPBCheck says: unknown!!"); 1303 return (-1); 1304 } 1305 } 1306 1307 /* 1308 * Check to see if the BPB we found is correct. 1309 * 1310 * First, look for obvious, tell-tale signs of trouble: 1311 * The NumFATs value should always be 2. Sometimes it can be a '1' 1312 * on FLASH memory cards and other non-disk-based media, so we 1313 * will allow that as well. 1314 * 1315 * We also look at the Media byte, the valid range is 0xF0, or 1316 * 0xF8 thru 0xFF, anything else means this is probably not a good 1317 * BPB. 1318 * 1319 * Finally, check the BPB Magic number at the end of the 512 byte 1320 * block, it must be 0xAA55. 1321 * 1322 * If that all is good, calculate the number of clusters and 1323 * do some final verification steps. 1324 * 1325 * If all is well, return success (1) and set the fattypep 1326 * value to the correct FAT value. 1327 */ 1328 static int 1329 isBPB(uchar_t *cp, int *fattypep) 1330 { 1331 struct bootsec *bpb = (struct bootsec *)cp; 1332 1333 uint_t numclusters; /* number of clusters in file area */ 1334 ushort_t secsize = (int)ltohs(bpb->bps[0]); 1335 1336 if (pcfsdebuglevel >= 3) { 1337 if (!VALID_SECSIZE(secsize)) 1338 PC_DPRINTF1(3, "check_bpb: invalid bps value %d", 1339 secsize); 1340 1341 if (!VALID_SPCL(bpb->spcl)) 1342 PC_DPRINTF1(3, "check_bpb: invalid spcl value %d", 1343 bpb->spcl); 1344 1345 if ((secsize * bpb->spcl) >= (32 * 1024)) 1346 PC_DPRINTF3(3, "check_bpb: BPC > 32K %d x %d = %d", 1347 secsize, 1348 bpb->spcl, 1349 secsize * bpb->spcl); 1350 1351 if (bpb->nfat == 0) 1352 PC_DPRINTF1(3, "check_bpb: bad NumFATs value %d", 1353 bpb->nfat); 1354 1355 if (ltohs(bpb->res_sec[0]) == 0) 1356 PC_DPRINTF1(3, "check_bpb: bad RsvdSecCnt value %d", 1357 ltohs(bpb->res_sec[0])); 1358 1359 PC_DPRINTF1(5, "check_bpb: Media byte = %02x", 1360 bpb->mediadesriptor); 1361 1362 } 1363 if ((bpb->nfat == 0) || 1364 (bpb->mediadesriptor != 0xF0 && bpb->mediadesriptor < 0xF8) || 1365 (ltohs(cp[510]) != MBB_MAGIC) || 1366 !VALID_SECSIZE(secsize) || 1367 !VALID_SPCL(bpb->spcl) || 1368 (secsize * bpb->spcl >= (64 * 1024)) || 1369 !(ltohs(bpb->res_sec[0]))) 1370 return (0); 1371 1372 /* 1373 * Basic sanity checks passed so far, now try to determine which 1374 * FAT format to use. 1375 */ 1376 numclusters = bpb_to_numclusters(cp); 1377 1378 *fattypep = fattype(numclusters); 1379 1380 /* Do some final sanity checks for each specific type of FAT */ 1381 switch (*fattypep) { 1382 case 0: /* FAT12 */ 1383 case PCFS_FAT16: 1384 if (!check_bpb_fat16((struct bootsec *)cp)) 1385 return (0); 1386 break; 1387 case PCFS_FAT32: 1388 if (!check_bpb_fat32((struct fat32_bootsec *)cp)) 1389 return (0); 1390 break; 1391 default: /* not sure yet */ 1392 *fattypep = secondaryBPBChecks(cp); 1393 if (*fattypep == -1) { 1394 /* Still nothing, give it up. */ 1395 return (0); 1396 } 1397 break; 1398 } 1399 PC_DPRINTF0(5, "isBPB: BPB passes verification tests"); 1400 return (1); 1401 } 1402 1403 1404 /* 1405 * Get the FAT type for the DOS medium. 1406 * 1407 * ------------------------- 1408 * According to Microsoft: 1409 * The FAT type one of FAT12, FAT16, or FAT32 is determined by the 1410 * count of clusters on the volume and nothing else. 1411 * ------------------------- 1412 * 1413 */ 1414 static int 1415 pc_getfattype( 1416 struct vnode *devvp, 1417 int ldrive, 1418 daddr_t *strtsectp, 1419 int *fattypep) 1420 { 1421 uchar_t *cp; /* for searching out FAT string */ 1422 buf_t *bp = NULL; /* Disk buffer pointer */ 1423 int rval = 0; 1424 uchar_t sysid = 0; /* System ID character */ 1425 dev_t dev = devvp->v_rdev; 1426 1427 *strtsectp = (daddr_t)0; 1428 1429 /* 1430 * Open the device so we can check out the BPB or FDISK table, 1431 * then read in the sector. 1432 */ 1433 PC_DPRINTF2(5, "pc_getfattype: dev=%x ldrive=%x ", (int)dev, ldrive); 1434 if (rval = VOP_OPEN(&devvp, FREAD, CRED())) { 1435 PC_DPRINTF1(1, "pc_getfattype: open error=%d\n", rval); 1436 return (rval); 1437 } 1438 1439 /* 1440 * Read block 0 from device 1441 */ 1442 bp = bread(dev, (daddr_t)0, PC_SAFESECSIZE); 1443 if (bp->b_flags & B_ERROR) { 1444 PC_DPRINTF0(1, "pc_getfattype: read error\n"); 1445 rval = EIO; 1446 goto out; 1447 } 1448 1449 cp = (uchar_t *)bp->b_un.b_addr; 1450 1451 /* 1452 * If the first block is not a valid BPB, look for the 1453 * through the FDISK table. 1454 */ 1455 if (!isBPB(cp, fattypep)) { 1456 /* find the partition table and get 512 bytes from it. */ 1457 PC_DPRINTF0(5, "pc_getfattype: using FDISK table to find BPB"); 1458 1459 if (findTheDrive(dev, ldrive, &rval, &bp, 1460 strtsectp, &sysid) == 0) 1461 goto out; 1462 1463 brelse(bp); 1464 bp = bread(dev, *strtsectp, PC_SAFESECSIZE); 1465 if (bp->b_flags & B_ERROR) { 1466 PC_DPRINTF0(1, "pc_getfattype: read error\n"); 1467 rval = EIO; 1468 goto out; 1469 } 1470 cp = (uchar_t *)bp->b_un.b_addr; 1471 1472 /* If this one is still no good, give it up. */ 1473 if (!isBPB(cp, fattypep)) { 1474 rval = EIO; 1475 goto out; 1476 } 1477 } 1478 1479 out: 1480 /* 1481 * Release the buffer used 1482 */ 1483 if (bp != NULL) 1484 brelse(bp); 1485 (void) VOP_CLOSE(devvp, FREAD, 1, (offset_t)0, CRED()); 1486 return (rval); 1487 } 1488 1489 1490 /* 1491 * Get the boot parameter block and file allocation table. 1492 * If there is an old FAT, invalidate it. 1493 */ 1494 int 1495 pc_getfat(struct pcfs *fsp) 1496 { 1497 struct vfs *vfsp = PCFSTOVFS(fsp); 1498 struct buf *tp = 0; 1499 struct buf *bp = 0; 1500 uchar_t *fatp = NULL; 1501 uchar_t *fat_changemap = NULL; 1502 struct bootsec *bootp; 1503 struct fat32_bootsec *f32b; 1504 struct vnode *devvp; 1505 int error; 1506 int fatsize; 1507 int fat_changemapsize; 1508 int flags = 0; 1509 int nfat; 1510 int secsize; 1511 int fatsec; 1512 1513 PC_DPRINTF0(5, "pc_getfat\n"); 1514 devvp = fsp->pcfs_devvp; 1515 if (fsp->pcfs_fatp) { 1516 /* 1517 * There is a FAT in core. 1518 * If there are open file pcnodes or we have modified it or 1519 * it hasn't timed out yet use the in core FAT. 1520 * Otherwise invalidate it and get a new one 1521 */ 1522 #ifdef notdef 1523 if (fsp->pcfs_frefs || 1524 (fsp->pcfs_flags & PCFS_FATMOD) || 1525 (gethrestime_sec() < fsp->pcfs_fattime)) { 1526 return (0); 1527 } else { 1528 mutex_enter(&pcfslock); 1529 pc_invalfat(fsp); 1530 mutex_exit(&pcfslock); 1531 } 1532 #endif /* notdef */ 1533 return (0); 1534 } 1535 /* 1536 * Open block device mounted on. 1537 */ 1538 error = VOP_OPEN(&devvp, 1539 (vfsp->vfs_flag & VFS_RDONLY) ? FREAD : FREAD|FWRITE, 1540 CRED()); 1541 if (error) { 1542 PC_DPRINTF1(1, "pc_getfat: open error=%d\n", error); 1543 return (error); 1544 } 1545 /* 1546 * Get boot parameter block and check it for validity 1547 */ 1548 tp = bread(fsp->pcfs_xdev, fsp->pcfs_dosstart, PC_SAFESECSIZE); 1549 if (tp->b_flags & (B_ERROR | B_STALE)) { 1550 PC_DPRINTF0(1, "pc_getfat: boot block error\n"); 1551 flags = tp->b_flags & B_ERROR; 1552 error = EIO; 1553 goto out; 1554 } 1555 tp->b_flags |= B_STALE | B_AGE; 1556 bootp = (struct bootsec *)tp->b_un.b_addr; 1557 1558 1559 /* get the sector size - may be more than 512 bytes */ 1560 secsize = (int)ltohs(bootp->bps[0]); 1561 /* check for bogus sector size - fat should be at least 1 sector */ 1562 if (IS_FAT32(fsp)) { 1563 f32b = (struct fat32_bootsec *)bootp; 1564 fatsec = ltohi(f32b->f_fatlength); 1565 } else { 1566 fatsec = ltohs(bootp->fatsec); 1567 } 1568 if (secsize < 512 || fatsec < 1 || bootp->nfat < 1) { 1569 cmn_err(CE_NOTE, "!pcfs: FAT size error"); 1570 error = EINVAL; 1571 goto out; 1572 } 1573 1574 switch (bootp->mediadesriptor) { 1575 default: 1576 cmn_err(CE_NOTE, "!pcfs: media-descriptor error, 0x%x", 1577 bootp->mediadesriptor); 1578 error = EINVAL; 1579 goto out; 1580 1581 case MD_FIXED: 1582 /* 1583 * PCMCIA pseudo floppy is type MD_FIXED, 1584 * but is accessed like a floppy 1585 */ 1586 if (!(fsp->pcfs_flags & PCFS_PCMCIA_NO_CIS)) { 1587 fsp->pcfs_flags |= PCFS_NOCHK; 1588 } 1589 /* FALLTHRU */ 1590 case SS8SPT: 1591 case DS8SPT: 1592 case SS9SPT: 1593 case DS9SPT: 1594 case DS18SPT: 1595 case DS9_15SPT: 1596 fsp->pcfs_secsize = secsize; 1597 fsp->pcfs_sdshift = secsize / DEV_BSIZE - 1; 1598 fsp->pcfs_entps = secsize / sizeof (struct pcdir); 1599 fsp->pcfs_spcl = (int)bootp->spcl; 1600 fsp->pcfs_fatsec = fatsec; 1601 fsp->pcfs_spt = (int)ltohs(bootp->spt); 1602 fsp->pcfs_rdirsec = (int)ltohs(bootp->rdirents[0]) 1603 * sizeof (struct pcdir) / secsize; 1604 fsp->pcfs_clsize = fsp->pcfs_spcl * secsize; 1605 fsp->pcfs_fatstart = fsp->pcfs_dosstart + 1606 (daddr_t)ltohs(bootp->res_sec[0]); 1607 fsp->pcfs_rdirstart = fsp->pcfs_fatstart + 1608 (bootp->nfat * fsp->pcfs_fatsec); 1609 fsp->pcfs_datastart = fsp->pcfs_rdirstart + fsp->pcfs_rdirsec; 1610 if (IS_FAT32(fsp)) 1611 fsp->pcfs_rdirstart = ltohi(f32b->f_rootcluster); 1612 fsp->pcfs_ncluster = (((int)(ltohs(bootp->numsect[0]) ? 1613 ltohs(bootp->numsect[0]) : ltohi(bootp->totalsec))) - 1614 fsp->pcfs_datastart + fsp->pcfs_dosstart) / fsp->pcfs_spcl; 1615 fsp->pcfs_numfat = (int)bootp->nfat; 1616 fsp->pcfs_nxfrecls = PCF_FIRSTCLUSTER; 1617 break; 1618 } 1619 1620 /* 1621 * Get FAT and check it for validity 1622 */ 1623 fatsize = fsp->pcfs_fatsec * fsp->pcfs_secsize; 1624 fatp = kmem_alloc(fatsize, KM_SLEEP); 1625 error = pc_readfat(fsp, fatp, fsp->pcfs_fatstart, fatsize); 1626 if (error) { 1627 flags = B_ERROR; 1628 goto out; 1629 } 1630 fat_changemapsize = (fatsize / fsp->pcfs_clsize) + 1; 1631 fat_changemap = kmem_zalloc(fat_changemapsize, KM_SLEEP); 1632 1633 /* 1634 * The only definite signature check is that the 1635 * media descriptor byte should match the first byte 1636 * of the FAT block. 1637 */ 1638 if (fatp[0] != bootp->mediadesriptor) { 1639 cmn_err(CE_NOTE, "!pcfs: FAT signature error"); 1640 error = EINVAL; 1641 goto out; 1642 } 1643 /* 1644 * Checking for fatsec and number of supported clusters, should 1645 * actually determine a FAT12/FAT media. 1646 */ 1647 if (fsp->pcfs_flags & PCFS_FAT16) { 1648 if ((fsp->pcfs_fatsec <= 12) && 1649 ((fatsize * 2 / 3) >= fsp->pcfs_ncluster)) { 1650 /* 1651 * We have a 12-bit FAT, rather than a 16-bit FAT. 1652 * Ignore what the fdisk table says. 1653 */ 1654 PC_DPRINTF0(2, "pc_getfattype: forcing 12-bit FAT\n"); 1655 fsp->pcfs_flags &= ~PCFS_FAT16; 1656 } 1657 } 1658 /* 1659 * Sanity check our FAT is large enough for the 1660 * clusters we think we have. 1661 */ 1662 if ((fsp->pcfs_flags & PCFS_FAT16) && 1663 ((fatsize / 2) < fsp->pcfs_ncluster)) { 1664 cmn_err(CE_NOTE, "!pcfs: FAT too small for number of clusters"); 1665 error = EINVAL; 1666 goto out; 1667 } 1668 1669 /* 1670 * Get alternate FATs and check for consistency 1671 * This is an inlined version of pc_readfat(). 1672 * Since we're only comparing FAT and alternate FAT, 1673 * there's no reason to let pc_readfat() copy data out 1674 * of the buf. Instead, compare in-situ, one cluster 1675 * at a time. 1676 */ 1677 for (nfat = 1; nfat < fsp->pcfs_numfat; nfat++) { 1678 size_t startsec; 1679 size_t off; 1680 1681 startsec = fsp->pcfs_fatstart + nfat * fsp->pcfs_fatsec; 1682 1683 for (off = 0; off < fatsize; off += fsp->pcfs_clsize) { 1684 bp = bread(fsp->pcfs_xdev, pc_dbdaddr(fsp, 1685 startsec + 1686 pc_cltodb(fsp, pc_lblkno(fsp, off))), 1687 MIN(fsp->pcfs_clsize, fatsize - off)); 1688 if (bp->b_flags & (B_ERROR | B_STALE)) { 1689 cmn_err(CE_NOTE, 1690 "!pcfs: alternate FAT #%d read error" 1691 " at byte %ld", nfat, off); 1692 flags = B_ERROR; 1693 error = EIO; 1694 goto out; 1695 } 1696 bp->b_flags |= B_STALE | B_AGE; 1697 if (bcmp(bp->b_un.b_addr, 1698 fatp + off, 1699 MIN(fsp->pcfs_clsize, fatsize - off))) { 1700 cmn_err(CE_NOTE, 1701 "!pcfs: alternate FAT #%d corrupted" 1702 " at byte %ld", nfat, off); 1703 flags = B_ERROR; 1704 } 1705 brelse(bp); 1706 bp = NULL; /* prevent double release */ 1707 } 1708 } 1709 1710 fsp->pcfs_fatsize = fatsize; 1711 fsp->pcfs_fatp = fatp; 1712 fsp->pcfs_fat_changemapsize = fat_changemapsize; 1713 fsp->pcfs_fat_changemap = fat_changemap; 1714 fsp->pcfs_fattime = gethrestime_sec() + PCFS_DISKTIMEOUT; 1715 fsp->pcfs_fatjustread = 1; 1716 1717 brelse(tp); 1718 tp = NULL; 1719 if (IS_FAT32(fsp)) { 1720 /* get fsinfo */ 1721 struct fat32_boot_fsinfo fsinfo_disk; 1722 1723 fsp->f32fsinfo_sector = ltohs(f32b->f_infosector); 1724 tp = bread(fsp->pcfs_xdev, 1725 fsp->pcfs_dosstart + pc_dbdaddr(fsp, fsp->f32fsinfo_sector), 1726 PC_SAFESECSIZE); 1727 if (tp->b_flags & (B_ERROR | B_STALE)) { 1728 cmn_err(CE_NOTE, "!pcfs: error reading fat32 fsinfo"); 1729 flags = tp->b_flags & B_ERROR; 1730 brelse(tp); 1731 tp = NULL; 1732 error = EIO; 1733 goto out; 1734 } 1735 tp->b_flags |= B_STALE | B_AGE; 1736 bcopy((void *)(tp->b_un.b_addr + FAT32_BOOT_FSINFO_OFF), 1737 &fsinfo_disk, sizeof (struct fat32_boot_fsinfo)); 1738 brelse(tp); 1739 tp = NULL; 1740 1741 /* translated fields */ 1742 fsp->fsinfo_native.fs_signature = 1743 ltohi(fsinfo_disk.fs_signature); 1744 fsp->fsinfo_native.fs_free_clusters = 1745 ltohi(fsinfo_disk.fs_free_clusters); 1746 if (fsp->fsinfo_native.fs_signature != FAT32_FS_SIGN) { 1747 cmn_err(CE_NOTE, 1748 "!pcfs: fat32 fsinfo signature mismatch."); 1749 error = EINVAL; 1750 goto out; 1751 } 1752 } 1753 1754 return (0); 1755 1756 out: 1757 cmn_err(CE_NOTE, "!pcfs: illegal disk format"); 1758 if (tp) 1759 brelse(tp); 1760 if (bp) 1761 brelse(bp); 1762 if (fatp) 1763 kmem_free(fatp, fatsize); 1764 if (fat_changemap) 1765 kmem_free(fat_changemap, fat_changemapsize); 1766 1767 if (flags) { 1768 pc_mark_irrecov(fsp); 1769 } 1770 (void) VOP_CLOSE(devvp, (vfsp->vfs_flag & VFS_RDONLY) ? 1771 FREAD : FREAD|FWRITE, 1, (offset_t)0, CRED()); 1772 return (error); 1773 } 1774 1775 int 1776 pc_syncfat(struct pcfs *fsp) 1777 { 1778 struct buf *bp; 1779 int nfat; 1780 int error; 1781 struct fat32_boot_fsinfo fsinfo_disk; 1782 1783 PC_DPRINTF0(7, "pcfs_syncfat\n"); 1784 if ((fsp->pcfs_fatp == (uchar_t *)0) || 1785 !(fsp->pcfs_flags & PCFS_FATMOD)) 1786 return (0); 1787 /* 1788 * write out all copies of FATs 1789 */ 1790 fsp->pcfs_flags &= ~PCFS_FATMOD; 1791 fsp->pcfs_fattime = gethrestime_sec() + PCFS_DISKTIMEOUT; 1792 for (nfat = 0; nfat < fsp->pcfs_numfat; nfat++) { 1793 error = pc_writefat(fsp, 1794 fsp->pcfs_fatstart + nfat*fsp->pcfs_fatsec); 1795 if (error) { 1796 pc_mark_irrecov(fsp); 1797 return (EIO); 1798 } 1799 } 1800 pc_clear_fatchanges(fsp); 1801 PC_DPRINTF0(6, "pcfs_syncfat: wrote out FAT\n"); 1802 /* write out fsinfo */ 1803 if (IS_FAT32(fsp)) { 1804 bp = bread(fsp->pcfs_xdev, 1805 fsp->pcfs_dosstart + pc_dbdaddr(fsp, fsp->f32fsinfo_sector), 1806 PC_SAFESECSIZE); 1807 if (bp->b_flags & (B_ERROR | B_STALE)) { 1808 brelse(bp); 1809 return (EIO); 1810 } 1811 bcopy((void *)(bp->b_un.b_addr + FAT32_BOOT_FSINFO_OFF), 1812 &fsinfo_disk, sizeof (struct fat32_boot_fsinfo)); 1813 /* translate fields */ 1814 fsinfo_disk.fs_free_clusters = 1815 htoli(fsp->fsinfo_native.fs_free_clusters); 1816 fsinfo_disk.fs_next_cluster = (uint32_t)FSINFO_UNKNOWN; 1817 bcopy(&fsinfo_disk, 1818 (void *)(bp->b_un.b_addr + FAT32_BOOT_FSINFO_OFF), 1819 sizeof (struct fat32_boot_fsinfo)); 1820 bwrite2(bp); 1821 error = geterror(bp); 1822 brelse(bp); 1823 if (error) { 1824 pc_mark_irrecov(fsp); 1825 return (EIO); 1826 } 1827 } 1828 return (0); 1829 } 1830 1831 void 1832 pc_invalfat(struct pcfs *fsp) 1833 { 1834 struct pcfs *xfsp; 1835 int mount_cnt = 0; 1836 1837 PC_DPRINTF0(7, "pc_invalfat\n"); 1838 if (fsp->pcfs_fatp == (uchar_t *)0) 1839 panic("pc_invalfat"); 1840 /* 1841 * Release FAT 1842 */ 1843 kmem_free(fsp->pcfs_fatp, fsp->pcfs_fatsize); 1844 fsp->pcfs_fatp = NULL; 1845 kmem_free(fsp->pcfs_fat_changemap, fsp->pcfs_fat_changemapsize); 1846 fsp->pcfs_fat_changemap = NULL; 1847 /* 1848 * Invalidate all the blocks associated with the device. 1849 * Not needed if stateless. 1850 */ 1851 for (xfsp = pc_mounttab; xfsp; xfsp = xfsp->pcfs_nxt) 1852 if (xfsp != fsp && xfsp->pcfs_xdev == fsp->pcfs_xdev) 1853 mount_cnt++; 1854 1855 if (!mount_cnt) 1856 binval(fsp->pcfs_xdev); 1857 /* 1858 * close mounted device 1859 */ 1860 (void) VOP_CLOSE(fsp->pcfs_devvp, 1861 (PCFSTOVFS(fsp)->vfs_flag & VFS_RDONLY) ? FREAD : FREAD|FWRITE, 1862 1, (offset_t)0, CRED()); 1863 } 1864 1865 void 1866 pc_badfs(struct pcfs *fsp) 1867 { 1868 cmn_err(CE_WARN, "corrupted PC file system on dev %x.%x\n", 1869 getmajor(fsp->pcfs_devvp->v_rdev), 1870 getminor(fsp->pcfs_devvp->v_rdev)); 1871 } 1872 1873 /* 1874 * The problem with supporting NFS on the PCFS filesystem is that there 1875 * is no good place to keep the generation number. The only possible 1876 * place is inside a directory entry. There are a few words that we 1877 * don't use - they store NT & OS/2 attributes, and the creation/last access 1878 * time of the file - but it seems wrong to use them. In addition, directory 1879 * entries come and go. If a directory is removed completely, its directory 1880 * blocks are freed and the generation numbers are lost. Whereas in ufs, 1881 * inode blocks are dedicated for inodes, so the generation numbers are 1882 * permanently kept on the disk. 1883 */ 1884 static int 1885 pcfs_vget(struct vfs *vfsp, struct vnode **vpp, struct fid *fidp) 1886 { 1887 struct pcnode *pcp; 1888 struct pc_fid *pcfid; 1889 struct pcfs *fsp; 1890 struct pcdir *ep; 1891 daddr_t eblkno; 1892 int eoffset; 1893 struct buf *bp; 1894 int error; 1895 pc_cluster32_t cn; 1896 1897 pcfid = (struct pc_fid *)fidp; 1898 fsp = VFSTOPCFS(vfsp); 1899 1900 error = pc_lockfs(fsp, 0, 0); 1901 if (error) { 1902 *vpp = NULL; 1903 return (error); 1904 } 1905 1906 if (pcfid->pcfid_block == 0) { 1907 pcp = pc_getnode(fsp, (daddr_t)0, 0, (struct pcdir *)0); 1908 pcp->pc_flags |= PC_EXTERNAL; 1909 *vpp = PCTOV(pcp); 1910 pc_unlockfs(fsp); 1911 return (0); 1912 } 1913 eblkno = pcfid->pcfid_block; 1914 eoffset = pcfid->pcfid_offset; 1915 if ((pc_dbtocl(fsp, 1916 eblkno - fsp->pcfs_dosstart) >= fsp->pcfs_ncluster) || 1917 (eoffset > fsp->pcfs_clsize)) { 1918 pc_unlockfs(fsp); 1919 *vpp = NULL; 1920 return (EINVAL); 1921 } 1922 1923 if (eblkno >= fsp->pcfs_datastart || (eblkno-fsp->pcfs_rdirstart) 1924 < (fsp->pcfs_rdirsec & ~(fsp->pcfs_spcl - 1))) { 1925 bp = bread(fsp->pcfs_xdev, eblkno, fsp->pcfs_clsize); 1926 } else { 1927 bp = bread(fsp->pcfs_xdev, eblkno, 1928 (int)(fsp->pcfs_datastart - eblkno) * fsp->pcfs_secsize); 1929 } 1930 if (bp->b_flags & (B_ERROR | B_STALE)) { 1931 error = geterror(bp); 1932 brelse(bp); 1933 if (error) 1934 pc_mark_irrecov(fsp); 1935 *vpp = NULL; 1936 pc_unlockfs(fsp); 1937 return (error); 1938 } 1939 ep = (struct pcdir *)(bp->b_un.b_addr + eoffset); 1940 /* 1941 * Ok, if this is a valid file handle that we gave out, 1942 * then simply ensuring that the creation time matches, 1943 * the entry has not been deleted, and it has a valid first 1944 * character should be enough. 1945 * 1946 * Unfortunately, verifying that the <blkno, offset> _still_ 1947 * refers to a directory entry is not easy, since we'd have 1948 * to search _all_ directories starting from root to find it. 1949 * That's a high price to pay just in case somebody is forging 1950 * file handles. So instead we verify that as much of the 1951 * entry is valid as we can: 1952 * 1953 * 1. The starting cluster is 0 (unallocated) or valid 1954 * 2. It is not an LFN entry 1955 * 3. It is not hidden (unless mounted as such) 1956 * 4. It is not the label 1957 */ 1958 cn = pc_getstartcluster(fsp, ep); 1959 /* 1960 * if the starting cluster is valid, but not valid according 1961 * to pc_validcl(), force it to be to simplify the following if. 1962 */ 1963 if (cn == 0) 1964 cn = PCF_FIRSTCLUSTER; 1965 if (IS_FAT32(fsp)) { 1966 if (cn >= PCF_LASTCLUSTER32) 1967 cn = PCF_FIRSTCLUSTER; 1968 } else { 1969 if (cn >= PCF_LASTCLUSTER) 1970 cn = PCF_FIRSTCLUSTER; 1971 } 1972 if ((!pc_validcl(fsp, cn)) || 1973 (PCDL_IS_LFN(ep)) || 1974 (PCA_IS_HIDDEN(fsp, ep->pcd_attr)) || 1975 ((ep->pcd_attr & PCA_LABEL) == PCA_LABEL)) { 1976 bp->b_flags |= B_STALE | B_AGE; 1977 brelse(bp); 1978 pc_unlockfs(fsp); 1979 return (EINVAL); 1980 } 1981 if ((ep->pcd_crtime.pct_time == pcfid->pcfid_ctime) && 1982 (ep->pcd_filename[0] != PCD_ERASED) && 1983 (pc_validchar(ep->pcd_filename[0]) || 1984 (ep->pcd_filename[0] == '.' && ep->pcd_filename[1] == '.'))) { 1985 pcp = pc_getnode(fsp, eblkno, eoffset, ep); 1986 pcp->pc_flags |= PC_EXTERNAL; 1987 *vpp = PCTOV(pcp); 1988 } else { 1989 *vpp = NULL; 1990 } 1991 bp->b_flags |= B_STALE | B_AGE; 1992 brelse(bp); 1993 pc_unlockfs(fsp); 1994 return (0); 1995 } 1996 1997 /* 1998 * if device is a PCMCIA pseudo floppy, return 1 1999 * otherwise, return 0 2000 */ 2001 static int 2002 pcfs_pseudo_floppy(dev_t rdev) 2003 { 2004 int error, err; 2005 struct dk_cinfo info; 2006 ldi_handle_t lh; 2007 ldi_ident_t li; 2008 2009 err = ldi_ident_from_mod(&modlinkage, &li); 2010 if (err) { 2011 PC_DPRINTF1(1, 2012 "pcfs_pseudo_floppy: ldi_ident_from_mod err=%d\n", err); 2013 return (0); 2014 } 2015 2016 err = ldi_open_by_dev(&rdev, OTYP_CHR, FREAD, CRED(), &lh, li); 2017 ldi_ident_release(li); 2018 if (err) { 2019 PC_DPRINTF1(1, 2020 "pcfs_pseudo_floppy: ldi_open err=%d\n", err); 2021 return (0); 2022 } 2023 2024 /* return value stored in err is purposfully ignored */ 2025 error = ldi_ioctl(lh, DKIOCINFO, (intptr_t)&info, FKIOCTL, 2026 CRED(), &err); 2027 2028 err = ldi_close(lh, FREAD, CRED()); 2029 if (err != 0) { 2030 PC_DPRINTF1(1, 2031 "pcfs_pseudo_floppy: ldi_close err=%d\n", err); 2032 return (0); 2033 } 2034 2035 if ((error == 0) && (info.dki_ctype == DKC_PCMCIA_MEM) && 2036 (info.dki_flags & DKI_PCMCIA_PFD)) 2037 return (1); 2038 else 2039 return (0); 2040 } 2041 2042 /* 2043 * Unfortunately, FAT32 fat's can be pretty big (On a 1 gig jaz drive, about 2044 * a meg), so we can't bread() it all in at once. This routine reads a 2045 * fat a chunk at a time. 2046 */ 2047 static int 2048 pc_readfat(struct pcfs *fsp, uchar_t *fatp, daddr_t start, size_t fatsize) 2049 { 2050 struct buf *bp; 2051 size_t off; 2052 size_t readsize; 2053 2054 readsize = fsp->pcfs_clsize; 2055 for (off = 0; off < fatsize; off += readsize, fatp += readsize) { 2056 if (readsize > (fatsize - off)) 2057 readsize = fatsize - off; 2058 bp = bread(fsp->pcfs_xdev, 2059 pc_dbdaddr(fsp, start + 2060 pc_cltodb(fsp, pc_lblkno(fsp, off))), 2061 readsize); 2062 if (bp->b_flags & (B_ERROR | B_STALE)) { 2063 brelse(bp); 2064 return (EIO); 2065 } 2066 bp->b_flags |= B_STALE | B_AGE; 2067 bcopy(bp->b_un.b_addr, fatp, readsize); 2068 brelse(bp); 2069 } 2070 return (0); 2071 } 2072 2073 /* 2074 * We write the FAT out a _lot_, in order to make sure that it 2075 * is up-to-date. But on a FAT32 system (large drive, small clusters) 2076 * the FAT might be a couple of megabytes, and writing it all out just 2077 * because we created or deleted a small file is painful (especially 2078 * since we do it for each alternate FAT too). So instead, for FAT16 and 2079 * FAT32 we only write out the bit that has changed. We don't clear 2080 * the 'updated' fields here because the caller might be writing out 2081 * several FATs, so the caller must use pc_clear_fatchanges() after 2082 * all FATs have been updated. 2083 */ 2084 static int 2085 pc_writefat(struct pcfs *fsp, daddr_t start) 2086 { 2087 struct buf *bp; 2088 size_t off; 2089 size_t writesize; 2090 int error; 2091 uchar_t *fatp = fsp->pcfs_fatp; 2092 size_t fatsize = fsp->pcfs_fatsize; 2093 2094 writesize = fsp->pcfs_clsize; 2095 for (off = 0; off < fatsize; off += writesize, fatp += writesize) { 2096 if (writesize > (fatsize - off)) 2097 writesize = fatsize - off; 2098 if (!pc_fat_is_changed(fsp, pc_lblkno(fsp, off))) { 2099 continue; 2100 } 2101 bp = ngeteblk(writesize); 2102 bp->b_edev = fsp->pcfs_xdev; 2103 bp->b_dev = cmpdev(bp->b_edev); 2104 bp->b_blkno = pc_dbdaddr(fsp, start + 2105 pc_cltodb(fsp, pc_lblkno(fsp, off))); 2106 bcopy(fatp, bp->b_un.b_addr, writesize); 2107 bwrite2(bp); 2108 error = geterror(bp); 2109 brelse(bp); 2110 if (error) { 2111 return (error); 2112 } 2113 } 2114 return (0); 2115 } 2116 2117 /* 2118 * Mark the FAT cluster that 'cn' is stored in as modified. 2119 */ 2120 void 2121 pc_mark_fat_updated(struct pcfs *fsp, pc_cluster32_t cn) 2122 { 2123 pc_cluster32_t bn; 2124 size_t size; 2125 2126 /* which fat block is the cluster number stored in? */ 2127 if (IS_FAT32(fsp)) { 2128 size = sizeof (pc_cluster32_t); 2129 bn = pc_lblkno(fsp, cn * size); 2130 fsp->pcfs_fat_changemap[bn] = 1; 2131 } else if (IS_FAT16(fsp)) { 2132 size = sizeof (pc_cluster16_t); 2133 bn = pc_lblkno(fsp, cn * size); 2134 fsp->pcfs_fat_changemap[bn] = 1; 2135 } else { 2136 offset_t off; 2137 pc_cluster32_t nbn; 2138 2139 ASSERT(IS_FAT12(fsp)); 2140 off = cn + (cn >> 1); 2141 bn = pc_lblkno(fsp, off); 2142 fsp->pcfs_fat_changemap[bn] = 1; 2143 /* does this field wrap into the next fat cluster? */ 2144 nbn = pc_lblkno(fsp, off + 1); 2145 if (nbn != bn) { 2146 fsp->pcfs_fat_changemap[nbn] = 1; 2147 } 2148 } 2149 } 2150 2151 /* 2152 * return whether the FAT cluster 'bn' is updated and needs to 2153 * be written out. 2154 */ 2155 int 2156 pc_fat_is_changed(struct pcfs *fsp, pc_cluster32_t bn) 2157 { 2158 return (fsp->pcfs_fat_changemap[bn] == 1); 2159 } 2160