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: releng/10.2/usr.sbin/fstyp/msdosfs.c 275680 2014-12-10 14:14:16Z trasz $"); 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 uint32_t i; 52275680Strasz 53275680Strasz sector0 = NULL; 54275680Strasz sector = NULL; 55275680Strasz 56275680Strasz /* Load 1st sector with boot sector and boot parameter block. */ 57275680Strasz sector0 = (uint8_t *)read_buf(fp, 0, 512); 58275680Strasz if (sector0 == NULL) 59275680Strasz return (1); 60275680Strasz 61275680Strasz /* Check for the FAT boot sector signature. */ 62275680Strasz if (sector0[510] != 0x55 || sector0[511] != 0xaa) { 63275680Strasz goto error; 64275680Strasz } 65275680Strasz 66275680Strasz /* 67275680Strasz * Test if this is really a FAT volume and determine the FAT type. 68275680Strasz */ 69275680Strasz 70275680Strasz pfat_bsbpb = (FAT_BSBPB *)sector0; 71275680Strasz pfat32_bsbpb = (FAT32_BSBPB *)sector0; 72275680Strasz 73275680Strasz if (UINT16BYTES(pfat_bsbpb->BPB_FATSz16) != 0) { 74275680Strasz /* 75275680Strasz * If the BPB_FATSz16 field is not zero and the string "FAT" is 76275680Strasz * at the right place, this should be a FAT12 or FAT16 volume. 77275680Strasz */ 78275680Strasz if (strncmp(pfat_bsbpb->BS_FilSysType, "FAT", 3) != 0) { 79275680Strasz goto error; 80275680Strasz } 81275680Strasz 82275680Strasz /* A volume with no name should have "NO NAME " as label. */ 83275680Strasz if (strncmp(pfat_bsbpb->BS_VolLab, LABEL_NO_NAME, 84275680Strasz sizeof(pfat_bsbpb->BS_VolLab)) == 0) { 85275680Strasz goto endofchecks; 86275680Strasz } 87275680Strasz strlcpy(label, pfat_bsbpb->BS_VolLab, 88275680Strasz MIN(size, sizeof(pfat_bsbpb->BS_VolLab) + 1)); 89275680Strasz } else if (UINT32BYTES(pfat32_bsbpb->BPB_FATSz32) != 0) { 90275680Strasz uint32_t fat_FirstDataSector, fat_BytesPerSector, offset; 91275680Strasz 92275680Strasz /* 93275680Strasz * If the BPB_FATSz32 field is not zero and the string "FAT" is 94275680Strasz * at the right place, this should be a FAT32 volume. 95275680Strasz */ 96275680Strasz if (strncmp(pfat32_bsbpb->BS_FilSysType, "FAT", 3) != 0) { 97275680Strasz goto error; 98275680Strasz } 99275680Strasz 100275680Strasz /* 101275680Strasz * If the volume label is not "NO NAME " we're done. 102275680Strasz */ 103275680Strasz if (strncmp(pfat32_bsbpb->BS_VolLab, LABEL_NO_NAME, 104275680Strasz sizeof(pfat32_bsbpb->BS_VolLab)) != 0) { 105275680Strasz strlcpy(label, pfat32_bsbpb->BS_VolLab, 106275680Strasz MIN(size, sizeof(pfat32_bsbpb->BS_VolLab) + 1)); 107275680Strasz goto endofchecks; 108275680Strasz } 109275680Strasz 110275680Strasz /* 111275680Strasz * If the volume label "NO NAME " is in the boot sector, the 112275680Strasz * label of FAT32 volumes may be stored as a special entry in 113275680Strasz * the root directory. 114275680Strasz */ 115275680Strasz fat_FirstDataSector = 116275680Strasz UINT16BYTES(pfat32_bsbpb->BPB_RsvdSecCnt) + 117275680Strasz (pfat32_bsbpb->BPB_NumFATs * 118275680Strasz UINT32BYTES(pfat32_bsbpb->BPB_FATSz32)); 119275680Strasz fat_BytesPerSector = UINT16BYTES(pfat32_bsbpb->BPB_BytsPerSec); 120275680Strasz 121275680Strasz // fat_FirstDataSector, fat_BytesPerSector); 122275680Strasz 123275680Strasz for (offset = fat_BytesPerSector * fat_FirstDataSector;; 124275680Strasz offset += fat_BytesPerSector) { 125275680Strasz sector = (uint8_t *)read_buf(fp, offset, fat_BytesPerSector); 126275680Strasz if (sector == NULL) 127275680Strasz goto error; 128275680Strasz 129275680Strasz pfat_entry = (FAT_DES *)sector; 130275680Strasz do { 131275680Strasz /* No more entries available. */ 132275680Strasz if (pfat_entry->DIR_Name[0] == 0) { 133275680Strasz goto endofchecks; 134275680Strasz } 135275680Strasz 136275680Strasz /* Skip empty or long name entries. */ 137275680Strasz if (pfat_entry->DIR_Name[0] == 0xe5 || 138275680Strasz (pfat_entry->DIR_Attr & 139275680Strasz FAT_DES_ATTR_LONG_NAME) == 140275680Strasz FAT_DES_ATTR_LONG_NAME) { 141275680Strasz continue; 142275680Strasz } 143275680Strasz 144275680Strasz /* 145275680Strasz * The name of the entry is the volume label if 146275680Strasz * ATTR_VOLUME_ID is set. 147275680Strasz */ 148275680Strasz if (pfat_entry->DIR_Attr & 149275680Strasz FAT_DES_ATTR_VOLUME_ID) { 150275680Strasz strlcpy(label, pfat_entry->DIR_Name, 151275680Strasz MIN(size, 152275680Strasz sizeof(pfat_entry->DIR_Name) + 1)); 153275680Strasz goto endofchecks; 154275680Strasz } 155275680Strasz } while((uint8_t *)(++pfat_entry) < 156275680Strasz (uint8_t *)(sector + fat_BytesPerSector)); 157275680Strasz free(sector); 158275680Strasz } 159275680Strasz } else { 160275680Strasz goto error; 161275680Strasz } 162275680Strasz 163275680Straszendofchecks: 164275680Strasz for (i = size - 1; i > 0; i--) { 165275680Strasz if (label[i] == '\0') 166275680Strasz continue; 167275680Strasz else if (label[i] == ' ') 168275680Strasz label[i] = '\0'; 169275680Strasz else 170275680Strasz break; 171275680Strasz } 172275680Strasz 173275680Strasz free(sector0); 174275680Strasz free(sector); 175275680Strasz 176275680Strasz return (0); 177275680Strasz 178275680Straszerror: 179275680Strasz free(sector0); 180275680Strasz free(sector); 181275680Strasz 182275680Strasz return (1); 183275680Strasz} 184