]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/makefs/msdos/msdosfs_vfsops.c
MFV 364467:
[FreeBSD/FreeBSD.git] / usr.sbin / makefs / msdos / msdosfs_vfsops.c
1 /*-
2  * SPDX-License-Identifier: BSD-4-Clause
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/cdefs.h>
51 /* $NetBSD: msdosfs_vfsops.c,v 1.10 2016/01/30 09:59:27 mlelstv Exp $ */
52 __FBSDID("$FreeBSD$");
53
54 #include <sys/param.h>
55 #include <sys/mount.h>
56
57 #include <errno.h>
58 #include <stdbool.h>
59 #include <stdio.h>
60 #include <string.h>
61 #include <stdlib.h>
62 #include <util.h>
63
64 #include "ffs/buf.h"
65 #include <fs/msdosfs/bootsect.h>
66 #include <fs/msdosfs/bpb.h>
67 #include "msdos/direntry.h"
68 #include <fs/msdosfs/denode.h>
69 #include <fs/msdosfs/fat.h>
70 #include <fs/msdosfs/msdosfsmount.h>
71
72 #include <mkfs_msdos.h>
73
74 #include "makefs.h"
75 #include "msdos.h"
76
77
78
79 struct msdosfsmount *
80 msdosfs_mount(struct vnode *devvp)
81 {
82         struct msdosfsmount *pmp = NULL;
83         struct buf *bp;
84         union bootsector *bsp;
85         struct byte_bpb33 *b33;
86         struct byte_bpb50 *b50;
87         struct byte_bpb710 *b710;
88         uint8_t SecPerClust;
89         int     ronly = 0, error;
90         int     bsize;
91         unsigned secsize = 512;
92
93         MSDOSFS_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                 MSDOSFS_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         MSDOSFS_DPRINTF(("%s(BytesPerSec=%u, ResSectors=%u, FATs=%d, "
130             "RootDirEnts=%u, Sectors=%u, FATsecs=%lu, SecPerTrack=%u, "
131             "Heads=%u, Media=%u)\n",
132             __func__, pmp->pm_BytesPerSec, pmp->pm_ResSectors,
133             pmp->pm_FATs, pmp->pm_RootDirEnts, pmp->pm_Sectors,
134             pmp->pm_FATsecs, pmp->pm_SecPerTrack, pmp->pm_Heads,
135             pmp->pm_Media));
136
137         /* XXX - We should probably check more values here */
138         if (!pmp->pm_BytesPerSec || !SecPerClust
139                 || pmp->pm_SecPerTrack > 63) {
140                 MSDOSFS_DPRINTF(("bytespersec %d secperclust %d "
141                     "secpertrack %d\n", pmp->pm_BytesPerSec,
142                     SecPerClust, pmp->pm_SecPerTrack));
143                 error = EINVAL;
144                 goto error_exit;
145         }
146
147         if (pmp->pm_Sectors == 0) {
148                 pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs);
149                 pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors);
150         } else {
151                 pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs);
152                 pmp->pm_HugeSectors = pmp->pm_Sectors;
153         }
154
155         pmp->pm_flags = 0;
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                         MSDOSFS_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                 MSDOSFS_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_maxcluster = ((pmp->pm_HugeSectors - pmp->pm_firstcluster) /
205             SecPerClust) + 1;
206         pmp->pm_fatsize = pmp->pm_FATsecs * pmp->pm_BytesPerSec;
207
208         if (pmp->pm_fatmask == 0) {
209                 if (pmp->pm_maxcluster
210                     <= ((CLUST_RSRVD - CLUST_FIRST) & FAT12_MASK)) {
211                         /*
212                          * This will usually be a floppy disk. This size makes
213                          * sure that one FAT entry will not be split across
214                          * multiple blocks.
215                          */
216                         pmp->pm_fatmask = FAT12_MASK;
217                         pmp->pm_fatmult = 3;
218                         pmp->pm_fatdiv = 2;
219                 } else {
220                         pmp->pm_fatmask = FAT16_MASK;
221                         pmp->pm_fatmult = 2;
222                         pmp->pm_fatdiv = 1;
223                 }
224         }
225         if (FAT12(pmp))
226                 pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec;
227         else
228                 pmp->pm_fatblocksize = MAXBSIZE;
229
230         pmp->pm_fatblocksec = pmp->pm_fatblocksize / pmp->pm_BytesPerSec;
231         pmp->pm_bnshift = ffs(pmp->pm_BytesPerSec) - 1;
232
233         /*
234          * Compute mask and shift value for isolating cluster relative byte
235          * offsets and cluster numbers from a file offset.
236          */
237         pmp->pm_bpcluster = SecPerClust * pmp->pm_BytesPerSec;
238         pmp->pm_crbomask = pmp->pm_bpcluster - 1;
239         pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1;
240
241         MSDOSFS_DPRINTF(("%s(fatmask=%lu, fatmult=%u, fatdiv=%u, "
242             "fatblocksize=%lu, fatblocksec=%lu, bnshift=%lu, pbcluster=%lu, "
243             "crbomask=%lu, cnshift=%lu)\n",
244             __func__, (unsigned long)pmp->pm_fatmask, pmp->pm_fatmult,
245             pmp->pm_fatdiv, pmp->pm_fatblocksize, pmp->pm_fatblocksec,
246             pmp->pm_bnshift, pmp->pm_bpcluster, pmp->pm_crbomask,
247             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                 MSDOSFS_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);
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                 if ((error = bread(devvp, pmp->pm_fsinfo, pmp->pm_BytesPerSec,
277                     0, &bp)) != 0)
278                         goto error_exit;
279                 fp = (struct fsinfo *)bp->b_data;
280                 if (!memcmp(fp->fsisig1, "RRaA", 4)
281                     && !memcmp(fp->fsisig2, "rrAa", 4)
282                     && !memcmp(fp->fsisig3, "\0\0\125\252", 4))
283                         pmp->pm_nxtfree = getulong(fp->fsinxtfree);
284                 else
285                         pmp->pm_fsinfo = 0;
286                 brelse(bp);
287                 bp = NULL;
288         }
289
290         /*
291          * Check and validate (or perhaps invalidate?) the fsinfo structure?
292          * XXX
293          */
294         if (pmp->pm_fsinfo) {
295                 if ((pmp->pm_nxtfree == 0xffffffffUL) ||
296                     (pmp->pm_nxtfree > pmp->pm_maxcluster))
297                         pmp->pm_fsinfo = 0;
298         }
299
300         /*
301          * Allocate memory for the bitmap of allocated clusters, and then
302          * fill it in.
303          */
304         pmp->pm_inusemap = ecalloc(sizeof(*pmp->pm_inusemap),
305             ((pmp->pm_maxcluster + N_INUSEBITS) / N_INUSEBITS));
306         /*
307          * fillinusemap() needs pm_devvp.
308          */
309         pmp->pm_dev = 0;
310         pmp->pm_devvp = devvp;
311
312         /*
313          * Have the inuse map filled in.
314          */
315         if ((error = fillinusemap(pmp)) != 0) {
316                 MSDOSFS_DPRINTF(("fillinusemap %d\n", error));
317                 goto error_exit;
318         }
319
320         /*
321          * Finish up.
322          */
323         if (ronly)
324                 pmp->pm_flags |= MSDOSFSMNT_RONLY;
325         else
326                 pmp->pm_fmod = 1;
327
328         /*
329          * If we ever do quotas for DOS filesystems this would be a place
330          * to fill in the info in the msdosfsmount structure. You dolt,
331          * quotas on dos filesystems make no sense because files have no
332          * owners on dos filesystems. of course there is some empty space
333          * in the directory entry where we could put uid's and gid's.
334          */
335
336         return pmp;
337
338 error_exit:
339         if (bp)
340                 brelse(bp);
341         if (pmp) {
342                 if (pmp->pm_inusemap)
343                         free(pmp->pm_inusemap);
344                 free(pmp);
345         }
346         errno = error;
347         return NULL;
348 }
349
350 int
351 msdosfs_root(struct msdosfsmount *pmp, struct vnode *vp) {
352         struct denode *ndep;
353         int error;
354
355         *vp = *pmp->pm_devvp;
356         if ((error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, &ndep)) != 0) {
357                 errno = error;
358                 return -1;
359         }
360         vp->v_data = ndep;
361         return 0;
362 }
363
364 /*
365  * If we have an FSInfo block, update it.
366  */
367 int
368 msdosfs_fsiflush(struct msdosfsmount *pmp)
369 {
370         struct fsinfo *fp;
371         struct buf *bp;
372         int error;
373
374         if (pmp->pm_fsinfo == 0 || (pmp->pm_flags & MSDOSFS_FSIMOD) == 0) {
375                 error = 0;
376                 goto out;
377         }
378         error = bread(pmp->pm_devvp, pmp->pm_fsinfo, pmp->pm_BytesPerSec,
379             NOCRED, &bp);
380         if (error != 0) {
381                 brelse(bp);
382                 goto out;
383         }
384         fp = (struct fsinfo *)bp->b_data;
385         putulong(fp->fsinfree, pmp->pm_freeclustercount);
386         putulong(fp->fsinxtfree, pmp->pm_nxtfree);
387         pmp->pm_flags &= ~MSDOSFS_FSIMOD;
388         error = bwrite(bp);
389
390 out:
391         return (error);
392 }