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