GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/makefs/msdos/msdosfs_vfsops.c Lines: 0 129 0.0 %
Date: 2017-11-07 Branches: 0 74 0.0 %

Line Branch Exec Source
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
}