1 /* $OpenBSD: msdosfs_vfsops.c,v 1.12 2019/09/04 14:40:22 cheloha Exp $ */ 2 3 /*- 4 * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank. 5 * Copyright (C) 1994, 1995, 1997 TooLs GmbH. 6 * All rights reserved. 7 * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by TooLs GmbH. 20 * 4. The name of TooLs GmbH may not be used to endorse or promote products 21 * derived from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 28 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 29 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 31 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 32 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 /* 35 * Written by Paul Popelka (paulp@uts.amdahl.com) 36 * 37 * You can do anything you want with this software, just don't say you wrote 38 * it, and don't remove this notice. 39 * 40 * This software is provided "as is". 41 * 42 * The author supplies this software to be publicly redistributed on the 43 * understanding that the author is not responsible for the correct 44 * functioning of this software in any circumstances and is not liable for 45 * any damages caused by this software. 46 * 47 * October 1992 48 */ 49 50 #include <sys/param.h> 51 52 #include "ffs/buf.h" 53 54 #include <msdosfs/bpb.h> 55 #include <msdosfs/bootsect.h> 56 #include "msdos/direntry.h" 57 #include "msdos/denode.h" 58 #include "msdos/msdosfsmount.h" 59 #include "msdos/fat.h" 60 61 #include <stdio.h> 62 #include <errno.h> 63 #include <stdlib.h> 64 #include <string.h> 65 #include <util.h> 66 67 #include "makefs.h" 68 #include "msdos.h" 69 #include "msdos/mkfs_msdos.h" 70 71 #ifdef MSDOSFS_DEBUG 72 #define DPRINTF(a) printf a 73 #else 74 #define DPRINTF(a) 75 #endif 76 77 struct msdosfsmount * 78 msdosfs_mount(struct mkfsvnode *devvp, int flags) 79 { 80 struct msdosfsmount *pmp = NULL; 81 struct mkfsbuf *bp; 82 union bootsector *bsp; 83 struct byte_bpb33 *b33; 84 struct byte_bpb50 *b50; 85 struct byte_bpb710 *b710; 86 uint8_t SecPerClust; 87 int ronly = 0, error; 88 int bsize; 89 unsigned secsize = 512; 90 91 DPRINTF(("%s(bread 0)\n", __func__)); 92 if ((error = bread(devvp, 0, secsize, 0, &bp)) != 0) 93 goto error_exit; 94 95 bsp = (union bootsector *)bp->b_data; 96 b33 = (struct byte_bpb33 *)bsp->bs33.bsBPB; 97 b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB; 98 b710 = (struct byte_bpb710 *)bsp->bs710.bsBPB; 99 100 if (bsp->bs50.bsBootSectSig0 != BOOTSIG0 101 || bsp->bs50.bsBootSectSig1 != BOOTSIG1) { 102 DPRINTF(("bootsig0 %d bootsig1 %d\n", 103 bsp->bs50.bsBootSectSig0, 104 bsp->bs50.bsBootSectSig1)); 105 error = EINVAL; 106 goto error_exit; 107 } 108 bsize = 0; 109 110 pmp = ecalloc(1, sizeof *pmp); 111 /* 112 * Compute several useful quantities from the bpb in the 113 * bootsector. Copy in the dos 5 variant of the bpb then fix up 114 * the fields that are different between dos 5 and dos 3.3. 115 */ 116 SecPerClust = b50->bpbSecPerClust; 117 pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec); 118 pmp->pm_ResSectors = getushort(b50->bpbResSectors); 119 pmp->pm_FATs = b50->bpbFATs; 120 pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts); 121 pmp->pm_Sectors = getushort(b50->bpbSectors); 122 pmp->pm_FATsecs = getushort(b50->bpbFATsecs); 123 pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack); 124 pmp->pm_Heads = getushort(b50->bpbHeads); 125 pmp->pm_Media = b50->bpbMedia; 126 pmp->pm_minuteswest = 0; 127 128 DPRINTF(("%s(BytesPerSec=%u, ResSectors=%u, FATs=%d, RootDirEnts=%u, " 129 "Sectors=%u, FATsecs=%lu, SecPerTrack=%u, Heads=%u, Media=%u)\n", 130 __func__, pmp->pm_BytesPerSec, pmp->pm_ResSectors, pmp->pm_FATs, 131 pmp->pm_RootDirEnts, pmp->pm_Sectors, pmp->pm_FATsecs, 132 pmp->pm_SecPerTrack, pmp->pm_Heads, pmp->pm_Media)); 133 /* XXX - We should probably check more values here */ 134 if (!pmp->pm_BytesPerSec || !SecPerClust 135 || pmp->pm_SecPerTrack > 63) { 136 DPRINTF(("bytespersec %d secperclust %d " 137 "secpertrack %d\n", 138 pmp->pm_BytesPerSec, SecPerClust, 139 pmp->pm_SecPerTrack)); 140 error = EINVAL; 141 goto error_exit; 142 } 143 144 pmp->pm_flags = flags & MSDOSFSMNT_MNTOPT; 145 if (pmp->pm_flags & MSDOSFSMNT_NOWIN95) 146 pmp->pm_flags |= MSDOSFSMNT_SHORTNAME; 147 148 if (pmp->pm_Sectors == 0) { 149 pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs); 150 pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors); 151 } else { 152 pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs); 153 pmp->pm_HugeSectors = pmp->pm_Sectors; 154 } 155 156 if (pmp->pm_RootDirEnts == 0) { 157 unsigned short vers = getushort(b710->bpbFSVers); 158 /* 159 * Some say that bsBootSectSig[23] must be zero, but 160 * Windows does not require this and some digital cameras 161 * do not set these to zero. Therefore, do not insist. 162 */ 163 if (pmp->pm_Sectors || pmp->pm_FATsecs || vers) { 164 DPRINTF(("sectors %d fatsecs %lu vers %d\n", 165 pmp->pm_Sectors, pmp->pm_FATsecs, vers)); 166 error = EINVAL; 167 goto error_exit; 168 } 169 pmp->pm_fatmask = FAT32_MASK; 170 pmp->pm_fatmult = 4; 171 pmp->pm_fatdiv = 1; 172 pmp->pm_FATsecs = getulong(b710->bpbBigFATsecs); 173 174 /* mirrorring is enabled if the FATMIRROR bit is not set */ 175 if ((getushort(b710->bpbExtFlags) & FATMIRROR) == 0) 176 pmp->pm_flags |= MSDOSFS_FATMIRROR; 177 else 178 pmp->pm_curfat = getushort(b710->bpbExtFlags) & FATNUM; 179 } else 180 pmp->pm_flags |= MSDOSFS_FATMIRROR; 181 182 /* Check that fs has nonzero FAT size */ 183 if (pmp->pm_FATsecs == 0) { 184 DPRINTF(("FATsecs is 0\n")); 185 error = EINVAL; 186 goto error_exit; 187 } 188 189 pmp->pm_fatblk = pmp->pm_ResSectors; 190 if (FAT32(pmp)) { 191 pmp->pm_rootdirblk = getulong(b710->bpbRootClust); 192 pmp->pm_firstcluster = pmp->pm_fatblk 193 + (pmp->pm_FATs * pmp->pm_FATsecs); 194 pmp->pm_fsinfo = getushort(b710->bpbFSInfo); 195 } else { 196 pmp->pm_rootdirblk = pmp->pm_fatblk + 197 (pmp->pm_FATs * pmp->pm_FATsecs); 198 pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry) 199 + pmp->pm_BytesPerSec - 1) 200 / pmp->pm_BytesPerSec;/* in sectors */ 201 pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize; 202 } 203 204 pmp->pm_nmbrofclusters = (pmp->pm_HugeSectors - pmp->pm_firstcluster) / 205 SecPerClust; 206 pmp->pm_maxcluster = pmp->pm_nmbrofclusters + 1; 207 pmp->pm_fatsize = pmp->pm_FATsecs * pmp->pm_BytesPerSec; 208 209 if (pmp->pm_fatmask == 0) { 210 if (pmp->pm_maxcluster 211 <= ((CLUST_RSRVD - CLUST_FIRST) & FAT12_MASK)) { 212 /* 213 * This will usually be a floppy disk. This size makes 214 * sure that one FAT entry will not be split across 215 * multiple blocks. 216 */ 217 pmp->pm_fatmask = FAT12_MASK; 218 pmp->pm_fatmult = 3; 219 pmp->pm_fatdiv = 2; 220 } else { 221 pmp->pm_fatmask = FAT16_MASK; 222 pmp->pm_fatmult = 2; 223 pmp->pm_fatdiv = 1; 224 } 225 } 226 if (FAT12(pmp)) 227 pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec; 228 else 229 pmp->pm_fatblocksize = MAXBSIZE; 230 231 pmp->pm_fatblocksec = pmp->pm_fatblocksize / pmp->pm_BytesPerSec; 232 pmp->pm_bnshift = ffs(pmp->pm_BytesPerSec) - 1; 233 234 /* 235 * Compute mask and shift value for isolating cluster relative byte 236 * offsets and cluster numbers from a file offset. 237 */ 238 pmp->pm_bpcluster = SecPerClust * pmp->pm_BytesPerSec; 239 pmp->pm_crbomask = pmp->pm_bpcluster - 1; 240 pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1; 241 242 DPRINTF(("%s(fatmask=%lu, fatmult=%u, fatdiv=%u, fatblocksize=%lu, " 243 "fatblocksec=%lu, bnshift=%lu, pbcluster=%lu, crbomask=%lu, " 244 "cnshift=%lu)\n", 245 __func__, pmp->pm_fatmask, pmp->pm_fatmult, pmp->pm_fatdiv, 246 pmp->pm_fatblocksize, pmp->pm_fatblocksec, pmp->pm_bnshift, 247 pmp->pm_bpcluster, pmp->pm_crbomask, pmp->pm_cnshift)); 248 /* 249 * Check for valid cluster size 250 * must be a power of 2 251 */ 252 if (pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) { 253 DPRINTF(("bpcluster %lu cnshift %lu\n", 254 pmp->pm_bpcluster, pmp->pm_cnshift)); 255 error = EINVAL; 256 goto error_exit; 257 } 258 259 /* 260 * Release the bootsector buffer. 261 */ 262 brelse(bp, BC_AGE); 263 bp = NULL; 264 265 /* 266 * Check FSInfo. 267 */ 268 if (pmp->pm_fsinfo) { 269 struct fsinfo *fp; 270 271 /* 272 * XXX If the fsinfo block is stored on media with 273 * 2KB or larger sectors, is the fsinfo structure 274 * padded at the end or in the middle? 275 */ 276 DPRINTF(("%s(bread %lu)\n", __func__, 277 (unsigned long)de_bn2kb(pmp, pmp->pm_fsinfo))); 278 if ((error = bread(devvp, de_bn2kb(pmp, pmp->pm_fsinfo), 279 pmp->pm_BytesPerSec, 0, &bp)) != 0) 280 goto error_exit; 281 fp = (struct fsinfo *)bp->b_data; 282 if (!memcmp(fp->fsisig1, "RRaA", 4) 283 && !memcmp(fp->fsisig2, "rrAa", 4) 284 && !memcmp(fp->fsisig3, "\0\0\125\252", 4) 285 && !memcmp(fp->fsisig4, "\0\0\125\252", 4)) 286 pmp->pm_nxtfree = getulong(fp->fsinxtfree); 287 else 288 pmp->pm_fsinfo = 0; 289 brelse(bp, 0); 290 bp = NULL; 291 } 292 293 /* 294 * Check and validate (or perhaps invalidate?) the fsinfo structure? 295 * XXX 296 */ 297 if (pmp->pm_fsinfo) { 298 if ((pmp->pm_nxtfree == 0xffffffffUL) || 299 (pmp->pm_nxtfree > pmp->pm_maxcluster)) 300 pmp->pm_fsinfo = 0; 301 } 302 303 /* 304 * Allocate memory for the bitmap of allocated clusters, and then 305 * fill it in. 306 */ 307 pmp->pm_inusemap = ecalloc(sizeof(*pmp->pm_inusemap), 308 ((pmp->pm_maxcluster + N_INUSEBITS) / N_INUSEBITS)); 309 /* 310 * fillinusemap() needs pm_devvp. 311 */ 312 pmp->pm_dev = 0; 313 pmp->pm_devvp = devvp; 314 315 /* 316 * Have the inuse map filled in. 317 */ 318 if ((error = fillinusemap(pmp)) != 0) { 319 DPRINTF(("fillinusemap %d\n", error)); 320 goto error_exit; 321 } 322 323 /* 324 * Finish up. 325 */ 326 if (ronly) 327 pmp->pm_flags |= MSDOSFSMNT_RONLY; 328 else 329 pmp->pm_fmod = 1; 330 331 return pmp; 332 333 error_exit: 334 if (bp) 335 brelse(bp, BC_AGE); 336 if (pmp) { 337 if (pmp->pm_inusemap) 338 free(pmp->pm_inusemap); 339 free(pmp); 340 } 341 errno = error; 342 return NULL; 343 } 344 345 int 346 msdosfs_root(struct msdosfsmount *pmp, struct mkfsvnode *vp) { 347 struct denode *ndep; 348 int error; 349 350 *vp = *pmp->pm_devvp; 351 if ((error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, &ndep)) != 0) { 352 errno = error; 353 return -1; 354 } 355 vp->v_data = ndep; 356 return 0; 357 } 358