xref: /netbsd-src/usr.sbin/fstyp/msdosfs.c (revision b985414b8f8688f3bfa6718c583260b26b0bf1d1)
1*b985414bSchristos /*	$NetBSD: msdosfs.c,v 1.1 2018/01/09 03:31:15 christos Exp $	*/
2*b985414bSchristos 
3*b985414bSchristos /*-
4*b985414bSchristos  * Copyright (c) 2017 The NetBSD Foundation, Inc.
5*b985414bSchristos  * Copyright (c) 2016 The DragonFly Project
6*b985414bSchristos  * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org>
7*b985414bSchristos  * Copyright (c) 2006 Tobias Reifenberger
8*b985414bSchristos  * Copyright (c) 2014 The FreeBSD Foundation
9*b985414bSchristos  * All rights reserved.
10*b985414bSchristos  *
11*b985414bSchristos  * This code is derived from software contributed to The NetBSD Foundation
12*b985414bSchristos  * by Tomohiro Kusumi <kusumi.tomohiro@gmail.com>.
13*b985414bSchristos  *
14*b985414bSchristos  * This software was developed by Edward Tomasz Napierala under sponsorship
15*b985414bSchristos  * from the FreeBSD Foundation.
16*b985414bSchristos  *
17*b985414bSchristos  * Redistribution and use in source and binary forms, with or without
18*b985414bSchristos  * modification, are permitted provided that the following conditions
19*b985414bSchristos  * are met:
20*b985414bSchristos  * 1. Redistributions of source code must retain the above copyright
21*b985414bSchristos  *    notice, this list of conditions and the following disclaimer.
22*b985414bSchristos  * 2. Redistributions in binary form must reproduce the above copyright
23*b985414bSchristos  *    notice, this list of conditions and the following disclaimer in the
24*b985414bSchristos  *    documentation and/or other materials provided with the distribution.
25*b985414bSchristos  *
26*b985414bSchristos  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
27*b985414bSchristos  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28*b985414bSchristos  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29*b985414bSchristos  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
30*b985414bSchristos  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31*b985414bSchristos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32*b985414bSchristos  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33*b985414bSchristos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34*b985414bSchristos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35*b985414bSchristos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36*b985414bSchristos  * SUCH DAMAGE.
37*b985414bSchristos  */
38*b985414bSchristos #include <sys/cdefs.h>
39*b985414bSchristos __RCSID("$NetBSD: msdosfs.c,v 1.1 2018/01/09 03:31:15 christos Exp $");
40*b985414bSchristos 
41*b985414bSchristos #include <sys/param.h>
42*b985414bSchristos #include <stdio.h>
43*b985414bSchristos #include <stdlib.h>
44*b985414bSchristos #include <string.h>
45*b985414bSchristos 
46*b985414bSchristos #include "fstyp.h"
47*b985414bSchristos #include "msdosfs.h"
48*b985414bSchristos 
49*b985414bSchristos #define LABEL_NO_NAME		"NO NAME    "
50*b985414bSchristos 
51*b985414bSchristos int
fstyp_msdosfs(FILE * fp,char * label,size_t size)52*b985414bSchristos fstyp_msdosfs(FILE *fp, char *label, size_t size)
53*b985414bSchristos {
54*b985414bSchristos 	FAT_BSBPB *pfat_bsbpb;
55*b985414bSchristos 	FAT32_BSBPB *pfat32_bsbpb;
56*b985414bSchristos 	FAT_DES *pfat_entry;
57*b985414bSchristos 	uint8_t *sector0, *sector;
58*b985414bSchristos 
59*b985414bSchristos 	sector0 = NULL;
60*b985414bSchristos 	sector = NULL;
61*b985414bSchristos 
62*b985414bSchristos 	/* Load 1st sector with boot sector and boot parameter block. */
63*b985414bSchristos 	sector0 = read_buf(fp, 0, 512);
64*b985414bSchristos 	if (sector0 == NULL)
65*b985414bSchristos 		return 1;
66*b985414bSchristos 
67*b985414bSchristos 	/* Check for the FAT boot sector signature. */
68*b985414bSchristos 	if (sector0[510] != 0x55 || sector0[511] != 0xaa) {
69*b985414bSchristos 		goto error;
70*b985414bSchristos 	}
71*b985414bSchristos 
72*b985414bSchristos 	/*
73*b985414bSchristos 	 * Test if this is really a FAT volume and determine the FAT type.
74*b985414bSchristos 	 */
75*b985414bSchristos 
76*b985414bSchristos 	pfat_bsbpb = (FAT_BSBPB *)sector0;
77*b985414bSchristos 	pfat32_bsbpb = (FAT32_BSBPB *)sector0;
78*b985414bSchristos 
79*b985414bSchristos 	if (UINT16BYTES(pfat_bsbpb->BPB_FATSz16) != 0) {
80*b985414bSchristos 		/*
81*b985414bSchristos 		 * If the BPB_FATSz16 field is not zero and the string "FAT" is
82*b985414bSchristos 		 * at the right place, this should be a FAT12 or FAT16 volume.
83*b985414bSchristos 		 */
84*b985414bSchristos 		if (strncmp((char*)pfat_bsbpb->BS_FilSysType, "FAT", 3) != 0) {
85*b985414bSchristos 			goto error;
86*b985414bSchristos 		}
87*b985414bSchristos 
88*b985414bSchristos 		/* A volume with no name should have "NO NAME    " as label. */
89*b985414bSchristos 		if (strncmp((char*)pfat_bsbpb->BS_VolLab, LABEL_NO_NAME,
90*b985414bSchristos 		    sizeof(pfat_bsbpb->BS_VolLab)) == 0) {
91*b985414bSchristos 			goto endofchecks;
92*b985414bSchristos 		}
93*b985414bSchristos 		strlcpy(label, (char*)pfat_bsbpb->BS_VolLab,
94*b985414bSchristos 		    MIN(size, sizeof(pfat_bsbpb->BS_VolLab) + 1));
95*b985414bSchristos 	} else if (UINT32BYTES(pfat32_bsbpb->BPB_FATSz32) != 0) {
96*b985414bSchristos 		uint32_t fat_FirstDataSector, fat_BytesPerSector, offset;
97*b985414bSchristos 
98*b985414bSchristos 		/*
99*b985414bSchristos 		 * If the BPB_FATSz32 field is not zero and the string "FAT" is
100*b985414bSchristos 		 * at the right place, this should be a FAT32 volume.
101*b985414bSchristos 		 */
102*b985414bSchristos 		if (strncmp((char*)pfat32_bsbpb->BS_FilSysType, "FAT", 3) != 0)
103*b985414bSchristos 		{
104*b985414bSchristos 			goto error;
105*b985414bSchristos 		}
106*b985414bSchristos 
107*b985414bSchristos 		/*
108*b985414bSchristos 		 * If the volume label is not "NO NAME    " we're done.
109*b985414bSchristos 		 */
110*b985414bSchristos 		if (strncmp((char*)pfat32_bsbpb->BS_VolLab, LABEL_NO_NAME,
111*b985414bSchristos 		    sizeof(pfat32_bsbpb->BS_VolLab)) != 0) {
112*b985414bSchristos 			strlcpy(label, (char*)pfat32_bsbpb->BS_VolLab,
113*b985414bSchristos 			    MIN(size, sizeof(pfat32_bsbpb->BS_VolLab) + 1));
114*b985414bSchristos 			goto endofchecks;
115*b985414bSchristos 		}
116*b985414bSchristos 
117*b985414bSchristos 		/*
118*b985414bSchristos 		 * If the volume label "NO NAME    " is in the boot sector, the
119*b985414bSchristos 		 * label of FAT32 volumes may be stored as a special entry in
120*b985414bSchristos 		 * the root directory.
121*b985414bSchristos 		 */
122*b985414bSchristos 		fat_FirstDataSector =
123*b985414bSchristos 		    UINT16BYTES(pfat32_bsbpb->BPB_RsvdSecCnt) +
124*b985414bSchristos 		    (pfat32_bsbpb->BPB_NumFATs *
125*b985414bSchristos 		     UINT32BYTES(pfat32_bsbpb->BPB_FATSz32));
126*b985414bSchristos 		fat_BytesPerSector = UINT16BYTES(pfat32_bsbpb->BPB_BytsPerSec);
127*b985414bSchristos 
128*b985414bSchristos 		//    fat_FirstDataSector, fat_BytesPerSector);
129*b985414bSchristos 
130*b985414bSchristos 		for (offset = fat_BytesPerSector * fat_FirstDataSector;;
131*b985414bSchristos 		    offset += fat_BytesPerSector) {
132*b985414bSchristos 			sector = read_buf(fp, offset, fat_BytesPerSector);
133*b985414bSchristos 			if (sector == NULL)
134*b985414bSchristos 				goto error;
135*b985414bSchristos 
136*b985414bSchristos 			pfat_entry = (FAT_DES *)sector;
137*b985414bSchristos 			do {
138*b985414bSchristos 				/* No more entries available. */
139*b985414bSchristos 				if (pfat_entry->DIR_Name[0] == 0) {
140*b985414bSchristos 					goto endofchecks;
141*b985414bSchristos 				}
142*b985414bSchristos 
143*b985414bSchristos 				/* Skip empty or long name entries. */
144*b985414bSchristos 				if (pfat_entry->DIR_Name[0] == 0xe5 ||
145*b985414bSchristos 				    (pfat_entry->DIR_Attr &
146*b985414bSchristos 				     FAT_DES_ATTR_LONG_NAME) ==
147*b985414bSchristos 				    FAT_DES_ATTR_LONG_NAME) {
148*b985414bSchristos 					continue;
149*b985414bSchristos 				}
150*b985414bSchristos 
151*b985414bSchristos 				/*
152*b985414bSchristos 				 * The name of the entry is the volume label if
153*b985414bSchristos 				 * ATTR_VOLUME_ID is set.
154*b985414bSchristos 				 */
155*b985414bSchristos 				if (pfat_entry->DIR_Attr &
156*b985414bSchristos 				    FAT_DES_ATTR_VOLUME_ID) {
157*b985414bSchristos 					strlcpy(label, (char*)pfat_entry->DIR_Name,
158*b985414bSchristos 					    MIN(size,
159*b985414bSchristos 					    sizeof(pfat_entry->DIR_Name) + 1));
160*b985414bSchristos 					goto endofchecks;
161*b985414bSchristos 				}
162*b985414bSchristos 			} while((uint8_t *)(++pfat_entry) <
163*b985414bSchristos 			    (uint8_t *)(sector + fat_BytesPerSector));
164*b985414bSchristos 			free(sector);
165*b985414bSchristos 		}
166*b985414bSchristos 	} else {
167*b985414bSchristos 		goto error;
168*b985414bSchristos 	}
169*b985414bSchristos 
170*b985414bSchristos endofchecks:
171*b985414bSchristos 	rtrim(label, size);
172*b985414bSchristos 
173*b985414bSchristos 	free(sector0);
174*b985414bSchristos 	free(sector);
175*b985414bSchristos 
176*b985414bSchristos 	return (0);
177*b985414bSchristos 
178*b985414bSchristos error:
179*b985414bSchristos 	free(sector0);
180*b985414bSchristos 	free(sector);
181*b985414bSchristos 
182*b985414bSchristos 	return (1);
183*b985414bSchristos }
184