1 /* $FreeBSD$ */ 2 /* $NetBSD: msdosfs_vfsops.c,v 1.19 1994/08/21 18:44:10 ws Exp $ */ 3 4 /*- 5 * Copyright (C) 1994 Wolfgang Solfrank. 6 * Copyright (C) 1994 TooLs GmbH. 7 * All rights reserved. 8 * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by TooLs GmbH. 21 * 4. The name of TooLs GmbH may not be used to endorse or promote products 22 * derived from this software without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 27 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 29 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 30 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 31 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 33 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 */ 35 /* 36 * Written by Paul Popelka (paulp@uts.amdahl.com) 37 * 38 * You can do anything you want with this software, just don't say you wrote 39 * it, and don't remove this notice. 40 * 41 * This software is provided "as is". 42 * 43 * The author supplies this software to be publicly redistributed on the 44 * understanding that the author is not responsible for the correct 45 * functioning of this software in any circumstances and is not liable for 46 * any damages caused by this software. 47 * 48 * October 1992 49 */ 50 51 #include <sys/param.h> 52 #include <sys/systm.h> 53 #include <sys/namei.h> 54 #include <sys/proc.h> 55 #include <sys/kernel.h> 56 #include <sys/vnode.h> 57 #include <miscfs/specfs/specdev.h> /* XXX */ /* defines v_rdev */ 58 #include <sys/mount.h> 59 #include <sys/buf.h> 60 #include <sys/file.h> 61 #include <sys/malloc.h> 62 63 #include <msdosfs/bpb.h> 64 #include <msdosfs/bootsect.h> 65 #include <msdosfs/direntry.h> 66 #include <msdosfs/denode.h> 67 #include <msdosfs/msdosfsmount.h> 68 #include <msdosfs/fat.h> 69 70 static int msdosfsdoforce = 1; /* 1 = force unmount */ 71 72 static int mountmsdosfs __P((struct vnode *devvp, struct mount *mp, 73 struct proc *p)); 74 static int msdosfs_fhtovp __P((struct mount *, struct fid *, 75 struct mbuf *, struct vnode **, int *, 76 struct ucred **)); 77 static int msdosfs_mount __P((struct mount *, char *, caddr_t, 78 struct nameidata *, struct proc *)); 79 static int msdosfs_quotactl __P((struct mount *, int, uid_t, caddr_t, 80 struct proc *)); 81 static int msdosfs_root __P((struct mount *, struct vnode **)); 82 static int msdosfs_start __P((struct mount *, int, struct proc *)); 83 static int msdosfs_statfs __P((struct mount *, struct statfs *, 84 struct proc *)); 85 static int msdosfs_sync __P((struct mount *, int, struct ucred *, 86 struct proc *)); 87 static int msdosfs_unmount __P((struct mount *, int, struct proc *)); 88 static int msdosfs_vget __P((struct mount *mp, ino_t ino, 89 struct vnode **vpp)); 90 static int msdosfs_vptofh __P((struct vnode *, struct fid *)); 91 92 /* 93 * mp - path - addr in user space of mount point (ie /usr or whatever) 94 * data - addr in user space of mount params including the name of the block 95 * special file to treat as a filesystem. 96 */ 97 static int 98 msdosfs_mount(mp, path, data, ndp, p) 99 struct mount *mp; 100 char *path; 101 caddr_t data; 102 struct nameidata *ndp; 103 struct proc *p; 104 { 105 struct vnode *devvp; /* vnode for blk device to mount */ 106 struct msdosfs_args args; /* will hold data from mount request */ 107 struct msdosfsmount *pmp; /* msdosfs specific mount control block */ 108 int error, flags; 109 u_int size; 110 struct ucred *cred, *scred; 111 struct vattr va; 112 113 /* 114 * Copy in the args for the mount request. 115 */ 116 error = copyin(data, (caddr_t) & args, sizeof(struct msdosfs_args)); 117 if (error) 118 return error; 119 120 /* 121 * If they just want to update then be sure we can do what is 122 * asked. Can't change a filesystem from read/write to read only. 123 * Why? And if they've supplied a new device file name then we 124 * continue, otherwise return. 125 */ 126 if (mp->mnt_flag & MNT_UPDATE) { 127 pmp = (struct msdosfsmount *) mp->mnt_data; 128 error = 0; 129 if (pmp->pm_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) { 130 flags = WRITECLOSE; 131 if (mp->mnt_flag & MNT_FORCE) 132 flags |= FORCECLOSE; 133 if (vfs_busy(mp, LK_NOWAIT, 0, p)) 134 return EBUSY; 135 error = vflush(mp, NULLVP, flags); 136 vfs_unbusy(mp, p); 137 } 138 if (!error && (mp->mnt_flag & MNT_RELOAD)) 139 /* not yet implemented */ 140 error = EINVAL; 141 if (error) 142 return error; 143 if (pmp->pm_ronly && (mp->mnt_flag & MNT_RDONLY) == 0) 144 pmp->pm_ronly = 0; 145 if (args.fspec == 0) { 146 /* 147 * Process export requests. 148 */ 149 return vfs_export(mp, &pmp->pm_export, &args.export); 150 } 151 } else 152 pmp = NULL; 153 154 /* 155 * check to see that the user in owns the target directory. 156 * Note the very XXX trick to make sure we're checking as the 157 * real user -- were mount() executable by anyone, this wouldn't 158 * be a problem. 159 * 160 * XXX there should be one consistent error out. 161 */ 162 cred = crdup(p->p_ucred); /* XXX */ 163 cred->cr_uid = p->p_cred->p_ruid; /* XXX */ 164 error = VOP_GETATTR(mp->mnt_vnodecovered, &va, cred, p); 165 if (error) { 166 crfree(cred); /* XXX */ 167 return error; 168 } 169 if (cred->cr_uid != 0) { 170 if (va.va_uid != cred->cr_uid) { 171 error = EACCES; 172 crfree(cred); /* XXX */ 173 return error; 174 } 175 176 /* a user mounted it; we'll verify permissions when unmounting */ 177 mp->mnt_flag |= MNT_USER; 178 } 179 180 /* 181 * Now, lookup the name of the block device this mount or name 182 * update request is to apply to. 183 */ 184 NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p); 185 scred = p->p_ucred; /* XXX */ 186 p->p_ucred = cred; /* XXX */ 187 error = namei(ndp); 188 p->p_ucred = scred; /* XXX */ 189 crfree(cred); /* XXX */ 190 if (error != 0) 191 return error; 192 193 /* 194 * Be sure they've given us a block device to treat as a 195 * filesystem. And, that its major number is within the bdevsw 196 * table. 197 */ 198 devvp = ndp->ni_vp; 199 if (devvp->v_type != VBLK) { 200 vrele(devvp); 201 return ENOTBLK; 202 } 203 if (major(devvp->v_rdev) >= nblkdev) { 204 vrele(devvp); 205 return ENXIO; 206 } 207 208 /* 209 * If this is an update, then make sure the vnode for the block 210 * special device is the same as the one our filesystem is in. 211 */ 212 if (mp->mnt_flag & MNT_UPDATE) { 213 if (devvp != pmp->pm_devvp) 214 error = EINVAL; 215 else 216 vrele(devvp); 217 } else { 218 219 /* 220 * Well, it's not an update, it's a real mount request. 221 * Time to get dirty. 222 */ 223 error = mountmsdosfs(devvp, mp, p); 224 } 225 if (error) { 226 vrele(devvp); 227 return error; 228 } 229 230 /* 231 * Copy in the name of the directory the filesystem is to be 232 * mounted on. Then copy in the name of the block special file 233 * representing the filesystem being mounted. And we clear the 234 * remainder of the character strings to be tidy. Set up the 235 * user id/group id/mask as specified by the user. Then, we try to 236 * fill in the filesystem stats structure as best we can with 237 * whatever applies from a dos file system. 238 */ 239 pmp = (struct msdosfsmount *) mp->mnt_data; 240 copyinstr(path, (caddr_t) mp->mnt_stat.f_mntonname, 241 sizeof(mp->mnt_stat.f_mntonname) - 1, &size); 242 bzero(mp->mnt_stat.f_mntonname + size, 243 sizeof(mp->mnt_stat.f_mntonname) - size); 244 copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size); 245 bzero(mp->mnt_stat.f_mntfromname + size, 246 MNAMELEN - size); 247 pmp->pm_mounter = p->p_cred->p_ruid; 248 pmp->pm_gid = args.gid; 249 pmp->pm_uid = args.uid; 250 pmp->pm_mask = args.mask; 251 (void) msdosfs_statfs(mp, &mp->mnt_stat, p); 252 #ifdef MSDOSFS_DEBUG 253 printf("msdosfs_mount(): mp %p, pmp %p, inusemap %p\n", mp, pmp, pmp->pm_inusemap); 254 #endif 255 return 0; 256 } 257 258 static int 259 mountmsdosfs(devvp, mp, p) 260 struct vnode *devvp; 261 struct mount *mp; 262 struct proc *p; 263 { 264 int i; 265 int bpc; 266 int bit; 267 int error; 268 int needclose; 269 int ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 270 dev_t dev = devvp->v_rdev; 271 union bootsector *bsp; 272 struct msdosfsmount *pmp = NULL; 273 struct buf *bp0 = NULL; 274 struct byte_bpb33 *b33; 275 struct byte_bpb50 *b50; 276 #ifdef PC98 277 u_int pc98_wrk; 278 u_int Phy_Sector_Size; 279 #endif 280 281 /* 282 * Multiple mounts of the same block special file aren't allowed. 283 * Make sure no one else has the special file open. And flush any 284 * old buffers from this filesystem. Presumably this prevents us 285 * from running into buffers that are the wrong blocksize. 286 */ 287 error = vfs_mountedon(devvp); 288 if (error) 289 return error; 290 if (vcount(devvp) > 1) 291 return EBUSY; 292 error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0); 293 if (error) 294 return error; 295 296 /* 297 * Now open the block special file. 298 */ 299 error = VOP_OPEN(devvp, ronly ? FREAD : FREAD | FWRITE, FSCRED, p); 300 if (error) 301 return error; 302 needclose = 1; 303 #ifdef HDSUPPORT 304 /* 305 * Put this in when we support reading dos filesystems from 306 * partitioned harddisks. 307 */ 308 if (VOP_IOCTL(devvp, DIOCGPART, &msdosfspart, FREAD, NOCRED, p) == 0) { 309 } 310 #endif 311 312 /* 313 * Read the boot sector of the filesystem, and then check the boot 314 * signature. If not a dos boot sector then error out. We could 315 * also add some checking on the bsOemName field. So far I've seen 316 * the following values: "IBM 3.3" "MSDOS3.3" "MSDOS5.0" 317 */ 318 #ifdef PC98 319 devvp->v_flag &= 0xffff; 320 error = bread(devvp, 0, 1024, NOCRED, &bp0); 321 #else 322 error = bread(devvp, 0, 512, NOCRED, &bp0); 323 #endif 324 if (error) 325 goto error_exit; 326 bp0->b_flags |= B_AGE; 327 bsp = (union bootsector *) bp0->b_data; 328 b33 = (struct byte_bpb33 *) bsp->bs33.bsBPB; 329 b50 = (struct byte_bpb50 *) bsp->bs50.bsBPB; 330 #ifdef MSDOSFS_CHECKSIG 331 #ifdef PC98 332 if (bsp->bs50.bsBootSectSig != BOOTSIG && 333 bsp->bs50.bsBootSectSig != 0 && /* PC98 DOS 3.3x */ 334 bsp->bs50.bsBootSectSig != 15760 && /* PC98 DOS 5.0 */ 335 bsp->bs50.bsBootSectSig != 64070) { /* PC98 DOS 3.3B */ 336 #else 337 if (bsp->bs50.bsBootSectSig != BOOTSIG) { 338 #endif 339 error = EINVAL; 340 goto error_exit; 341 } 342 #endif 343 if ( bsp->bs50.bsJump[0] != 0xe9 && 344 (bsp->bs50.bsJump[0] != 0xeb || bsp->bs50.bsJump[2] != 0x90)) { 345 error = EINVAL; 346 goto error_exit; 347 } 348 349 pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK); 350 bzero((caddr_t)pmp, sizeof *pmp); 351 pmp->pm_mountp = mp; 352 353 /* 354 * Compute several useful quantities from the bpb in the 355 * bootsector. Copy in the dos 5 variant of the bpb then fix up 356 * the fields that are different between dos 5 and dos 3.3. 357 */ 358 pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec); 359 pmp->pm_SectPerClust = b50->bpbSecPerClust; 360 pmp->pm_ResSectors = getushort(b50->bpbResSectors); 361 pmp->pm_FATs = b50->bpbFATs; 362 pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts); 363 pmp->pm_Sectors = getushort(b50->bpbSectors); 364 pmp->pm_Media = b50->bpbMedia; 365 pmp->pm_FATsecs = getushort(b50->bpbFATsecs); 366 pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack); 367 pmp->pm_Heads = getushort(b50->bpbHeads); 368 369 /* XXX - We should probably check more values here */ 370 if (!pmp->pm_BytesPerSec || !pmp->pm_SectPerClust || 371 !pmp->pm_Heads || pmp->pm_Heads > 255 || 372 #ifdef PC98 373 !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 255) { 374 #else 375 !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 63) { 376 #endif 377 error = EINVAL; 378 goto error_exit; 379 } 380 381 if (pmp->pm_Sectors == 0) { 382 pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs); 383 pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors); 384 } else { 385 pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs); 386 pmp->pm_HugeSectors = pmp->pm_Sectors; 387 } 388 #ifdef PC98 /* for PC98 added Satoshi Yasuda */ 389 Phy_Sector_Size = 512; 390 if ((devvp->v_rdev>>8) == 2) { /* floppy check */ 391 if (((devvp->v_rdev&077) == 2) && (pmp->pm_HugeSectors == 1232)) { 392 Phy_Sector_Size = 1024; /* 2HD */ 393 /* 394 * 1024byte/sector support 395 */ 396 devvp->v_flag |= 0x10000; 397 } else { 398 if ((((devvp->v_rdev&077) == 3) /* 2DD 8 or 9 sector */ 399 && (pmp->pm_HugeSectors == 1440)) /* 9 sector */ 400 || (((devvp->v_rdev&077) == 4) 401 && (pmp->pm_HugeSectors == 1280)) /* 8 sector */ 402 || (((devvp->v_rdev&077) == 5) 403 && (pmp->pm_HugeSectors == 2880))) { /* 1.44M */ 404 Phy_Sector_Size = 512; 405 } else { 406 if (((devvp->v_rdev&077) != 1) 407 && ((devvp->v_rdev&077) != 0)) { /* 2HC */ 408 error = EINVAL; 409 goto error_exit; 410 } 411 } 412 } 413 } 414 pc98_wrk = pmp->pm_BytesPerSec / Phy_Sector_Size; 415 pmp->pm_BytesPerSec = Phy_Sector_Size; 416 pmp->pm_SectPerClust = pmp->pm_SectPerClust * pc98_wrk; 417 pmp->pm_HugeSectors = pmp->pm_HugeSectors * pc98_wrk; 418 pmp->pm_ResSectors = pmp->pm_ResSectors * pc98_wrk; 419 pmp->pm_FATsecs = pmp->pm_FATsecs * pc98_wrk; 420 pmp->pm_SecPerTrack = pmp->pm_SecPerTrack * pc98_wrk; 421 pmp->pm_HiddenSects = pmp->pm_HiddenSects * pc98_wrk; 422 #endif /* */ 423 pmp->pm_fatblk = pmp->pm_ResSectors; 424 pmp->pm_rootdirblk = pmp->pm_fatblk + 425 (pmp->pm_FATs * pmp->pm_FATsecs); 426 pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry)) 427 / 428 pmp->pm_BytesPerSec;/* in sectors */ 429 pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize; 430 pmp->pm_nmbrofclusters = (pmp->pm_HugeSectors - pmp->pm_firstcluster) / 431 pmp->pm_SectPerClust; 432 pmp->pm_maxcluster = pmp->pm_nmbrofclusters + 1; 433 pmp->pm_fatsize = pmp->pm_FATsecs * pmp->pm_BytesPerSec; 434 if (FAT12(pmp)) 435 /* 436 * This will usually be a floppy disk. This size makes sure 437 * that one fat entry will not be split across multiple 438 * blocks. 439 */ 440 pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec; 441 else 442 /* 443 * This will usually be a hard disk. Reading or writing one 444 * block should be quite fast. 445 */ 446 pmp->pm_fatblocksize = MAXBSIZE; 447 pmp->pm_fatblocksec = pmp->pm_fatblocksize / pmp->pm_BytesPerSec; 448 449 450 if ((pmp->pm_rootdirsize % pmp->pm_SectPerClust) != 0) 451 printf("mountmsdosfs(): Warning: root directory is not a multiple of the clustersize in length\n"); 452 453 /* 454 * Compute mask and shift value for isolating cluster relative byte 455 * offsets and cluster numbers from a file offset. 456 */ 457 bpc = pmp->pm_SectPerClust * pmp->pm_BytesPerSec; 458 pmp->pm_bpcluster = bpc; 459 pmp->pm_depclust = bpc / sizeof(struct direntry); 460 pmp->pm_crbomask = bpc - 1; 461 if (bpc == 0) { 462 error = EINVAL; 463 goto error_exit; 464 } 465 bit = 1; 466 for (i = 0; i < 32; i++) { 467 if (bit & bpc) { 468 if (bit ^ bpc) { 469 error = EINVAL; 470 goto error_exit; 471 } 472 pmp->pm_cnshift = i; 473 break; 474 } 475 bit <<= 1; 476 } 477 478 #ifdef PC98 479 if (Phy_Sector_Size == 512) { 480 pmp->pm_brbomask = 0x01ff; /* 512 byte blocks only (so far) */ 481 pmp->pm_bnshift = 9; /* shift right 9 bits to get bn */ 482 } else { 483 pmp->pm_brbomask = 0x03ff; 484 pmp->pm_bnshift = 10; 485 } 486 #else 487 pmp->pm_brbomask = 0x01ff; /* 512 byte blocks only (so far) */ 488 pmp->pm_bnshift = 9; /* shift right 9 bits to get bn */ 489 #endif 490 491 /* 492 * Release the bootsector buffer. 493 */ 494 brelse(bp0); 495 bp0 = NULL; 496 497 /* 498 * Allocate memory for the bitmap of allocated clusters, and then 499 * fill it in. 500 */ 501 pmp->pm_inusemap = malloc(((pmp->pm_maxcluster + N_INUSEBITS - 1) 502 / N_INUSEBITS) 503 * sizeof(*pmp->pm_inusemap), 504 M_MSDOSFSFAT, M_WAITOK); 505 506 /* 507 * fillinusemap() needs pm_devvp. 508 */ 509 pmp->pm_dev = dev; 510 pmp->pm_devvp = devvp; 511 512 /* 513 * Have the inuse map filled in. 514 */ 515 error = fillinusemap(pmp); 516 if (error) 517 goto error_exit; 518 519 /* 520 * If they want fat updates to be synchronous then let them suffer 521 * the performance degradation in exchange for the on disk copy of 522 * the fat being correct just about all the time. I suppose this 523 * would be a good thing to turn on if the kernel is still flakey. 524 */ 525 pmp->pm_waitonfat = mp->mnt_flag & MNT_SYNCHRONOUS; 526 527 /* 528 * Finish up. 529 */ 530 pmp->pm_ronly = ronly; 531 if (ronly == 0) 532 pmp->pm_fmod = 1; 533 mp->mnt_data = (qaddr_t) pmp; 534 mp->mnt_stat.f_fsid.val[0] = (long)dev; 535 mp->mnt_stat.f_fsid.val[1] = MOUNT_MSDOS; 536 mp->mnt_flag |= MNT_LOCAL; 537 devvp->v_specflags |= SI_MOUNTEDON; 538 539 return 0; 540 541 error_exit:; 542 if (bp0) 543 brelse(bp0); 544 if (needclose) 545 (void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD | FWRITE, 546 NOCRED, p); 547 if (pmp) { 548 if (pmp->pm_inusemap) 549 free((caddr_t) pmp->pm_inusemap, M_MSDOSFSFAT); 550 free((caddr_t) pmp, M_MSDOSFSMNT); 551 mp->mnt_data = (qaddr_t) 0; 552 } 553 return error; 554 } 555 556 static int 557 msdosfs_start(mp, flags, p) 558 struct mount *mp; 559 int flags; 560 struct proc *p; 561 { 562 return 0; 563 } 564 565 /* 566 * Unmount the filesystem described by mp. 567 */ 568 static int 569 msdosfs_unmount(mp, mntflags, p) 570 struct mount *mp; 571 int mntflags; 572 struct proc *p; 573 { 574 int flags = 0; 575 int error; 576 struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data; 577 578 /* only the mounter, or superuser can unmount */ 579 if ((p->p_cred->p_ruid != pmp->pm_mounter) && 580 (error = suser(p->p_ucred, &p->p_acflag))) 581 return error; 582 583 if (mntflags & MNT_FORCE) { 584 if (!msdosfsdoforce) 585 return EINVAL; 586 flags |= FORCECLOSE; 587 } 588 error = vflush(mp, NULLVP, flags); 589 if (error) 590 return error; 591 pmp->pm_devvp->v_specflags &= ~SI_MOUNTEDON; 592 error = VOP_CLOSE(pmp->pm_devvp, pmp->pm_ronly ? FREAD : FREAD | FWRITE, 593 NOCRED, p); 594 vrele(pmp->pm_devvp); 595 free((caddr_t) pmp->pm_inusemap, M_MSDOSFSFAT); 596 free((caddr_t) pmp, M_MSDOSFSMNT); 597 mp->mnt_data = (qaddr_t) 0; 598 mp->mnt_flag &= ~MNT_LOCAL; 599 return error; 600 } 601 602 static int 603 msdosfs_root(mp, vpp) 604 struct mount *mp; 605 struct vnode **vpp; 606 { 607 struct denode *ndep; 608 struct msdosfsmount *pmp = (struct msdosfsmount *) (mp->mnt_data); 609 int error; 610 611 error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, NULL, &ndep); 612 #ifdef MSDOSFS_DEBUG 613 printf("msdosfs_root(); mp %p, pmp %p, ndep %p, vp %p\n", 614 mp, pmp, ndep, DETOV(ndep)); 615 #endif 616 if (error == 0) 617 *vpp = DETOV(ndep); 618 return error; 619 } 620 621 static int 622 msdosfs_quotactl(mp, cmds, uid, arg, p) 623 struct mount *mp; 624 int cmds; 625 uid_t uid; 626 caddr_t arg; 627 struct proc *p; 628 { 629 return EOPNOTSUPP; 630 } 631 632 static int 633 msdosfs_statfs(mp, sbp, p) 634 struct mount *mp; 635 struct statfs *sbp; 636 struct proc *p; 637 { 638 struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data; 639 640 /* 641 * Fill in the stat block. 642 */ 643 sbp->f_type = MOUNT_MSDOS; 644 sbp->f_bsize = pmp->pm_bpcluster; 645 sbp->f_iosize = pmp->pm_bpcluster; 646 sbp->f_blocks = pmp->pm_nmbrofclusters; 647 sbp->f_bfree = pmp->pm_freeclustercount; 648 sbp->f_bavail = pmp->pm_freeclustercount; 649 sbp->f_files = pmp->pm_RootDirEnts; /* XXX */ 650 sbp->f_ffree = 0; /* what to put in here? */ 651 652 /* 653 * Copy the mounted on and mounted from names into the passed in 654 * stat block, if it is not the one in the mount structure. 655 */ 656 if (sbp != &mp->mnt_stat) { 657 bcopy((caddr_t) mp->mnt_stat.f_mntonname, 658 (caddr_t) & sbp->f_mntonname[0], MNAMELEN); 659 bcopy((caddr_t) mp->mnt_stat.f_mntfromname, 660 (caddr_t) & sbp->f_mntfromname[0], MNAMELEN); 661 } 662 #if 0 663 strncpy(&sbp->f_fstypename[0], mp->mnt_op->vfs_name, MFSNAMELEN); 664 sbp->f_fstypename[MFSNAMELEN] = '\0'; 665 #endif 666 return 0; 667 } 668 669 static int 670 msdosfs_sync(mp, waitfor, cred, p) 671 struct mount *mp; 672 int waitfor; 673 struct ucred *cred; 674 struct proc *p; 675 { 676 struct vnode *vp; 677 struct denode *dep; 678 struct msdosfsmount *pmp; 679 int error; 680 int allerror = 0; 681 682 pmp = (struct msdosfsmount *) mp->mnt_data; 683 684 /* 685 * If we ever switch to not updating all of the fats all the time, 686 * this would be the place to update them from the first one. 687 */ 688 if (pmp->pm_fmod) 689 if (pmp->pm_ronly) 690 panic("msdosfs_sync: rofs mod"); 691 else { 692 /* update fats here */ 693 } 694 695 /* 696 * Go thru in memory denodes and write them out along with 697 * unwritten file blocks. 698 */ 699 loop: 700 for (vp = mp->mnt_vnodelist.lh_first; vp; 701 vp = vp->v_mntvnodes.le_next) { 702 if (vp->v_mount != mp) /* not ours anymore */ 703 goto loop; 704 if (VOP_ISLOCKED(vp)) /* file is busy */ 705 continue; 706 dep = VTODE(vp); 707 if ((dep->de_flag & (DE_MODIFIED | DE_UPDATE)) == 0 && 708 vp->v_dirtyblkhd.lh_first == NULL) 709 continue; 710 if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p)) /* not there anymore? */ 711 goto loop; 712 error = VOP_FSYNC(vp, cred, waitfor, p); 713 if (error) 714 allerror = error; 715 vput(vp); /* done with this one */ 716 } 717 718 /* 719 * Flush filesystem control info. 720 */ 721 error = VOP_FSYNC(pmp->pm_devvp, cred, waitfor, p); 722 if (error) 723 allerror = error; 724 return allerror; 725 } 726 727 static int 728 msdosfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp) 729 struct mount *mp; 730 struct fid *fhp; 731 struct mbuf *nam; 732 struct vnode **vpp; 733 int *exflagsp; 734 struct ucred **credanonp; 735 { 736 struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data; 737 struct defid *defhp = (struct defid *) fhp; 738 struct denode *dep; 739 struct netcred *np; 740 int error; 741 742 np = vfs_export_lookup(mp, &pmp->pm_export, nam); 743 if (np == NULL) 744 return EACCES; 745 error = deget(pmp, defhp->defid_dirclust, defhp->defid_dirofs, 746 NULL, &dep); 747 if (error) { 748 *vpp = NULLVP; 749 return error; 750 } 751 *vpp = DETOV(dep); 752 *exflagsp = np->netc_exflags; 753 *credanonp = &np->netc_anon; 754 return 0; 755 } 756 757 758 static int 759 msdosfs_vptofh(vp, fhp) 760 struct vnode *vp; 761 struct fid *fhp; 762 { 763 struct denode *dep = VTODE(vp); 764 struct defid *defhp = (struct defid *) fhp; 765 766 defhp->defid_len = sizeof(struct defid); 767 defhp->defid_dirclust = dep->de_dirclust; 768 defhp->defid_dirofs = dep->de_diroffset; 769 /* defhp->defid_gen = ip->i_gen; */ 770 return 0; 771 } 772 773 static int 774 msdosfs_vget(mp, ino, vpp) 775 struct mount *mp; 776 ino_t ino; 777 struct vnode **vpp; 778 { 779 return EOPNOTSUPP; 780 } 781 782 static struct vfsops msdosfs_vfsops = { 783 msdosfs_mount, 784 msdosfs_start, 785 msdosfs_unmount, 786 msdosfs_root, 787 msdosfs_quotactl, 788 msdosfs_statfs, 789 msdosfs_sync, 790 msdosfs_vget, 791 msdosfs_fhtovp, 792 msdosfs_vptofh, 793 msdosfs_init 794 }; 795 796 VFS_SET(msdosfs_vfsops, msdos, MOUNT_MSDOS, 0); 797