| 1 | /* $FreeBSD: /usr/local/www/cvsroot/FreeBSD/src/sys/msdosfs/Attic/msdosfs_vfsops.c,v 1.60.2.8 2004/03/02 09:43:04 tjr Exp $ */ |
| 2 | /* $DragonFly: src/sys/vfs/msdosfs/msdosfs_vfsops.c,v 1.15 2004/05/19 22:53:05 dillon Exp $ */ |
| 3 | /* $NetBSD: msdosfs_vfsops.c,v 1.51 1997/11/17 15:36:58 ws Exp $ */ |
| 4 | |
| 5 | /*- |
| 6 | * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank. |
| 7 | * Copyright (C) 1994, 1995, 1997 TooLs GmbH. |
| 8 | * All rights reserved. |
| 9 | * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). |
| 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. All advertising materials mentioning features or use of this software |
| 20 | * must display the following acknowledgement: |
| 21 | * This product includes software developed by TooLs GmbH. |
| 22 | * 4. The name of TooLs GmbH may not be used to endorse or promote products |
| 23 | * derived from this software without specific prior written permission. |
| 24 | * |
| 25 | * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR |
| 26 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| 27 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
| 28 | * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 29 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| 30 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
| 31 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| 32 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
| 33 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
| 34 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 35 | */ |
| 36 | /* |
| 37 | * Written by Paul Popelka (paulp@uts.amdahl.com) |
| 38 | * |
| 39 | * You can do anything you want with this software, just don't say you wrote |
| 40 | * it, and don't remove this notice. |
| 41 | * |
| 42 | * This software is provided "as is". |
| 43 | * |
| 44 | * The author supplies this software to be publicly redistributed on the |
| 45 | * understanding that the author is not responsible for the correct |
| 46 | * functioning of this software in any circumstances and is not liable for |
| 47 | * any damages caused by this software. |
| 48 | * |
| 49 | * October 1992 |
| 50 | */ |
| 51 | |
| 52 | #include <sys/param.h> |
| 53 | #include <sys/systm.h> |
| 54 | #include <sys/conf.h> |
| 55 | #include <sys/proc.h> |
| 56 | #include <sys/namei.h> |
| 57 | #include <sys/kernel.h> |
| 58 | #include <sys/vnode.h> |
| 59 | #include <sys/mount.h> |
| 60 | #include <sys/buf.h> |
| 61 | #include <sys/fcntl.h> |
| 62 | #include <sys/malloc.h> |
| 63 | #include <sys/stat.h> /* defines ALLPERMS */ |
| 64 | #include <vm/vm_zone.h> |
| 65 | |
| 66 | #include "bpb.h" |
| 67 | #include "bootsect.h" |
| 68 | #include "direntry.h" |
| 69 | #include "denode.h" |
| 70 | #include "msdosfsmount.h" |
| 71 | #include "fat.h" |
| 72 | |
| 73 | #define MSDOSFS_DFLTBSIZE 4096 |
| 74 | |
| 75 | #if 1 /*def PC98*/ |
| 76 | /* |
| 77 | * XXX - The boot signature formatted by NEC PC-98 DOS looks like a |
| 78 | * garbage or a random value :-{ |
| 79 | * If you want to use that broken-signatured media, define the |
| 80 | * following symbol even though PC/AT. |
| 81 | * (ex. mount PC-98 DOS formatted FD on PC/AT) |
| 82 | */ |
| 83 | #define MSDOSFS_NOCHECKSIG |
| 84 | #endif |
| 85 | |
| 86 | MALLOC_DEFINE(M_MSDOSFSMNT, "MSDOSFS mount", "MSDOSFS mount structure"); |
| 87 | static MALLOC_DEFINE(M_MSDOSFSFAT, "MSDOSFS FAT", "MSDOSFS file allocation table"); |
| 88 | |
| 89 | static int update_mp (struct mount *mp, struct msdosfs_args *argp); |
| 90 | static int mountmsdosfs (struct vnode *devvp, struct mount *mp, |
| 91 | struct thread *td, struct msdosfs_args *argp); |
| 92 | static int msdosfs_fhtovp (struct mount *, struct fid *, |
| 93 | struct vnode **); |
| 94 | static int msdosfs_checkexp (struct mount *, struct sockaddr *, |
| 95 | int *, struct ucred **); |
| 96 | static int msdosfs_mount (struct mount *, char *, caddr_t, |
| 97 | struct nameidata *, struct thread *); |
| 98 | static int msdosfs_root (struct mount *, struct vnode **); |
| 99 | static int msdosfs_statfs (struct mount *, struct statfs *, |
| 100 | struct thread *); |
| 101 | static int msdosfs_sync (struct mount *, int, struct thread *); |
| 102 | static int msdosfs_unmount (struct mount *, int, struct thread *); |
| 103 | static int msdosfs_vptofh (struct vnode *, struct fid *); |
| 104 | |
| 105 | static int |
| 106 | update_mp(struct mount *mp, struct msdosfs_args *argp) |
| 107 | { |
| 108 | struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); |
| 109 | int error; |
| 110 | |
| 111 | pmp->pm_gid = argp->gid; |
| 112 | pmp->pm_uid = argp->uid; |
| 113 | pmp->pm_mask = argp->mask & ALLPERMS; |
| 114 | pmp->pm_flags |= argp->flags & MSDOSFSMNT_MNTOPT; |
| 115 | if (pmp->pm_flags & MSDOSFSMNT_U2WTABLE) { |
| 116 | bcopy(argp->u2w, pmp->pm_u2w, sizeof(pmp->pm_u2w)); |
| 117 | bcopy(argp->d2u, pmp->pm_d2u, sizeof(pmp->pm_d2u)); |
| 118 | bcopy(argp->u2d, pmp->pm_u2d, sizeof(pmp->pm_u2d)); |
| 119 | } |
| 120 | if (pmp->pm_flags & MSDOSFSMNT_ULTABLE) { |
| 121 | bcopy(argp->ul, pmp->pm_ul, sizeof(pmp->pm_ul)); |
| 122 | bcopy(argp->lu, pmp->pm_lu, sizeof(pmp->pm_lu)); |
| 123 | } |
| 124 | |
| 125 | #ifndef __DragonFly__ |
| 126 | /* |
| 127 | * GEMDOS knows nothing (yet) about win95 |
| 128 | */ |
| 129 | if (pmp->pm_flags & MSDOSFSMNT_GEMDOSFS) |
| 130 | pmp->pm_flags |= MSDOSFSMNT_NOWIN95; |
| 131 | #endif |
| 132 | |
| 133 | if (pmp->pm_flags & MSDOSFSMNT_NOWIN95) |
| 134 | pmp->pm_flags |= MSDOSFSMNT_SHORTNAME; |
| 135 | else if (!(pmp->pm_flags & |
| 136 | (MSDOSFSMNT_SHORTNAME | MSDOSFSMNT_LONGNAME))) { |
| 137 | struct vnode *rootvp; |
| 138 | |
| 139 | /* |
| 140 | * Try to divine whether to support Win'95 long filenames |
| 141 | */ |
| 142 | if (FAT32(pmp)) |
| 143 | pmp->pm_flags |= MSDOSFSMNT_LONGNAME; |
| 144 | else { |
| 145 | if ((error = msdosfs_root(mp, &rootvp)) != 0) |
| 146 | return error; |
| 147 | pmp->pm_flags |= findwin95(VTODE(rootvp)) |
| 148 | ? MSDOSFSMNT_LONGNAME |
| 149 | : MSDOSFSMNT_SHORTNAME; |
| 150 | vput(rootvp); |
| 151 | } |
| 152 | } |
| 153 | return 0; |
| 154 | } |
| 155 | |
| 156 | #ifndef __DragonFly__ |
| 157 | int |
| 158 | msdosfs_mountroot(void) |
| 159 | { |
| 160 | struct mount *mp; |
| 161 | struct thread *td = curthread; /* XXX */ |
| 162 | size_t size; |
| 163 | int error; |
| 164 | struct msdosfs_args args; |
| 165 | |
| 166 | if (root_device->dv_class != DV_DISK) |
| 167 | return (ENODEV); |
| 168 | |
| 169 | /* |
| 170 | * Get vnodes for swapdev and rootdev. |
| 171 | */ |
| 172 | if (bdevvp(rootdev, &rootvp)) |
| 173 | panic("msdosfs_mountroot: can't setup rootvp"); |
| 174 | |
| 175 | mp = malloc((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK); |
| 176 | bzero((char *)mp, (u_long)sizeof(struct mount)); |
| 177 | mp->mnt_op = &msdosfs_vfsops; |
| 178 | mp->mnt_flag = 0; |
| 179 | TAILQ_INIT(&mp->mnt_nvnodelist); |
| 180 | TAILQ_INIT(&mp->mnt_reservedvnlist); |
| 181 | |
| 182 | args.flags = 0; |
| 183 | args.uid = 0; |
| 184 | args.gid = 0; |
| 185 | args.mask = 0777; |
| 186 | |
| 187 | if ((error = mountmsdosfs(rootvp, mp, p, &args)) != 0) { |
| 188 | free(mp, M_MOUNT); |
| 189 | return (error); |
| 190 | } |
| 191 | |
| 192 | if ((error = update_mp(mp, &args)) != 0) { |
| 193 | (void)msdosfs_unmount(mp, 0, p); |
| 194 | free(mp, M_MOUNT); |
| 195 | return (error); |
| 196 | } |
| 197 | |
| 198 | if ((error = vfs_lock(mp)) != 0) { |
| 199 | (void)msdosfs_unmount(mp, 0, p); |
| 200 | free(mp, M_MOUNT); |
| 201 | return (error); |
| 202 | } |
| 203 | |
| 204 | TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); |
| 205 | mp->mnt_vnodecovered = NULLVP; |
| 206 | (void) copystr("/", mp->mnt_stat.f_mntonname, MNAMELEN - 1, |
| 207 | &size); |
| 208 | bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); |
| 209 | (void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, |
| 210 | &size); |
| 211 | bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); |
| 212 | (void)msdosfs_statfs(mp, &mp->mnt_stat, p); |
| 213 | vfs_unlock(mp); |
| 214 | return (0); |
| 215 | } |
| 216 | #endif |
| 217 | |
| 218 | /* |
| 219 | * mp - path - addr in user space of mount point (ie /usr or whatever) |
| 220 | * data - addr in user space of mount params including the name of the block |
| 221 | * special file to treat as a filesystem. |
| 222 | */ |
| 223 | static int |
| 224 | msdosfs_mount(struct mount *mp, char *path, caddr_t data, struct nameidata *ndp, |
| 225 | struct thread *td) |
| 226 | { |
| 227 | struct vnode *devvp; /* vnode for blk device to mount */ |
| 228 | struct msdosfs_args args; /* will hold data from mount request */ |
| 229 | /* msdosfs specific mount control block */ |
| 230 | struct msdosfsmount *pmp = NULL; |
| 231 | size_t size; |
| 232 | int error, flags; |
| 233 | mode_t accessmode; |
| 234 | struct proc *p = td->td_proc; |
| 235 | |
| 236 | KKASSERT(p); |
| 237 | |
| 238 | error = copyin(data, (caddr_t)&args, sizeof(struct msdosfs_args)); |
| 239 | if (error) |
| 240 | return (error); |
| 241 | if (args.magic != MSDOSFS_ARGSMAGIC) |
| 242 | args.flags = 0; |
| 243 | /* |
| 244 | * If updating, check whether changing from read-only to |
| 245 | * read/write; if there is no device name, that's all we do. |
| 246 | */ |
| 247 | if (mp->mnt_flag & MNT_UPDATE) { |
| 248 | pmp = VFSTOMSDOSFS(mp); |
| 249 | error = 0; |
| 250 | if (!(pmp->pm_flags & MSDOSFSMNT_RONLY) && (mp->mnt_flag & MNT_RDONLY)) { |
| 251 | flags = WRITECLOSE; |
| 252 | if (mp->mnt_flag & MNT_FORCE) |
| 253 | flags |= FORCECLOSE; |
| 254 | error = vflush(mp, 0, flags); |
| 255 | } |
| 256 | if (!error && (mp->mnt_flag & MNT_RELOAD)) |
| 257 | /* not yet implemented */ |
| 258 | error = EOPNOTSUPP; |
| 259 | if (error) |
| 260 | return (error); |
| 261 | if ((pmp->pm_flags & MSDOSFSMNT_RONLY) && (mp->mnt_kern_flag & MNTK_WANTRDWR)) { |
| 262 | /* |
| 263 | * If upgrade to read-write by non-root, then verify |
| 264 | * that user has necessary permissions on the device. |
| 265 | */ |
| 266 | if (p->p_ucred->cr_uid != 0) { |
| 267 | devvp = pmp->pm_devvp; |
| 268 | vn_lock(devvp, NULL, LK_EXCLUSIVE | LK_RETRY, td); |
| 269 | error = VOP_ACCESS(devvp, VREAD | VWRITE, |
| 270 | p->p_ucred, td); |
| 271 | if (error) { |
| 272 | VOP_UNLOCK(devvp, NULL, 0, td); |
| 273 | return (error); |
| 274 | } |
| 275 | VOP_UNLOCK(devvp, NULL, 0, td); |
| 276 | } |
| 277 | pmp->pm_flags &= ~MSDOSFSMNT_RONLY; |
| 278 | } |
| 279 | if (args.fspec == 0) { |
| 280 | #ifdef __notyet__ /* doesn't work correctly with current mountd XXX */ |
| 281 | if (args.flags & MSDOSFSMNT_MNTOPT) { |
| 282 | pmp->pm_flags &= ~MSDOSFSMNT_MNTOPT; |
| 283 | pmp->pm_flags |= args.flags & MSDOSFSMNT_MNTOPT; |
| 284 | if (pmp->pm_flags & MSDOSFSMNT_NOWIN95) |
| 285 | pmp->pm_flags |= MSDOSFSMNT_SHORTNAME; |
| 286 | } |
| 287 | #endif |
| 288 | /* |
| 289 | * Process export requests. |
| 290 | */ |
| 291 | return (vfs_export(mp, &pmp->pm_export, &args.export)); |
| 292 | } |
| 293 | } |
| 294 | /* |
| 295 | * Not an update, or updating the name: look up the name |
| 296 | * and verify that it refers to a sensible block device. |
| 297 | */ |
| 298 | NDINIT(ndp, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE, args.fspec, td); |
| 299 | error = namei(ndp); |
| 300 | if (error) |
| 301 | return (error); |
| 302 | devvp = ndp->ni_vp; |
| 303 | NDFREE(ndp, NDF_ONLY_PNBUF); |
| 304 | |
| 305 | if (!vn_isdisk(devvp, &error)) { |
| 306 | vrele(devvp); |
| 307 | return (error); |
| 308 | } |
| 309 | /* |
| 310 | * If mount by non-root, then verify that user has necessary |
| 311 | * permissions on the device. |
| 312 | */ |
| 313 | if (p->p_ucred->cr_uid != 0) { |
| 314 | accessmode = VREAD; |
| 315 | if ((mp->mnt_flag & MNT_RDONLY) == 0) |
| 316 | accessmode |= VWRITE; |
| 317 | vn_lock(devvp, NULL, LK_EXCLUSIVE | LK_RETRY, td); |
| 318 | error = VOP_ACCESS(devvp, accessmode, p->p_ucred, td); |
| 319 | if (error) { |
| 320 | vput(devvp); |
| 321 | return (error); |
| 322 | } |
| 323 | VOP_UNLOCK(devvp, NULL, 0, td); |
| 324 | } |
| 325 | if ((mp->mnt_flag & MNT_UPDATE) == 0) { |
| 326 | error = mountmsdosfs(devvp, mp, td, &args); |
| 327 | #ifdef MSDOSFS_DEBUG /* only needed for the printf below */ |
| 328 | pmp = VFSTOMSDOSFS(mp); |
| 329 | #endif |
| 330 | } else { |
| 331 | if (devvp != pmp->pm_devvp) |
| 332 | error = EINVAL; /* XXX needs translation */ |
| 333 | else |
| 334 | vrele(devvp); |
| 335 | } |
| 336 | if (error) { |
| 337 | vrele(devvp); |
| 338 | return (error); |
| 339 | } |
| 340 | |
| 341 | error = update_mp(mp, &args); |
| 342 | if (error) { |
| 343 | msdosfs_unmount(mp, MNT_FORCE, td); |
| 344 | return error; |
| 345 | } |
| 346 | |
| 347 | (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size); |
| 348 | bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); |
| 349 | (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, |
| 350 | &size); |
| 351 | bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); |
| 352 | (void) msdosfs_statfs(mp, &mp->mnt_stat, td); |
| 353 | #ifdef MSDOSFS_DEBUG |
| 354 | printf("msdosfs_mount(): mp %p, pmp %p, inusemap %p\n", mp, pmp, pmp->pm_inusemap); |
| 355 | #endif |
| 356 | return (0); |
| 357 | } |
| 358 | |
| 359 | static int |
| 360 | mountmsdosfs(struct vnode *devvp, struct mount *mp, struct thread *td, |
| 361 | struct msdosfs_args *argp) |
| 362 | { |
| 363 | struct msdosfsmount *pmp; |
| 364 | struct buf *bp; |
| 365 | dev_t dev; |
| 366 | #ifndef __DragonFly__ |
| 367 | struct partinfo dpart; |
| 368 | int bsize = 0, dtype = 0, tmp; |
| 369 | #endif |
| 370 | union bootsector *bsp; |
| 371 | struct byte_bpb33 *b33; |
| 372 | struct byte_bpb50 *b50; |
| 373 | struct byte_bpb710 *b710; |
| 374 | u_int8_t SecPerClust; |
| 375 | u_long clusters; |
| 376 | int ronly, error; |
| 377 | |
| 378 | /* |
| 379 | * Disallow multiple mounts of the same device. |
| 380 | * Disallow mounting of a device that is currently in use |
| 381 | * (except for root, which might share swap device for miniroot). |
| 382 | * Flush out any old buffers remaining from a previous use. |
| 383 | */ |
| 384 | error = vfs_mountedon(devvp); |
| 385 | if (error) |
| 386 | return (error); |
| 387 | if (count_udev(devvp) > 0 && devvp != rootvp) |
| 388 | return (EBUSY); |
| 389 | vn_lock(devvp, NULL, LK_EXCLUSIVE | LK_RETRY, td); |
| 390 | error = vinvalbuf(devvp, V_SAVE, td, 0, 0); |
| 391 | VOP_UNLOCK(devvp, NULL, 0, td); |
| 392 | if (error) |
| 393 | return (error); |
| 394 | |
| 395 | ronly = (mp->mnt_flag & MNT_RDONLY) != 0; |
| 396 | vn_lock(devvp, NULL, LK_EXCLUSIVE | LK_RETRY, td); |
| 397 | error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, td); |
| 398 | VOP_UNLOCK(devvp, NULL, 0, td); |
| 399 | if (error) |
| 400 | return (error); |
| 401 | dev = devvp->v_rdev; |
| 402 | bp = NULL; /* both used in error_exit */ |
| 403 | pmp = NULL; |
| 404 | |
| 405 | #ifndef __DragonFly__ |
| 406 | if (argp->flags & MSDOSFSMNT_GEMDOSFS) { |
| 407 | /* |
| 408 | * We need the disklabel to calculate the size of a FAT entry |
| 409 | * later on. Also make sure the partition contains a filesystem |
| 410 | * of type FS_MSDOS. This doesn't work for floppies, so we have |
| 411 | * to check for them too. |
| 412 | * |
| 413 | * At least some parts of the msdos fs driver seem to assume |
| 414 | * that the size of a disk block will always be 512 bytes. |
| 415 | * Let's check it... |
| 416 | */ |
| 417 | error = VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, td); |
| 418 | if (error) |
| 419 | goto error_exit; |
| 420 | tmp = dpart.part->p_fstype; |
| 421 | dtype = dpart.disklab->d_type; |
| 422 | bsize = dpart.disklab->d_secsize; |
| 423 | if (bsize != 512 || (dtype!=DTYPE_FLOPPY && tmp!=FS_MSDOS)) { |
| 424 | error = EINVAL; |
| 425 | goto error_exit; |
| 426 | } |
| 427 | } |
| 428 | #endif |
| 429 | |
| 430 | /* |
| 431 | * Read the boot sector of the filesystem, and then check the |
| 432 | * boot signature. If not a dos boot sector then error out. |
| 433 | * |
| 434 | * NOTE: 2048 is a maximum sector size in current... |
| 435 | */ |
| 436 | error = bread(devvp, 0, 2048, &bp); |
| 437 | if (error) |
| 438 | goto error_exit; |
| 439 | bp->b_flags |= B_AGE; |
| 440 | bsp = (union bootsector *)bp->b_data; |
| 441 | b33 = (struct byte_bpb33 *)bsp->bs33.bsBPB; |
| 442 | b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB; |
| 443 | b710 = (struct byte_bpb710 *)bsp->bs710.bsPBP; |
| 444 | |
| 445 | #ifndef __DragonFly__ |
| 446 | if (!(argp->flags & MSDOSFSMNT_GEMDOSFS)) { |
| 447 | #endif |
| 448 | #ifndef MSDOSFS_NOCHECKSIG |
| 449 | if (bsp->bs50.bsBootSectSig0 != BOOTSIG0 |
| 450 | || bsp->bs50.bsBootSectSig1 != BOOTSIG1) { |
| 451 | error = EINVAL; |
| 452 | goto error_exit; |
| 453 | } |
| 454 | #endif |
| 455 | #ifndef __DragonFly__ |
| 456 | } |
| 457 | #endif |
| 458 | |
| 459 | pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK); |
| 460 | bzero((caddr_t)pmp, sizeof *pmp); |
| 461 | pmp->pm_mountp = mp; |
| 462 | |
| 463 | /* |
| 464 | * Compute several useful quantities from the bpb in the |
| 465 | * bootsector. Copy in the dos 5 variant of the bpb then fix up |
| 466 | * the fields that are different between dos 5 and dos 3.3. |
| 467 | */ |
| 468 | SecPerClust = b50->bpbSecPerClust; |
| 469 | pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec); |
| 470 | pmp->pm_ResSectors = getushort(b50->bpbResSectors); |
| 471 | pmp->pm_FATs = b50->bpbFATs; |
| 472 | pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts); |
| 473 | pmp->pm_Sectors = getushort(b50->bpbSectors); |
| 474 | pmp->pm_FATsecs = getushort(b50->bpbFATsecs); |
| 475 | pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack); |
| 476 | pmp->pm_Heads = getushort(b50->bpbHeads); |
| 477 | pmp->pm_Media = b50->bpbMedia; |
| 478 | |
| 479 | /* calculate the ratio of sector size to DEV_BSIZE */ |
| 480 | pmp->pm_BlkPerSec = pmp->pm_BytesPerSec / DEV_BSIZE; |
| 481 | |
| 482 | #ifndef __DragonFly__ |
| 483 | if (!(argp->flags & MSDOSFSMNT_GEMDOSFS)) { |
| 484 | #endif |
| 485 | /* XXX - We should probably check more values here */ |
| 486 | if (!pmp->pm_BytesPerSec || !SecPerClust |
| 487 | || !pmp->pm_Heads |
| 488 | #ifdef PC98 |
| 489 | || !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 255) { |
| 490 | #else |
| 491 | || !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 63) { |
| 492 | #endif |
| 493 | error = EINVAL; |
| 494 | goto error_exit; |
| 495 | } |
| 496 | #ifndef __DragonFly__ |
| 497 | } |
| 498 | #endif |
| 499 | |
| 500 | if (pmp->pm_Sectors == 0) { |
| 501 | pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs); |
| 502 | pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors); |
| 503 | } else { |
| 504 | pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs); |
| 505 | pmp->pm_HugeSectors = pmp->pm_Sectors; |
| 506 | } |
| 507 | if (pmp->pm_HugeSectors > 0xffffffff / |
| 508 | (pmp->pm_BytesPerSec / sizeof(struct direntry)) + 1) { |
| 509 | /* |
| 510 | * We cannot deal currently with this size of disk |
| 511 | * due to fileid limitations (see msdosfs_getattr and |
| 512 | * msdosfs_readdir) |
| 513 | */ |
| 514 | error = EINVAL; |
| 515 | printf("mountmsdosfs(): disk too big, sorry\n"); |
| 516 | goto error_exit; |
| 517 | } |
| 518 | |
| 519 | if (pmp->pm_RootDirEnts == 0) { |
| 520 | if (bsp->bs710.bsBootSectSig2 != BOOTSIG2 |
| 521 | || bsp->bs710.bsBootSectSig3 != BOOTSIG3 |
| 522 | || pmp->pm_Sectors |
| 523 | || pmp->pm_FATsecs |
| 524 | || getushort(b710->bpbFSVers)) { |
| 525 | error = EINVAL; |
| 526 | printf("mountmsdosfs(): bad FAT32 filesystem\n"); |
| 527 | goto error_exit; |
| 528 | } |
| 529 | pmp->pm_fatmask = FAT32_MASK; |
| 530 | pmp->pm_fatmult = 4; |
| 531 | pmp->pm_fatdiv = 1; |
| 532 | pmp->pm_FATsecs = getulong(b710->bpbBigFATsecs); |
| 533 | if (getushort(b710->bpbExtFlags) & FATMIRROR) |
| 534 | pmp->pm_curfat = getushort(b710->bpbExtFlags) & FATNUM; |
| 535 | else |
| 536 | pmp->pm_flags |= MSDOSFS_FATMIRROR; |
| 537 | } else |
| 538 | pmp->pm_flags |= MSDOSFS_FATMIRROR; |
| 539 | |
| 540 | /* |
| 541 | * Check a few values (could do some more): |
| 542 | * - logical sector size: power of 2, >= block size |
| 543 | * - sectors per cluster: power of 2, >= 1 |
| 544 | * - number of sectors: >= 1, <= size of partition |
| 545 | */ |
| 546 | if ( (SecPerClust == 0) |
| 547 | || (SecPerClust & (SecPerClust - 1)) |
| 548 | || (pmp->pm_BytesPerSec < DEV_BSIZE) |
| 549 | || (pmp->pm_BytesPerSec & (pmp->pm_BytesPerSec - 1)) |
| 550 | || (pmp->pm_HugeSectors == 0) |
| 551 | ) { |
| 552 | error = EINVAL; |
| 553 | goto error_exit; |
| 554 | } |
| 555 | |
| 556 | pmp->pm_HugeSectors *= pmp->pm_BlkPerSec; |
| 557 | pmp->pm_HiddenSects *= pmp->pm_BlkPerSec; /* XXX not used? */ |
| 558 | pmp->pm_FATsecs *= pmp->pm_BlkPerSec; |
| 559 | SecPerClust *= pmp->pm_BlkPerSec; |
| 560 | |
| 561 | pmp->pm_fatblk = pmp->pm_ResSectors * pmp->pm_BlkPerSec; |
| 562 | |
| 563 | if (FAT32(pmp)) { |
| 564 | pmp->pm_rootdirblk = getulong(b710->bpbRootClust); |
| 565 | pmp->pm_firstcluster = pmp->pm_fatblk |
| 566 | + (pmp->pm_FATs * pmp->pm_FATsecs); |
| 567 | pmp->pm_fsinfo = getushort(b710->bpbFSInfo) * pmp->pm_BlkPerSec; |
| 568 | } else { |
| 569 | pmp->pm_rootdirblk = pmp->pm_fatblk + |
| 570 | (pmp->pm_FATs * pmp->pm_FATsecs); |
| 571 | pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry) |
| 572 | + DEV_BSIZE - 1) |
| 573 | / DEV_BSIZE; /* in blocks */ |
| 574 | pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize; |
| 575 | } |
| 576 | |
| 577 | pmp->pm_maxcluster = (pmp->pm_HugeSectors - pmp->pm_firstcluster) / |
| 578 | SecPerClust + 1; |
| 579 | pmp->pm_fatsize = pmp->pm_FATsecs * DEV_BSIZE; /* XXX not used? */ |
| 580 | |
| 581 | #ifndef __DragonFly__ |
| 582 | if (argp->flags & MSDOSFSMNT_GEMDOSFS) { |
| 583 | if ((pmp->pm_maxcluster <= (0xff0 - 2)) |
| 584 | && ((dtype == DTYPE_FLOPPY) || ((dtype == DTYPE_VNODE) |
| 585 | && ((pmp->pm_Heads == 1) || (pmp->pm_Heads == 2)))) |
| 586 | ) { |
| 587 | pmp->pm_fatmask = FAT12_MASK; |
| 588 | pmp->pm_fatmult = 3; |
| 589 | pmp->pm_fatdiv = 2; |
| 590 | } else { |
| 591 | pmp->pm_fatmask = FAT16_MASK; |
| 592 | pmp->pm_fatmult = 2; |
| 593 | pmp->pm_fatdiv = 1; |
| 594 | } |
| 595 | } else |
| 596 | #endif |
| 597 | if (pmp->pm_fatmask == 0) { |
| 598 | if (pmp->pm_maxcluster |
| 599 | <= ((CLUST_RSRVD - CLUST_FIRST) & FAT12_MASK)) { |
| 600 | /* |
| 601 | * This will usually be a floppy disk. This size makes |
| 602 | * sure that one fat entry will not be split across |
| 603 | * multiple blocks. |
| 604 | */ |
| 605 | pmp->pm_fatmask = FAT12_MASK; |
| 606 | pmp->pm_fatmult = 3; |
| 607 | pmp->pm_fatdiv = 2; |
| 608 | } else { |
| 609 | pmp->pm_fatmask = FAT16_MASK; |
| 610 | pmp->pm_fatmult = 2; |
| 611 | pmp->pm_fatdiv = 1; |
| 612 | } |
| 613 | } |
| 614 | |
| 615 | clusters = (pmp->pm_fatsize / pmp->pm_fatmult) * pmp->pm_fatdiv; |
| 616 | if (pmp->pm_maxcluster >= clusters) { |
| 617 | printf("Warning: number of clusters (%ld) exceeds FAT " |
| 618 | "capacity (%ld)\n", pmp->pm_maxcluster + 1, clusters); |
| 619 | pmp->pm_maxcluster = clusters - 1; |
| 620 | } |
| 621 | |
| 622 | |
| 623 | if (FAT12(pmp)) |
| 624 | pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec; |
| 625 | else |
| 626 | pmp->pm_fatblocksize = MSDOSFS_DFLTBSIZE; |
| 627 | |
| 628 | pmp->pm_fatblocksec = pmp->pm_fatblocksize / DEV_BSIZE; |
| 629 | pmp->pm_bnshift = ffs(DEV_BSIZE) - 1; |
| 630 | |
| 631 | /* |
| 632 | * Compute mask and shift value for isolating cluster relative byte |
| 633 | * offsets and cluster numbers from a file offset. |
| 634 | */ |
| 635 | pmp->pm_bpcluster = SecPerClust * DEV_BSIZE; |
| 636 | pmp->pm_crbomask = pmp->pm_bpcluster - 1; |
| 637 | pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1; |
| 638 | |
| 639 | /* |
| 640 | * Check for valid cluster size |
| 641 | * must be a power of 2 |
| 642 | */ |
| 643 | if (pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) { |
| 644 | error = EINVAL; |
| 645 | goto error_exit; |
| 646 | } |
| 647 | |
| 648 | /* |
| 649 | * Release the bootsector buffer. |
| 650 | */ |
| 651 | brelse(bp); |
| 652 | bp = NULL; |
| 653 | |
| 654 | /* |
| 655 | * Check FSInfo. |
| 656 | */ |
| 657 | if (pmp->pm_fsinfo) { |
| 658 | struct fsinfo *fp; |
| 659 | |
| 660 | if ((error = bread(devvp, pmp->pm_fsinfo, fsi_size(pmp), &bp)) != 0) |
| 661 | goto error_exit; |
| 662 | fp = (struct fsinfo *)bp->b_data; |
| 663 | if (!bcmp(fp->fsisig1, "RRaA", 4) |
| 664 | && !bcmp(fp->fsisig2, "rrAa", 4) |
| 665 | && !bcmp(fp->fsisig3, "\0\0\125\252", 4) |
| 666 | && !bcmp(fp->fsisig4, "\0\0\125\252", 4)) { |
| 667 | pmp->pm_nxtfree = getulong(fp->fsinxtfree); |
| 668 | if (pmp->pm_nxtfree == 0xffffffff) |
| 669 | pmp->pm_nxtfree = CLUST_FIRST; |
| 670 | } else |
| 671 | pmp->pm_fsinfo = 0; |
| 672 | brelse(bp); |
| 673 | bp = NULL; |
| 674 | } |
| 675 | |
| 676 | /* |
| 677 | * Check and validate (or perhaps invalidate?) the fsinfo structure? |
| 678 | */ |
| 679 | if (pmp->pm_fsinfo && pmp->pm_nxtfree > pmp->pm_maxcluster) { |
| 680 | printf( |
| 681 | "Next free cluster in FSInfo (%lu) exceeds maxcluster (%lu)\n", |
| 682 | pmp->pm_nxtfree, pmp->pm_maxcluster); |
| 683 | error = EINVAL; |
| 684 | goto error_exit; |
| 685 | } |
| 686 | |
| 687 | /* |
| 688 | * Allocate memory for the bitmap of allocated clusters, and then |
| 689 | * fill it in. |
| 690 | */ |
| 691 | pmp->pm_inusemap = malloc(((pmp->pm_maxcluster + N_INUSEBITS - 1) |
| 692 | / N_INUSEBITS) |
| 693 | * sizeof(*pmp->pm_inusemap), |
| 694 | M_MSDOSFSFAT, M_WAITOK); |
| 695 | |
| 696 | /* |
| 697 | * fillinusemap() needs pm_devvp. |
| 698 | */ |
| 699 | pmp->pm_dev = dev; |
| 700 | pmp->pm_devvp = devvp; |
| 701 | |
| 702 | /* |
| 703 | * Have the inuse map filled in. |
| 704 | */ |
| 705 | if ((error = fillinusemap(pmp)) != 0) |
| 706 | goto error_exit; |
| 707 | |
| 708 | /* |
| 709 | * If they want fat updates to be synchronous then let them suffer |
| 710 | * the performance degradation in exchange for the on disk copy of |
| 711 | * the fat being correct just about all the time. I suppose this |
| 712 | * would be a good thing to turn on if the kernel is still flakey. |
| 713 | */ |
| 714 | if (mp->mnt_flag & MNT_SYNCHRONOUS) |
| 715 | pmp->pm_flags |= MSDOSFSMNT_WAITONFAT; |
| 716 | |
| 717 | /* |
| 718 | * Finish up. |
| 719 | */ |
| 720 | if (ronly) |
| 721 | pmp->pm_flags |= MSDOSFSMNT_RONLY; |
| 722 | else |
| 723 | pmp->pm_fmod = 1; |
| 724 | mp->mnt_data = (qaddr_t) pmp; |
| 725 | mp->mnt_stat.f_fsid.val[0] = dev2udev(dev); |
| 726 | mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; |
| 727 | mp->mnt_flag |= MNT_LOCAL; |
| 728 | dev->si_mountpoint = mp; |
| 729 | |
| 730 | return 0; |
| 731 | |
| 732 | error_exit: |
| 733 | if (bp) |
| 734 | brelse(bp); |
| 735 | (void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD | FWRITE, td); |
| 736 | if (pmp) { |
| 737 | if (pmp->pm_inusemap) |
| 738 | free(pmp->pm_inusemap, M_MSDOSFSFAT); |
| 739 | free(pmp, M_MSDOSFSMNT); |
| 740 | mp->mnt_data = (qaddr_t)0; |
| 741 | } |
| 742 | return (error); |
| 743 | } |
| 744 | |
| 745 | /* |
| 746 | * Unmount the filesystem described by mp. |
| 747 | */ |
| 748 | static int |
| 749 | msdosfs_unmount(struct mount *mp, int mntflags, struct thread *td) |
| 750 | { |
| 751 | struct msdosfsmount *pmp; |
| 752 | int error, flags; |
| 753 | |
| 754 | flags = 0; |
| 755 | if (mntflags & MNT_FORCE) |
| 756 | flags |= FORCECLOSE; |
| 757 | error = vflush(mp, 0, flags); |
| 758 | if (error) |
| 759 | return error; |
| 760 | pmp = VFSTOMSDOSFS(mp); |
| 761 | pmp->pm_devvp->v_rdev->si_mountpoint = NULL; |
| 762 | #ifdef MSDOSFS_DEBUG |
| 763 | { |
| 764 | struct vnode *vp = pmp->pm_devvp; |
| 765 | |
| 766 | printf("msdosfs_umount(): just before calling VOP_CLOSE()\n"); |
| 767 | printf("flag %08lx, usecount %d, writecount %d, holdcnt %ld\n", |
| 768 | vp->v_flag, vp->v_usecount, vp->v_writecount, vp->v_holdcnt); |
| 769 | printf("id %lu, mount %p, op %p\n", |
| 770 | vp->v_id, vp->v_mount, vp->v_op); |
| 771 | printf("freef %p, freeb %p, mount %p\n", |
| 772 | vp->v_freelist.tqe_next, vp->v_freelist.tqe_prev, |
| 773 | vp->v_mount); |
| 774 | printf("cleanblkhd %p, dirtyblkhd %p, numoutput %ld, type %d\n", |
| 775 | TAILQ_FIRST(&vp->v_cleanblkhd), |
| 776 | TAILQ_FIRST(&vp->v_dirtyblkhd), |
| 777 | vp->v_numoutput, vp->v_type); |
| 778 | printf("union %p, tag %d, data[0] %08x, data[1] %08x\n", |
| 779 | vp->v_socket, vp->v_tag, |
| 780 | ((u_int *)vp->v_data)[0], |
| 781 | ((u_int *)vp->v_data)[1]); |
| 782 | } |
| 783 | #endif |
| 784 | error = VOP_CLOSE(pmp->pm_devvp, |
| 785 | (pmp->pm_flags&MSDOSFSMNT_RONLY) ? FREAD : FREAD | FWRITE, |
| 786 | td); |
| 787 | vrele(pmp->pm_devvp); |
| 788 | free(pmp->pm_inusemap, M_MSDOSFSFAT); |
| 789 | free(pmp, M_MSDOSFSMNT); |
| 790 | mp->mnt_data = (qaddr_t)0; |
| 791 | mp->mnt_flag &= ~MNT_LOCAL; |
| 792 | return (error); |
| 793 | } |
| 794 | |
| 795 | static int |
| 796 | msdosfs_root(struct mount *mp, struct vnode **vpp) |
| 797 | { |
| 798 | struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); |
| 799 | struct denode *ndep; |
| 800 | int error; |
| 801 | |
| 802 | #ifdef MSDOSFS_DEBUG |
| 803 | printf("msdosfs_root(); mp %p, pmp %p\n", mp, pmp); |
| 804 | #endif |
| 805 | error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, &ndep); |
| 806 | if (error) |
| 807 | return (error); |
| 808 | *vpp = DETOV(ndep); |
| 809 | return (0); |
| 810 | } |
| 811 | |
| 812 | static int |
| 813 | msdosfs_statfs(struct mount *mp, struct statfs *sbp, struct thread *td) |
| 814 | { |
| 815 | struct msdosfsmount *pmp; |
| 816 | |
| 817 | pmp = VFSTOMSDOSFS(mp); |
| 818 | sbp->f_bsize = pmp->pm_bpcluster; |
| 819 | sbp->f_iosize = pmp->pm_bpcluster; |
| 820 | sbp->f_blocks = pmp->pm_maxcluster + 1; |
| 821 | sbp->f_bfree = pmp->pm_freeclustercount; |
| 822 | sbp->f_bavail = pmp->pm_freeclustercount; |
| 823 | sbp->f_files = pmp->pm_RootDirEnts; /* XXX */ |
| 824 | sbp->f_ffree = 0; /* what to put in here? */ |
| 825 | if (sbp != &mp->mnt_stat) { |
| 826 | sbp->f_type = mp->mnt_vfc->vfc_typenum; |
| 827 | bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); |
| 828 | bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); |
| 829 | } |
| 830 | strncpy(sbp->f_fstypename, mp->mnt_vfc->vfc_name, MFSNAMELEN); |
| 831 | return (0); |
| 832 | } |
| 833 | |
| 834 | struct scaninfo { |
| 835 | int rescan; |
| 836 | int allerror; |
| 837 | int waitfor; |
| 838 | thread_t td; |
| 839 | }; |
| 840 | |
| 841 | static int msdosfs_sync_scan(struct mount *mp, struct vnode *vp, |
| 842 | lwkt_tokref_t vlock, void *data); |
| 843 | |
| 844 | static int |
| 845 | msdosfs_sync(struct mount *mp, int waitfor, struct thread *td) |
| 846 | { |
| 847 | struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); |
| 848 | struct scaninfo scaninfo; |
| 849 | int error; |
| 850 | |
| 851 | /* |
| 852 | * If we ever switch to not updating all of the fats all the time, |
| 853 | * this would be the place to update them from the first one. |
| 854 | */ |
| 855 | if (pmp->pm_fmod != 0) { |
| 856 | if (pmp->pm_flags & MSDOSFSMNT_RONLY) |
| 857 | panic("msdosfs_sync: rofs mod"); |
| 858 | else { |
| 859 | /* update fats here */ |
| 860 | } |
| 861 | } |
| 862 | /* |
| 863 | * Write back each (modified) denode. |
| 864 | */ |
| 865 | scaninfo.allerror = 0; |
| 866 | scaninfo.rescan = 1; |
| 867 | scaninfo.td = td; |
| 868 | while (scaninfo.rescan) { |
| 869 | scaninfo.rescan = 0; |
| 870 | vmntvnodescan(mp, NULL, msdosfs_sync_scan, &scaninfo); |
| 871 | } |
| 872 | |
| 873 | /* |
| 874 | * Flush filesystem control info. |
| 875 | */ |
| 876 | if (waitfor != MNT_LAZY) { |
| 877 | vn_lock(pmp->pm_devvp, NULL, LK_EXCLUSIVE | LK_RETRY, td); |
| 878 | if ((error = VOP_FSYNC(pmp->pm_devvp, waitfor, td)) != 0) |
| 879 | scaninfo.allerror = error; |
| 880 | VOP_UNLOCK(pmp->pm_devvp, NULL, 0, td); |
| 881 | } |
| 882 | return (scaninfo.allerror); |
| 883 | } |
| 884 | |
| 885 | static int |
| 886 | msdosfs_sync_scan(struct mount *mp, struct vnode *vp, |
| 887 | lwkt_tokref_t vlock, void *data) |
| 888 | { |
| 889 | struct scaninfo *info = data; |
| 890 | struct denode *dep; |
| 891 | int error; |
| 892 | |
| 893 | dep = VTODE(vp); |
| 894 | if (vp->v_type == VNON || |
| 895 | ((dep->de_flag & |
| 896 | (DE_ACCESS | DE_CREATE | DE_UPDATE | DE_MODIFIED)) == 0 && |
| 897 | (TAILQ_EMPTY(&vp->v_dirtyblkhd) || info->waitfor == MNT_LAZY))) { |
| 898 | lwkt_reltoken(vlock); |
| 899 | return(0); |
| 900 | } |
| 901 | error = vget(vp, vlock, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, info->td); |
| 902 | if (error) { |
| 903 | if (error == ENOENT) |
| 904 | info->rescan = 1; |
| 905 | return(0); |
| 906 | } |
| 907 | if ((error = VOP_FSYNC(vp, info->waitfor, info->td)) != 0) |
| 908 | info->allerror = error; |
| 909 | VOP_UNLOCK(vp, NULL, 0, info->td); |
| 910 | vrele(vp); |
| 911 | return(0); |
| 912 | } |
| 913 | |
| 914 | static int |
| 915 | msdosfs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp) |
| 916 | { |
| 917 | struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); |
| 918 | struct defid *defhp = (struct defid *) fhp; |
| 919 | struct denode *dep; |
| 920 | int error; |
| 921 | |
| 922 | error = deget(pmp, defhp->defid_dirclust, defhp->defid_dirofs, &dep); |
| 923 | if (error) { |
| 924 | *vpp = NULLVP; |
| 925 | return (error); |
| 926 | } |
| 927 | *vpp = DETOV(dep); |
| 928 | return (0); |
| 929 | } |
| 930 | |
| 931 | static int |
| 932 | msdosfs_checkexp(struct mount *mp, struct sockaddr *nam, int *exflagsp, |
| 933 | struct ucred **credanonp) |
| 934 | { |
| 935 | struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); |
| 936 | struct netcred *np; |
| 937 | |
| 938 | np = vfs_export_lookup(mp, &pmp->pm_export, nam); |
| 939 | if (np == NULL) |
| 940 | return (EACCES); |
| 941 | *exflagsp = np->netc_exflags; |
| 942 | *credanonp = &np->netc_anon; |
| 943 | return (0); |
| 944 | } |
| 945 | |
| 946 | static int |
| 947 | msdosfs_vptofh(struct vnode *vp, struct fid *fhp) |
| 948 | { |
| 949 | struct denode *dep; |
| 950 | struct defid *defhp; |
| 951 | |
| 952 | dep = VTODE(vp); |
| 953 | defhp = (struct defid *)fhp; |
| 954 | defhp->defid_len = sizeof(struct defid); |
| 955 | defhp->defid_dirclust = dep->de_dirclust; |
| 956 | defhp->defid_dirofs = dep->de_diroffset; |
| 957 | /* defhp->defid_gen = dep->de_gen; */ |
| 958 | return (0); |
| 959 | } |
| 960 | |
| 961 | static struct vfsops msdosfs_vfsops = { |
| 962 | msdosfs_mount, |
| 963 | vfs_stdstart, |
| 964 | msdosfs_unmount, |
| 965 | msdosfs_root, |
| 966 | vfs_stdquotactl, |
| 967 | msdosfs_statfs, |
| 968 | msdosfs_sync, |
| 969 | vfs_stdvget, |
| 970 | msdosfs_fhtovp, |
| 971 | msdosfs_checkexp, |
| 972 | msdosfs_vptofh, |
| 973 | msdosfs_init, |
| 974 | msdosfs_uninit, |
| 975 | vfs_stdextattrctl, |
| 976 | }; |
| 977 | |
| 978 | VFS_SET(msdosfs_vfsops, msdos, 0); |