1131476Spjd/*- 2131476Spjd * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3161246Spjd * Copyright (c) 2006 Tobias Reifenberger 4131476Spjd * All rights reserved. 5131476Spjd * 6131476Spjd * Redistribution and use in source and binary forms, with or without 7131476Spjd * modification, are permitted provided that the following conditions 8131476Spjd * are met: 9131476Spjd * 1. Redistributions of source code must retain the above copyright 10131476Spjd * notice, this list of conditions and the following disclaimer. 11131476Spjd * 2. Redistributions in binary form must reproduce the above copyright 12131476Spjd * notice, this list of conditions and the following disclaimer in the 13131476Spjd * documentation and/or other materials provided with the distribution. 14155174Spjd * 15131476Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 16131476Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17131476Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18131476Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 19131476Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20131476Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21131476Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22131476Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23131476Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24131476Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25131476Spjd * SUCH DAMAGE. 26131476Spjd */ 27131476Spjd 28131476Spjd#include <sys/cdefs.h> 29131476Spjd__FBSDID("$FreeBSD: releng/10.2/sys/geom/label/g_label_msdosfs.c 199875 2009-11-28 11:57:43Z trasz $"); 30131476Spjd 31131476Spjd#include <sys/param.h> 32131476Spjd#include <sys/systm.h> 33131476Spjd#include <sys/kernel.h> 34131476Spjd#include <sys/malloc.h> 35131476Spjd 36131476Spjd#include <geom/geom.h> 37131476Spjd#include <geom/label/g_label.h> 38161246Spjd#include <geom/label/g_label_msdosfs.h> 39131476Spjd 40131476Spjd#define G_LABEL_MSDOSFS_DIR "msdosfs" 41161246Spjd#define LABEL_NO_NAME "NO NAME " 42131476Spjd 43131476Spjdstatic void 44131476Spjdg_label_msdosfs_taste(struct g_consumer *cp, char *label, size_t size) 45131476Spjd{ 46131476Spjd struct g_provider *pp; 47161246Spjd FAT_BSBPB *pfat_bsbpb; 48161246Spjd FAT32_BSBPB *pfat32_bsbpb; 49161246Spjd FAT_DES *pfat_entry; 50161246Spjd uint8_t *sector0, *sector; 51161246Spjd uint32_t i; 52131476Spjd 53131476Spjd g_topology_assert_not(); 54131476Spjd pp = cp->provider; 55161246Spjd sector0 = NULL; 56161246Spjd sector = NULL; 57161246Spjd bzero(label, size); 58131476Spjd 59161246Spjd /* Check if the sector size of the medium is a valid FAT sector size. */ 60161246Spjd switch(pp->sectorsize) { 61161246Spjd case 512: 62161246Spjd case 1024: 63161246Spjd case 2048: 64161246Spjd case 4096: 65161246Spjd break; 66161246Spjd default: 67161246Spjd G_LABEL_DEBUG(1, "MSDOSFS: %s: sector size %d not compatible.", 68161246Spjd pp->name, pp->sectorsize); 69131476Spjd return; 70161246Spjd } 71161246Spjd 72161246Spjd /* Load 1st sector with boot sector and boot parameter block. */ 73161246Spjd sector0 = (uint8_t *)g_read_data(cp, 0, pp->sectorsize, NULL); 74161246Spjd if (sector0 == NULL) 75161246Spjd return; 76161246Spjd 77161246Spjd /* Check for the FAT boot sector signature. */ 78161246Spjd if (sector0[510] != 0x55 || sector0[511] != 0xaa) { 79161246Spjd G_LABEL_DEBUG(1, "MSDOSFS: %s: no FAT signature found.", 80131476Spjd pp->name); 81161246Spjd goto error; 82161246Spjd } 83161246Spjd 84161246Spjd 85161246Spjd /* 86161246Spjd * Test if this is really a FAT volume and determine the FAT type. 87161246Spjd */ 88161246Spjd 89161246Spjd pfat_bsbpb = (FAT_BSBPB *)sector0; 90161246Spjd pfat32_bsbpb = (FAT32_BSBPB *)sector0; 91161246Spjd 92161246Spjd if (UINT16BYTES(pfat_bsbpb->BPB_FATSz16) != 0) { 93161246Spjd /* 94161246Spjd * If the BPB_FATSz16 field is not zero and the string "FAT" is 95161246Spjd * at the right place, this should be a FAT12 or FAT16 volume. 96161246Spjd */ 97161246Spjd if (strncmp(pfat_bsbpb->BS_FilSysType, "FAT", 3) != 0) { 98161246Spjd G_LABEL_DEBUG(1, 99161246Spjd "MSDOSFS: %s: FAT12/16 volume not valid.", 100161246Spjd pp->name); 101161246Spjd goto error; 102161246Spjd } 103161246Spjd G_LABEL_DEBUG(1, "MSDOSFS: %s: FAT12/FAT16 volume detected.", 104131476Spjd pp->name); 105161246Spjd 106161246Spjd /* A volume with no name should have "NO NAME " as label. */ 107161246Spjd if (strncmp(pfat_bsbpb->BS_VolLab, LABEL_NO_NAME, 108161246Spjd sizeof(pfat_bsbpb->BS_VolLab)) == 0) { 109161246Spjd G_LABEL_DEBUG(1, 110161246Spjd "MSDOSFS: %s: FAT12/16 volume has no name.", 111161246Spjd pp->name); 112161246Spjd goto error; 113161246Spjd } 114161246Spjd strlcpy(label, pfat_bsbpb->BS_VolLab, 115161246Spjd MIN(size, sizeof(pfat_bsbpb->BS_VolLab) + 1)); 116161246Spjd } else if (UINT32BYTES(pfat32_bsbpb->BPB_FATSz32) != 0) { 117161246Spjd uint32_t fat_FirstDataSector, fat_BytesPerSector, offset; 118161246Spjd 119161246Spjd /* 120161246Spjd * If the BPB_FATSz32 field is not zero and the string "FAT" is 121161246Spjd * at the right place, this should be a FAT32 volume. 122161246Spjd */ 123161246Spjd if (strncmp(pfat32_bsbpb->BS_FilSysType, "FAT", 3) != 0) { 124161246Spjd G_LABEL_DEBUG(1, "MSDOSFS: %s: FAT32 volume not valid.", 125161246Spjd pp->name); 126161246Spjd goto error; 127161246Spjd } 128161246Spjd G_LABEL_DEBUG(1, "MSDOSFS: %s: FAT32 volume detected.", 129131476Spjd pp->name); 130161246Spjd 131161246Spjd /* 132161246Spjd * If the volume label is not "NO NAME " we're done. 133161246Spjd */ 134161246Spjd if (strncmp(pfat32_bsbpb->BS_VolLab, LABEL_NO_NAME, 135161246Spjd sizeof(pfat32_bsbpb->BS_VolLab)) != 0) { 136161246Spjd strlcpy(label, pfat32_bsbpb->BS_VolLab, 137161246Spjd MIN(size, sizeof(pfat32_bsbpb->BS_VolLab) + 1)); 138161246Spjd goto endofchecks; 139161246Spjd } 140161246Spjd 141161246Spjd /* 142161246Spjd * If the volume label "NO NAME " is in the boot sector, the 143161246Spjd * label of FAT32 volumes may be stored as a special entry in 144161246Spjd * the root directory. 145161246Spjd */ 146161246Spjd fat_FirstDataSector = 147161246Spjd UINT16BYTES(pfat32_bsbpb->BPB_RsvdSecCnt) + 148161246Spjd (pfat32_bsbpb->BPB_NumFATs * 149161246Spjd UINT32BYTES(pfat32_bsbpb->BPB_FATSz32)); 150161246Spjd fat_BytesPerSector = UINT16BYTES(pfat32_bsbpb->BPB_BytsPerSec); 151162834Spjd 152161246Spjd G_LABEL_DEBUG(2, 153161246Spjd "MSDOSFS: FAT_FirstDataSector=0x%x, FAT_BytesPerSector=%d", 154161246Spjd fat_FirstDataSector, fat_BytesPerSector); 155161246Spjd 156161246Spjd for (offset = fat_BytesPerSector * fat_FirstDataSector;; 157161246Spjd offset += fat_BytesPerSector) { 158161246Spjd sector = (uint8_t *)g_read_data(cp, offset, 159161246Spjd fat_BytesPerSector, NULL); 160161246Spjd if (sector == NULL) 161161246Spjd goto error; 162161246Spjd 163161246Spjd pfat_entry = (FAT_DES *)sector; 164161246Spjd do { 165161246Spjd /* No more entries available. */ 166161246Spjd if (pfat_entry->DIR_Name[0] == 0) { 167161246Spjd G_LABEL_DEBUG(1, "MSDOSFS: %s: " 168161246Spjd "FAT32 volume has no name.", 169161246Spjd pp->name); 170161246Spjd goto error; 171161246Spjd } 172161246Spjd 173161246Spjd /* Skip empty or long name entries. */ 174161246Spjd if (pfat_entry->DIR_Name[0] == 0xe5 || 175161246Spjd (pfat_entry->DIR_Attr & 176161246Spjd FAT_DES_ATTR_LONG_NAME) == 177161246Spjd FAT_DES_ATTR_LONG_NAME) { 178161246Spjd continue; 179161246Spjd } 180161246Spjd 181161246Spjd /* 182161246Spjd * The name of the entry is the volume label if 183161246Spjd * ATTR_VOLUME_ID is set. 184161246Spjd */ 185161246Spjd if (pfat_entry->DIR_Attr & 186161246Spjd FAT_DES_ATTR_VOLUME_ID) { 187161246Spjd strlcpy(label, pfat_entry->DIR_Name, 188161246Spjd MIN(size, 189188492Slulf sizeof(pfat_entry->DIR_Name) + 1)); 190161246Spjd goto endofchecks; 191161246Spjd } 192161246Spjd } while((uint8_t *)(++pfat_entry) < 193161246Spjd (uint8_t *)(sector + fat_BytesPerSector)); 194161246Spjd g_free(sector); 195161246Spjd } 196131476Spjd } else { 197161246Spjd G_LABEL_DEBUG(1, "MSDOSFS: %s: no FAT volume detected.", 198161246Spjd pp->name); 199161246Spjd goto error; 200131476Spjd } 201161246Spjd 202161246Spjdendofchecks: 203131476Spjd for (i = size - 1; i > 0; i--) { 204131476Spjd if (label[i] == '\0') 205131476Spjd continue; 206131476Spjd else if (label[i] == ' ') 207131476Spjd label[i] = '\0'; 208131476Spjd else 209131476Spjd break; 210131476Spjd } 211161246Spjd 212161246Spjderror: 213161246Spjd if (sector0 != NULL) 214161246Spjd g_free(sector0); 215161246Spjd if (sector != NULL) 216161246Spjd g_free(sector); 217131476Spjd} 218131476Spjd 219199875Straszstruct g_label_desc g_label_msdosfs = { 220131476Spjd .ld_taste = g_label_msdosfs_taste, 221199875Strasz .ld_dir = G_LABEL_MSDOSFS_DIR, 222199875Strasz .ld_enabled = 1 223131476Spjd}; 224199875Strasz 225199875StraszG_LABEL_INIT(msdosfs, g_label_msdosfs, "Create device nodes for MSDOSFS volumes"); 226