1275680Strasz/*- 2275680Strasz * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3275680Strasz * Copyright (c) 2006 Tobias Reifenberger 4275680Strasz * Copyright (c) 2014 The FreeBSD Foundation 5275680Strasz * All rights reserved. 6275680Strasz * 7275680Strasz * This software was developed by Edward Tomasz Napierala under sponsorship 8275680Strasz * from the FreeBSD Foundation. 9275680Strasz * 10275680Strasz * Redistribution and use in source and binary forms, with or without 11275680Strasz * modification, are permitted provided that the following conditions 12275680Strasz * are met: 13275680Strasz * 1. Redistributions of source code must retain the above copyright 14275680Strasz * notice, this list of conditions and the following disclaimer. 15275680Strasz * 2. Redistributions in binary form must reproduce the above copyright 16275680Strasz * notice, this list of conditions and the following disclaimer in the 17275680Strasz * documentation and/or other materials provided with the distribution. 18275680Strasz * 19275680Strasz * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 20275680Strasz * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21275680Strasz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22275680Strasz * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 23275680Strasz * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24275680Strasz * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25275680Strasz * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26275680Strasz * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27275680Strasz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28275680Strasz * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29275680Strasz * SUCH DAMAGE. 30275680Strasz */ 31275680Strasz 32275680Strasz#include <sys/cdefs.h> 33275680Strasz__FBSDID("$FreeBSD$"); 34275680Strasz 35275680Strasz#include <stdio.h> 36275680Strasz#include <stdlib.h> 37275680Strasz#include <string.h> 38275680Strasz 39275680Strasz#include "fstyp.h" 40275680Strasz#include "msdosfs.h" 41275680Strasz 42275680Strasz#define LABEL_NO_NAME "NO NAME " 43275680Strasz 44275680Straszint 45275680Straszfstyp_msdosfs(FILE *fp, char *label, size_t size) 46275680Strasz{ 47275680Strasz FAT_BSBPB *pfat_bsbpb; 48275680Strasz FAT32_BSBPB *pfat32_bsbpb; 49275680Strasz FAT_DES *pfat_entry; 50275680Strasz uint8_t *sector0, *sector; 51275680Strasz 52275680Strasz sector0 = NULL; 53275680Strasz sector = NULL; 54275680Strasz 55275680Strasz /* Load 1st sector with boot sector and boot parameter block. */ 56275680Strasz sector0 = (uint8_t *)read_buf(fp, 0, 512); 57275680Strasz if (sector0 == NULL) 58275680Strasz return (1); 59275680Strasz 60275680Strasz /* Check for the FAT boot sector signature. */ 61275680Strasz if (sector0[510] != 0x55 || sector0[511] != 0xaa) { 62275680Strasz goto error; 63275680Strasz } 64275680Strasz 65275680Strasz /* 66275680Strasz * Test if this is really a FAT volume and determine the FAT type. 67275680Strasz */ 68275680Strasz 69275680Strasz pfat_bsbpb = (FAT_BSBPB *)sector0; 70275680Strasz pfat32_bsbpb = (FAT32_BSBPB *)sector0; 71275680Strasz 72275680Strasz if (UINT16BYTES(pfat_bsbpb->BPB_FATSz16) != 0) { 73275680Strasz /* 74275680Strasz * If the BPB_FATSz16 field is not zero and the string "FAT" is 75275680Strasz * at the right place, this should be a FAT12 or FAT16 volume. 76275680Strasz */ 77275680Strasz if (strncmp(pfat_bsbpb->BS_FilSysType, "FAT", 3) != 0) { 78275680Strasz goto error; 79275680Strasz } 80275680Strasz 81275680Strasz /* A volume with no name should have "NO NAME " as label. */ 82275680Strasz if (strncmp(pfat_bsbpb->BS_VolLab, LABEL_NO_NAME, 83275680Strasz sizeof(pfat_bsbpb->BS_VolLab)) == 0) { 84275680Strasz goto endofchecks; 85275680Strasz } 86275680Strasz strlcpy(label, pfat_bsbpb->BS_VolLab, 87275680Strasz MIN(size, sizeof(pfat_bsbpb->BS_VolLab) + 1)); 88275680Strasz } else if (UINT32BYTES(pfat32_bsbpb->BPB_FATSz32) != 0) { 89275680Strasz uint32_t fat_FirstDataSector, fat_BytesPerSector, offset; 90275680Strasz 91275680Strasz /* 92275680Strasz * If the BPB_FATSz32 field is not zero and the string "FAT" is 93275680Strasz * at the right place, this should be a FAT32 volume. 94275680Strasz */ 95275680Strasz if (strncmp(pfat32_bsbpb->BS_FilSysType, "FAT", 3) != 0) { 96275680Strasz goto error; 97275680Strasz } 98275680Strasz 99275680Strasz /* 100275680Strasz * If the volume label is not "NO NAME " we're done. 101275680Strasz */ 102275680Strasz if (strncmp(pfat32_bsbpb->BS_VolLab, LABEL_NO_NAME, 103275680Strasz sizeof(pfat32_bsbpb->BS_VolLab)) != 0) { 104275680Strasz strlcpy(label, pfat32_bsbpb->BS_VolLab, 105275680Strasz MIN(size, sizeof(pfat32_bsbpb->BS_VolLab) + 1)); 106275680Strasz goto endofchecks; 107275680Strasz } 108275680Strasz 109275680Strasz /* 110275680Strasz * If the volume label "NO NAME " is in the boot sector, the 111275680Strasz * label of FAT32 volumes may be stored as a special entry in 112275680Strasz * the root directory. 113275680Strasz */ 114275680Strasz fat_FirstDataSector = 115275680Strasz UINT16BYTES(pfat32_bsbpb->BPB_RsvdSecCnt) + 116275680Strasz (pfat32_bsbpb->BPB_NumFATs * 117275680Strasz UINT32BYTES(pfat32_bsbpb->BPB_FATSz32)); 118275680Strasz fat_BytesPerSector = UINT16BYTES(pfat32_bsbpb->BPB_BytsPerSec); 119275680Strasz 120275680Strasz // fat_FirstDataSector, fat_BytesPerSector); 121275680Strasz 122275680Strasz for (offset = fat_BytesPerSector * fat_FirstDataSector;; 123275680Strasz offset += fat_BytesPerSector) { 124275680Strasz sector = (uint8_t *)read_buf(fp, offset, fat_BytesPerSector); 125275680Strasz if (sector == NULL) 126275680Strasz goto error; 127275680Strasz 128275680Strasz pfat_entry = (FAT_DES *)sector; 129275680Strasz do { 130275680Strasz /* No more entries available. */ 131275680Strasz if (pfat_entry->DIR_Name[0] == 0) { 132275680Strasz goto endofchecks; 133275680Strasz } 134275680Strasz 135275680Strasz /* Skip empty or long name entries. */ 136275680Strasz if (pfat_entry->DIR_Name[0] == 0xe5 || 137275680Strasz (pfat_entry->DIR_Attr & 138275680Strasz FAT_DES_ATTR_LONG_NAME) == 139275680Strasz FAT_DES_ATTR_LONG_NAME) { 140275680Strasz continue; 141275680Strasz } 142275680Strasz 143275680Strasz /* 144275680Strasz * The name of the entry is the volume label if 145275680Strasz * ATTR_VOLUME_ID is set. 146275680Strasz */ 147275680Strasz if (pfat_entry->DIR_Attr & 148275680Strasz FAT_DES_ATTR_VOLUME_ID) { 149275680Strasz strlcpy(label, pfat_entry->DIR_Name, 150275680Strasz MIN(size, 151275680Strasz sizeof(pfat_entry->DIR_Name) + 1)); 152275680Strasz goto endofchecks; 153275680Strasz } 154275680Strasz } while((uint8_t *)(++pfat_entry) < 155275680Strasz (uint8_t *)(sector + fat_BytesPerSector)); 156275680Strasz free(sector); 157275680Strasz } 158275680Strasz } else { 159275680Strasz goto error; 160275680Strasz } 161275680Strasz 162275680Straszendofchecks: 163286193Strasz rtrim(label, size); 164275680Strasz 165275680Strasz free(sector0); 166275680Strasz free(sector); 167275680Strasz 168275680Strasz return (0); 169275680Strasz 170275680Straszerror: 171275680Strasz free(sector0); 172275680Strasz free(sector); 173275680Strasz 174275680Strasz return (1); 175275680Strasz} 176