1551c4c36STomohiro Kusumi /*-
2551c4c36STomohiro Kusumi * Copyright (c) 2016 The DragonFly Project
3551c4c36STomohiro Kusumi * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org>
4551c4c36STomohiro Kusumi * Copyright (c) 2006 Tobias Reifenberger
5551c4c36STomohiro Kusumi * Copyright (c) 2014 The FreeBSD Foundation
6551c4c36STomohiro Kusumi * All rights reserved.
7551c4c36STomohiro Kusumi *
8551c4c36STomohiro Kusumi * This software was developed by Edward Tomasz Napierala under sponsorship
9551c4c36STomohiro Kusumi * from the FreeBSD Foundation.
10551c4c36STomohiro Kusumi *
11551c4c36STomohiro Kusumi * Redistribution and use in source and binary forms, with or without
12551c4c36STomohiro Kusumi * modification, are permitted provided that the following conditions
13551c4c36STomohiro Kusumi * are met:
14551c4c36STomohiro Kusumi * 1. Redistributions of source code must retain the above copyright
15551c4c36STomohiro Kusumi * notice, this list of conditions and the following disclaimer.
16551c4c36STomohiro Kusumi * 2. Redistributions in binary form must reproduce the above copyright
17551c4c36STomohiro Kusumi * notice, this list of conditions and the following disclaimer in the
18551c4c36STomohiro Kusumi * documentation and/or other materials provided with the distribution.
19551c4c36STomohiro Kusumi *
20551c4c36STomohiro Kusumi * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
21551c4c36STomohiro Kusumi * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22551c4c36STomohiro Kusumi * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23551c4c36STomohiro Kusumi * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
24551c4c36STomohiro Kusumi * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25551c4c36STomohiro Kusumi * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26551c4c36STomohiro Kusumi * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27551c4c36STomohiro Kusumi * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28551c4c36STomohiro Kusumi * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29551c4c36STomohiro Kusumi * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30551c4c36STomohiro Kusumi * SUCH DAMAGE.
31551c4c36STomohiro Kusumi */
32551c4c36STomohiro Kusumi
33eff346a5STomohiro Kusumi #include <sys/param.h>
34551c4c36STomohiro Kusumi #include <stdio.h>
35551c4c36STomohiro Kusumi #include <stdlib.h>
36551c4c36STomohiro Kusumi #include <string.h>
37551c4c36STomohiro Kusumi
38551c4c36STomohiro Kusumi #include "fstyp.h"
39551c4c36STomohiro Kusumi #include "msdosfs.h"
40551c4c36STomohiro Kusumi
41551c4c36STomohiro Kusumi #define LABEL_NO_NAME "NO NAME "
42551c4c36STomohiro Kusumi
43551c4c36STomohiro Kusumi int
fstyp_msdosfs(FILE * fp,char * label,size_t size,const char * devpath)4465d969b4STomohiro Kusumi fstyp_msdosfs(FILE *fp, char *label, size_t size, const char *devpath)
45551c4c36STomohiro Kusumi {
46551c4c36STomohiro Kusumi FAT_BSBPB *pfat_bsbpb;
47551c4c36STomohiro Kusumi FAT32_BSBPB *pfat32_bsbpb;
48551c4c36STomohiro Kusumi FAT_DES *pfat_entry;
49551c4c36STomohiro Kusumi uint8_t *sector0, *sector;
50*bc425cd9STomohiro Kusumi size_t copysize;
51551c4c36STomohiro Kusumi
52551c4c36STomohiro Kusumi sector0 = NULL;
53551c4c36STomohiro Kusumi sector = NULL;
54551c4c36STomohiro Kusumi
55551c4c36STomohiro Kusumi /* Load 1st sector with boot sector and boot parameter block. */
56551c4c36STomohiro Kusumi sector0 = (uint8_t *)read_buf(fp, 0, 512);
57551c4c36STomohiro Kusumi if (sector0 == NULL)
58551c4c36STomohiro Kusumi return (1);
59551c4c36STomohiro Kusumi
60551c4c36STomohiro Kusumi /* Check for the FAT boot sector signature. */
61551c4c36STomohiro Kusumi if (sector0[510] != 0x55 || sector0[511] != 0xaa) {
62551c4c36STomohiro Kusumi goto error;
63551c4c36STomohiro Kusumi }
64551c4c36STomohiro Kusumi
65551c4c36STomohiro Kusumi /*
66551c4c36STomohiro Kusumi * Test if this is really a FAT volume and determine the FAT type.
67551c4c36STomohiro Kusumi */
68551c4c36STomohiro Kusumi
69551c4c36STomohiro Kusumi pfat_bsbpb = (FAT_BSBPB *)sector0;
70551c4c36STomohiro Kusumi pfat32_bsbpb = (FAT32_BSBPB *)sector0;
71551c4c36STomohiro Kusumi
72551c4c36STomohiro Kusumi if (UINT16BYTES(pfat_bsbpb->BPB_FATSz16) != 0) {
73551c4c36STomohiro Kusumi /*
74551c4c36STomohiro Kusumi * If the BPB_FATSz16 field is not zero and the string "FAT" is
75551c4c36STomohiro Kusumi * at the right place, this should be a FAT12 or FAT16 volume.
76551c4c36STomohiro Kusumi */
77551c4c36STomohiro Kusumi if (strncmp(pfat_bsbpb->BS_FilSysType, "FAT", 3) != 0) {
78551c4c36STomohiro Kusumi goto error;
79551c4c36STomohiro Kusumi }
80551c4c36STomohiro Kusumi
81551c4c36STomohiro Kusumi /* A volume with no name should have "NO NAME " as label. */
82551c4c36STomohiro Kusumi if (strncmp(pfat_bsbpb->BS_VolLab, LABEL_NO_NAME,
83551c4c36STomohiro Kusumi sizeof(pfat_bsbpb->BS_VolLab)) == 0) {
84551c4c36STomohiro Kusumi goto endofchecks;
85551c4c36STomohiro Kusumi }
86*bc425cd9STomohiro Kusumi copysize = MIN(size - 1, sizeof(pfat_bsbpb->BS_VolLab));
87*bc425cd9STomohiro Kusumi memcpy(label, pfat_bsbpb->BS_VolLab, copysize);
88*bc425cd9STomohiro Kusumi label[copysize] = '\0';
89551c4c36STomohiro Kusumi } else if (UINT32BYTES(pfat32_bsbpb->BPB_FATSz32) != 0) {
90551c4c36STomohiro Kusumi uint32_t fat_FirstDataSector, fat_BytesPerSector, offset;
91551c4c36STomohiro Kusumi
92551c4c36STomohiro Kusumi /*
93551c4c36STomohiro Kusumi * If the BPB_FATSz32 field is not zero and the string "FAT" is
94551c4c36STomohiro Kusumi * at the right place, this should be a FAT32 volume.
95551c4c36STomohiro Kusumi */
96551c4c36STomohiro Kusumi if (strncmp(pfat32_bsbpb->BS_FilSysType, "FAT", 3) != 0) {
97551c4c36STomohiro Kusumi goto error;
98551c4c36STomohiro Kusumi }
99551c4c36STomohiro Kusumi
100551c4c36STomohiro Kusumi /*
101551c4c36STomohiro Kusumi * If the volume label is not "NO NAME " we're done.
102551c4c36STomohiro Kusumi */
103551c4c36STomohiro Kusumi if (strncmp(pfat32_bsbpb->BS_VolLab, LABEL_NO_NAME,
104551c4c36STomohiro Kusumi sizeof(pfat32_bsbpb->BS_VolLab)) != 0) {
105*bc425cd9STomohiro Kusumi copysize = MIN(size - 1,
106*bc425cd9STomohiro Kusumi sizeof(pfat32_bsbpb->BS_VolLab));
107*bc425cd9STomohiro Kusumi memcpy(label, pfat32_bsbpb->BS_VolLab, copysize);
108*bc425cd9STomohiro Kusumi label[copysize] = '\0';
109551c4c36STomohiro Kusumi goto endofchecks;
110551c4c36STomohiro Kusumi }
111551c4c36STomohiro Kusumi
112551c4c36STomohiro Kusumi /*
113551c4c36STomohiro Kusumi * If the volume label "NO NAME " is in the boot sector, the
114551c4c36STomohiro Kusumi * label of FAT32 volumes may be stored as a special entry in
115551c4c36STomohiro Kusumi * the root directory.
116551c4c36STomohiro Kusumi */
117551c4c36STomohiro Kusumi fat_FirstDataSector =
118551c4c36STomohiro Kusumi UINT16BYTES(pfat32_bsbpb->BPB_RsvdSecCnt) +
119551c4c36STomohiro Kusumi (pfat32_bsbpb->BPB_NumFATs *
120551c4c36STomohiro Kusumi UINT32BYTES(pfat32_bsbpb->BPB_FATSz32));
121551c4c36STomohiro Kusumi fat_BytesPerSector = UINT16BYTES(pfat32_bsbpb->BPB_BytsPerSec);
122551c4c36STomohiro Kusumi
123551c4c36STomohiro Kusumi // fat_FirstDataSector, fat_BytesPerSector);
124551c4c36STomohiro Kusumi
125551c4c36STomohiro Kusumi for (offset = fat_BytesPerSector * fat_FirstDataSector;;
126551c4c36STomohiro Kusumi offset += fat_BytesPerSector) {
127551c4c36STomohiro Kusumi sector = (uint8_t *)read_buf(fp, offset, fat_BytesPerSector);
128551c4c36STomohiro Kusumi if (sector == NULL)
129551c4c36STomohiro Kusumi goto error;
130551c4c36STomohiro Kusumi
131551c4c36STomohiro Kusumi pfat_entry = (FAT_DES *)sector;
132551c4c36STomohiro Kusumi do {
133551c4c36STomohiro Kusumi /* No more entries available. */
134551c4c36STomohiro Kusumi if (pfat_entry->DIR_Name[0] == 0) {
135551c4c36STomohiro Kusumi goto endofchecks;
136551c4c36STomohiro Kusumi }
137551c4c36STomohiro Kusumi
138551c4c36STomohiro Kusumi /* Skip empty or long name entries. */
139551c4c36STomohiro Kusumi if (pfat_entry->DIR_Name[0] == 0xe5 ||
140551c4c36STomohiro Kusumi (pfat_entry->DIR_Attr &
141551c4c36STomohiro Kusumi FAT_DES_ATTR_LONG_NAME) ==
142551c4c36STomohiro Kusumi FAT_DES_ATTR_LONG_NAME) {
143551c4c36STomohiro Kusumi continue;
144551c4c36STomohiro Kusumi }
145551c4c36STomohiro Kusumi
146551c4c36STomohiro Kusumi /*
147551c4c36STomohiro Kusumi * The name of the entry is the volume label if
148551c4c36STomohiro Kusumi * ATTR_VOLUME_ID is set.
149551c4c36STomohiro Kusumi */
150551c4c36STomohiro Kusumi if (pfat_entry->DIR_Attr &
151551c4c36STomohiro Kusumi FAT_DES_ATTR_VOLUME_ID) {
152*bc425cd9STomohiro Kusumi copysize = MIN(size - 1,
153*bc425cd9STomohiro Kusumi sizeof(pfat_entry->DIR_Name));
154*bc425cd9STomohiro Kusumi memcpy(label, pfat_entry->DIR_Name,
155*bc425cd9STomohiro Kusumi copysize);
156*bc425cd9STomohiro Kusumi label[copysize] = '\0';
157551c4c36STomohiro Kusumi goto endofchecks;
158551c4c36STomohiro Kusumi }
159551c4c36STomohiro Kusumi } while((uint8_t *)(++pfat_entry) <
160551c4c36STomohiro Kusumi (uint8_t *)(sector + fat_BytesPerSector));
161551c4c36STomohiro Kusumi free(sector);
162551c4c36STomohiro Kusumi }
163551c4c36STomohiro Kusumi } else {
164551c4c36STomohiro Kusumi goto error;
165551c4c36STomohiro Kusumi }
166551c4c36STomohiro Kusumi
167551c4c36STomohiro Kusumi endofchecks:
168551c4c36STomohiro Kusumi rtrim(label, size);
169551c4c36STomohiro Kusumi
170551c4c36STomohiro Kusumi free(sector0);
171551c4c36STomohiro Kusumi free(sector);
172551c4c36STomohiro Kusumi
173551c4c36STomohiro Kusumi return (0);
174551c4c36STomohiro Kusumi
175551c4c36STomohiro Kusumi error:
176551c4c36STomohiro Kusumi free(sector0);
177551c4c36STomohiro Kusumi free(sector);
178551c4c36STomohiro Kusumi
179551c4c36STomohiro Kusumi return (1);
180551c4c36STomohiro Kusumi }
181