xref: /dragonfly/usr.sbin/fstyp/msdosfs.c (revision bc425cd9)
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