1 |
|
|
/* $OpenBSD: msdosfs_vfsops.c,v 1.11 2016/12/17 16:43:30 krw 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 |
|
|
#include <sys/time.h> |
52 |
|
|
|
53 |
|
|
#include "ffs/buf.h" |
54 |
|
|
|
55 |
|
|
#include <msdosfs/bpb.h> |
56 |
|
|
#include <msdosfs/bootsect.h> |
57 |
|
|
#include "msdos/direntry.h" |
58 |
|
|
#include "msdos/denode.h" |
59 |
|
|
#include "msdos/msdosfsmount.h" |
60 |
|
|
#include "msdos/fat.h" |
61 |
|
|
|
62 |
|
|
#include <stdio.h> |
63 |
|
|
#include <errno.h> |
64 |
|
|
#include <stdlib.h> |
65 |
|
|
#include <string.h> |
66 |
|
|
#include <util.h> |
67 |
|
|
|
68 |
|
|
#include "makefs.h" |
69 |
|
|
#include "msdos.h" |
70 |
|
|
#include "msdos/mkfs_msdos.h" |
71 |
|
|
|
72 |
|
|
#ifdef MSDOSFS_DEBUG |
73 |
|
|
#define DPRINTF(a) printf a |
74 |
|
|
#else |
75 |
|
|
#define DPRINTF(a) |
76 |
|
|
#endif |
77 |
|
|
|
78 |
|
|
struct msdosfsmount * |
79 |
|
|
msdosfs_mount(struct mkfsvnode *devvp, int flags) |
80 |
|
|
{ |
81 |
|
|
struct msdosfsmount *pmp = NULL; |
82 |
|
|
struct mkfsbuf *bp; |
83 |
|
|
union bootsector *bsp; |
84 |
|
|
struct byte_bpb33 *b33; |
85 |
|
|
struct byte_bpb50 *b50; |
86 |
|
|
struct byte_bpb710 *b710; |
87 |
|
|
uint8_t SecPerClust; |
88 |
|
|
int ronly = 0, error; |
89 |
|
|
int bsize; |
90 |
|
|
struct timezone tz; |
91 |
|
|
unsigned secsize = 512; |
92 |
|
|
|
93 |
|
|
DPRINTF(("%s(bread 0)\n", __func__)); |
94 |
|
|
if ((error = bread(devvp, 0, secsize, 0, &bp)) != 0) |
95 |
|
|
goto error_exit; |
96 |
|
|
|
97 |
|
|
bsp = (union bootsector *)bp->b_data; |
98 |
|
|
b33 = (struct byte_bpb33 *)bsp->bs33.bsBPB; |
99 |
|
|
b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB; |
100 |
|
|
b710 = (struct byte_bpb710 *)bsp->bs710.bsBPB; |
101 |
|
|
|
102 |
|
|
if (bsp->bs50.bsBootSectSig0 != BOOTSIG0 |
103 |
|
|
|| bsp->bs50.bsBootSectSig1 != BOOTSIG1) { |
104 |
|
|
DPRINTF(("bootsig0 %d bootsig1 %d\n", |
105 |
|
|
bsp->bs50.bsBootSectSig0, |
106 |
|
|
bsp->bs50.bsBootSectSig1)); |
107 |
|
|
error = EINVAL; |
108 |
|
|
goto error_exit; |
109 |
|
|
} |
110 |
|
|
bsize = 0; |
111 |
|
|
|
112 |
|
|
pmp = ecalloc(1, sizeof *pmp); |
113 |
|
|
/* |
114 |
|
|
* Compute several useful quantities from the bpb in the |
115 |
|
|
* bootsector. Copy in the dos 5 variant of the bpb then fix up |
116 |
|
|
* the fields that are different between dos 5 and dos 3.3. |
117 |
|
|
*/ |
118 |
|
|
SecPerClust = b50->bpbSecPerClust; |
119 |
|
|
pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec); |
120 |
|
|
pmp->pm_ResSectors = getushort(b50->bpbResSectors); |
121 |
|
|
pmp->pm_FATs = b50->bpbFATs; |
122 |
|
|
pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts); |
123 |
|
|
pmp->pm_Sectors = getushort(b50->bpbSectors); |
124 |
|
|
pmp->pm_FATsecs = getushort(b50->bpbFATsecs); |
125 |
|
|
pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack); |
126 |
|
|
pmp->pm_Heads = getushort(b50->bpbHeads); |
127 |
|
|
pmp->pm_Media = b50->bpbMedia; |
128 |
|
|
|
129 |
|
|
if (gettimeofday(NULL, &tz) == -1) { |
130 |
|
|
error = errno; |
131 |
|
|
goto error_exit; |
132 |
|
|
} |
133 |
|
|
pmp->pm_minuteswest = tz.tz_minuteswest; |
134 |
|
|
|
135 |
|
|
DPRINTF(("%s(BytesPerSec=%u, ResSectors=%u, FATs=%d, RootDirEnts=%u, " |
136 |
|
|
"Sectors=%u, FATsecs=%lu, SecPerTrack=%u, Heads=%u, Media=%u)\n", |
137 |
|
|
__func__, pmp->pm_BytesPerSec, pmp->pm_ResSectors, pmp->pm_FATs, |
138 |
|
|
pmp->pm_RootDirEnts, pmp->pm_Sectors, pmp->pm_FATsecs, |
139 |
|
|
pmp->pm_SecPerTrack, pmp->pm_Heads, pmp->pm_Media)); |
140 |
|
|
/* XXX - We should probably check more values here */ |
141 |
|
|
if (!pmp->pm_BytesPerSec || !SecPerClust |
142 |
|
|
|| pmp->pm_SecPerTrack > 63) { |
143 |
|
|
DPRINTF(("bytespersec %d secperclust %d " |
144 |
|
|
"secpertrack %d\n", |
145 |
|
|
pmp->pm_BytesPerSec, SecPerClust, |
146 |
|
|
pmp->pm_SecPerTrack)); |
147 |
|
|
error = EINVAL; |
148 |
|
|
goto error_exit; |
149 |
|
|
} |
150 |
|
|
|
151 |
|
|
pmp->pm_flags = flags & MSDOSFSMNT_MNTOPT; |
152 |
|
|
if (pmp->pm_flags & MSDOSFSMNT_NOWIN95) |
153 |
|
|
pmp->pm_flags |= MSDOSFSMNT_SHORTNAME; |
154 |
|
|
|
155 |
|
|
if (pmp->pm_Sectors == 0) { |
156 |
|
|
pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs); |
157 |
|
|
pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors); |
158 |
|
|
} else { |
159 |
|
|
pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs); |
160 |
|
|
pmp->pm_HugeSectors = pmp->pm_Sectors; |
161 |
|
|
} |
162 |
|
|
|
163 |
|
|
if (pmp->pm_RootDirEnts == 0) { |
164 |
|
|
unsigned short vers = getushort(b710->bpbFSVers); |
165 |
|
|
/* |
166 |
|
|
* Some say that bsBootSectSig[23] must be zero, but |
167 |
|
|
* Windows does not require this and some digital cameras |
168 |
|
|
* do not set these to zero. Therefore, do not insist. |
169 |
|
|
*/ |
170 |
|
|
if (pmp->pm_Sectors || pmp->pm_FATsecs || vers) { |
171 |
|
|
DPRINTF(("sectors %d fatsecs %lu vers %d\n", |
172 |
|
|
pmp->pm_Sectors, pmp->pm_FATsecs, vers)); |
173 |
|
|
error = EINVAL; |
174 |
|
|
goto error_exit; |
175 |
|
|
} |
176 |
|
|
pmp->pm_fatmask = FAT32_MASK; |
177 |
|
|
pmp->pm_fatmult = 4; |
178 |
|
|
pmp->pm_fatdiv = 1; |
179 |
|
|
pmp->pm_FATsecs = getulong(b710->bpbBigFATsecs); |
180 |
|
|
|
181 |
|
|
/* mirrorring is enabled if the FATMIRROR bit is not set */ |
182 |
|
|
if ((getushort(b710->bpbExtFlags) & FATMIRROR) == 0) |
183 |
|
|
pmp->pm_flags |= MSDOSFS_FATMIRROR; |
184 |
|
|
else |
185 |
|
|
pmp->pm_curfat = getushort(b710->bpbExtFlags) & FATNUM; |
186 |
|
|
} else |
187 |
|
|
pmp->pm_flags |= MSDOSFS_FATMIRROR; |
188 |
|
|
|
189 |
|
|
/* Check that fs has nonzero FAT size */ |
190 |
|
|
if (pmp->pm_FATsecs == 0) { |
191 |
|
|
DPRINTF(("FATsecs is 0\n")); |
192 |
|
|
error = EINVAL; |
193 |
|
|
goto error_exit; |
194 |
|
|
} |
195 |
|
|
|
196 |
|
|
pmp->pm_fatblk = pmp->pm_ResSectors; |
197 |
|
|
if (FAT32(pmp)) { |
198 |
|
|
pmp->pm_rootdirblk = getulong(b710->bpbRootClust); |
199 |
|
|
pmp->pm_firstcluster = pmp->pm_fatblk |
200 |
|
|
+ (pmp->pm_FATs * pmp->pm_FATsecs); |
201 |
|
|
pmp->pm_fsinfo = getushort(b710->bpbFSInfo); |
202 |
|
|
} else { |
203 |
|
|
pmp->pm_rootdirblk = pmp->pm_fatblk + |
204 |
|
|
(pmp->pm_FATs * pmp->pm_FATsecs); |
205 |
|
|
pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry) |
206 |
|
|
+ pmp->pm_BytesPerSec - 1) |
207 |
|
|
/ pmp->pm_BytesPerSec;/* in sectors */ |
208 |
|
|
pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize; |
209 |
|
|
} |
210 |
|
|
|
211 |
|
|
pmp->pm_nmbrofclusters = (pmp->pm_HugeSectors - pmp->pm_firstcluster) / |
212 |
|
|
SecPerClust; |
213 |
|
|
pmp->pm_maxcluster = pmp->pm_nmbrofclusters + 1; |
214 |
|
|
pmp->pm_fatsize = pmp->pm_FATsecs * pmp->pm_BytesPerSec; |
215 |
|
|
|
216 |
|
|
if (pmp->pm_fatmask == 0) { |
217 |
|
|
if (pmp->pm_maxcluster |
218 |
|
|
<= ((CLUST_RSRVD - CLUST_FIRST) & FAT12_MASK)) { |
219 |
|
|
/* |
220 |
|
|
* This will usually be a floppy disk. This size makes |
221 |
|
|
* sure that one FAT entry will not be split across |
222 |
|
|
* multiple blocks. |
223 |
|
|
*/ |
224 |
|
|
pmp->pm_fatmask = FAT12_MASK; |
225 |
|
|
pmp->pm_fatmult = 3; |
226 |
|
|
pmp->pm_fatdiv = 2; |
227 |
|
|
} else { |
228 |
|
|
pmp->pm_fatmask = FAT16_MASK; |
229 |
|
|
pmp->pm_fatmult = 2; |
230 |
|
|
pmp->pm_fatdiv = 1; |
231 |
|
|
} |
232 |
|
|
} |
233 |
|
|
if (FAT12(pmp)) |
234 |
|
|
pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec; |
235 |
|
|
else |
236 |
|
|
pmp->pm_fatblocksize = MAXBSIZE; |
237 |
|
|
|
238 |
|
|
pmp->pm_fatblocksec = pmp->pm_fatblocksize / pmp->pm_BytesPerSec; |
239 |
|
|
pmp->pm_bnshift = ffs(pmp->pm_BytesPerSec) - 1; |
240 |
|
|
|
241 |
|
|
/* |
242 |
|
|
* Compute mask and shift value for isolating cluster relative byte |
243 |
|
|
* offsets and cluster numbers from a file offset. |
244 |
|
|
*/ |
245 |
|
|
pmp->pm_bpcluster = SecPerClust * pmp->pm_BytesPerSec; |
246 |
|
|
pmp->pm_crbomask = pmp->pm_bpcluster - 1; |
247 |
|
|
pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1; |
248 |
|
|
|
249 |
|
|
DPRINTF(("%s(fatmask=%lu, fatmult=%u, fatdiv=%u, fatblocksize=%lu, " |
250 |
|
|
"fatblocksec=%lu, bnshift=%lu, pbcluster=%lu, crbomask=%lu, " |
251 |
|
|
"cnshift=%lu)\n", |
252 |
|
|
__func__, pmp->pm_fatmask, pmp->pm_fatmult, pmp->pm_fatdiv, |
253 |
|
|
pmp->pm_fatblocksize, pmp->pm_fatblocksec, pmp->pm_bnshift, |
254 |
|
|
pmp->pm_bpcluster, pmp->pm_crbomask, pmp->pm_cnshift)); |
255 |
|
|
/* |
256 |
|
|
* Check for valid cluster size |
257 |
|
|
* must be a power of 2 |
258 |
|
|
*/ |
259 |
|
|
if (pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) { |
260 |
|
|
DPRINTF(("bpcluster %lu cnshift %lu\n", |
261 |
|
|
pmp->pm_bpcluster, pmp->pm_cnshift)); |
262 |
|
|
error = EINVAL; |
263 |
|
|
goto error_exit; |
264 |
|
|
} |
265 |
|
|
|
266 |
|
|
/* |
267 |
|
|
* Release the bootsector buffer. |
268 |
|
|
*/ |
269 |
|
|
brelse(bp, BC_AGE); |
270 |
|
|
bp = NULL; |
271 |
|
|
|
272 |
|
|
/* |
273 |
|
|
* Check FSInfo. |
274 |
|
|
*/ |
275 |
|
|
if (pmp->pm_fsinfo) { |
276 |
|
|
struct fsinfo *fp; |
277 |
|
|
|
278 |
|
|
/* |
279 |
|
|
* XXX If the fsinfo block is stored on media with |
280 |
|
|
* 2KB or larger sectors, is the fsinfo structure |
281 |
|
|
* padded at the end or in the middle? |
282 |
|
|
*/ |
283 |
|
|
DPRINTF(("%s(bread %lu)\n", __func__, |
284 |
|
|
(unsigned long)de_bn2kb(pmp, pmp->pm_fsinfo))); |
285 |
|
|
if ((error = bread(devvp, de_bn2kb(pmp, pmp->pm_fsinfo), |
286 |
|
|
pmp->pm_BytesPerSec, 0, &bp)) != 0) |
287 |
|
|
goto error_exit; |
288 |
|
|
fp = (struct fsinfo *)bp->b_data; |
289 |
|
|
if (!memcmp(fp->fsisig1, "RRaA", 4) |
290 |
|
|
&& !memcmp(fp->fsisig2, "rrAa", 4) |
291 |
|
|
&& !memcmp(fp->fsisig3, "\0\0\125\252", 4) |
292 |
|
|
&& !memcmp(fp->fsisig4, "\0\0\125\252", 4)) |
293 |
|
|
pmp->pm_nxtfree = getulong(fp->fsinxtfree); |
294 |
|
|
else |
295 |
|
|
pmp->pm_fsinfo = 0; |
296 |
|
|
brelse(bp, 0); |
297 |
|
|
bp = NULL; |
298 |
|
|
} |
299 |
|
|
|
300 |
|
|
/* |
301 |
|
|
* Check and validate (or perhaps invalidate?) the fsinfo structure? |
302 |
|
|
* XXX |
303 |
|
|
*/ |
304 |
|
|
if (pmp->pm_fsinfo) { |
305 |
|
|
if ((pmp->pm_nxtfree == 0xffffffffUL) || |
306 |
|
|
(pmp->pm_nxtfree > pmp->pm_maxcluster)) |
307 |
|
|
pmp->pm_fsinfo = 0; |
308 |
|
|
} |
309 |
|
|
|
310 |
|
|
/* |
311 |
|
|
* Allocate memory for the bitmap of allocated clusters, and then |
312 |
|
|
* fill it in. |
313 |
|
|
*/ |
314 |
|
|
pmp->pm_inusemap = ecalloc(sizeof(*pmp->pm_inusemap), |
315 |
|
|
((pmp->pm_maxcluster + N_INUSEBITS) / N_INUSEBITS)); |
316 |
|
|
/* |
317 |
|
|
* fillinusemap() needs pm_devvp. |
318 |
|
|
*/ |
319 |
|
|
pmp->pm_dev = 0; |
320 |
|
|
pmp->pm_devvp = devvp; |
321 |
|
|
|
322 |
|
|
/* |
323 |
|
|
* Have the inuse map filled in. |
324 |
|
|
*/ |
325 |
|
|
if ((error = fillinusemap(pmp)) != 0) { |
326 |
|
|
DPRINTF(("fillinusemap %d\n", error)); |
327 |
|
|
goto error_exit; |
328 |
|
|
} |
329 |
|
|
|
330 |
|
|
/* |
331 |
|
|
* Finish up. |
332 |
|
|
*/ |
333 |
|
|
if (ronly) |
334 |
|
|
pmp->pm_flags |= MSDOSFSMNT_RONLY; |
335 |
|
|
else |
336 |
|
|
pmp->pm_fmod = 1; |
337 |
|
|
|
338 |
|
|
return pmp; |
339 |
|
|
|
340 |
|
|
error_exit: |
341 |
|
|
if (bp) |
342 |
|
|
brelse(bp, BC_AGE); |
343 |
|
|
if (pmp) { |
344 |
|
|
if (pmp->pm_inusemap) |
345 |
|
|
free(pmp->pm_inusemap); |
346 |
|
|
free(pmp); |
347 |
|
|
} |
348 |
|
|
errno = error; |
349 |
|
|
return NULL; |
350 |
|
|
} |
351 |
|
|
|
352 |
|
|
int |
353 |
|
|
msdosfs_root(struct msdosfsmount *pmp, struct mkfsvnode *vp) { |
354 |
|
|
struct denode *ndep; |
355 |
|
|
int error; |
356 |
|
|
|
357 |
|
|
*vp = *pmp->pm_devvp; |
358 |
|
|
if ((error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, &ndep)) != 0) { |
359 |
|
|
errno = error; |
360 |
|
|
return -1; |
361 |
|
|
} |
362 |
|
|
vp->v_data = ndep; |
363 |
|
|
return 0; |
364 |
|
|
} |