diff options
author | trasz <trasz@FreeBSD.org> | 2015-01-20 20:39:29 +0000 |
---|---|---|
committer | trasz <trasz@FreeBSD.org> | 2015-01-20 20:39:29 +0000 |
commit | 0638ccbfc6cc8bfa31852aa15bc3c7e15bc40406 (patch) | |
tree | 8f48ce245679198d9b1f16d6c998c0b60806e91d /usr.sbin/fstyp/msdosfs.c | |
parent | a20136a3031bbdcb96276992b5f185c751668636 (diff) | |
download | FreeBSD-src-0638ccbfc6cc8bfa31852aa15bc3c7e15bc40406.zip FreeBSD-src-0638ccbfc6cc8bfa31852aa15bc3c7e15bc40406.tar.gz |
MFC r275680:
Add fstyp(8). This utility, named after its SVR4 counterpart, detects
filesystems. It differs from file(1) in that it gives machine-parseable
output, it outputs filesystem labels, doesn't get confused by other
formats metadata, and runs in Capsicum sandbox.
Differential Revision: https://reviews.freebsd.org/D1255
Relnotes: yes
Sponsored by: The FreeBSD Foundation
Diffstat (limited to 'usr.sbin/fstyp/msdosfs.c')
-rw-r--r-- | usr.sbin/fstyp/msdosfs.c | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/usr.sbin/fstyp/msdosfs.c b/usr.sbin/fstyp/msdosfs.c new file mode 100644 index 0000000..b299243 --- /dev/null +++ b/usr.sbin/fstyp/msdosfs.c @@ -0,0 +1,183 @@ +/*- + * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org> + * Copyright (c) 2006 Tobias Reifenberger + * Copyright (c) 2014 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Edward Tomasz Napierala under sponsorship + * from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "fstyp.h" +#include "msdosfs.h" + +#define LABEL_NO_NAME "NO NAME " + +int +fstyp_msdosfs(FILE *fp, char *label, size_t size) +{ + FAT_BSBPB *pfat_bsbpb; + FAT32_BSBPB *pfat32_bsbpb; + FAT_DES *pfat_entry; + uint8_t *sector0, *sector; + uint32_t i; + + sector0 = NULL; + sector = NULL; + + /* Load 1st sector with boot sector and boot parameter block. */ + sector0 = (uint8_t *)read_buf(fp, 0, 512); + if (sector0 == NULL) + return (1); + + /* Check for the FAT boot sector signature. */ + if (sector0[510] != 0x55 || sector0[511] != 0xaa) { + goto error; + } + + /* + * Test if this is really a FAT volume and determine the FAT type. + */ + + pfat_bsbpb = (FAT_BSBPB *)sector0; + pfat32_bsbpb = (FAT32_BSBPB *)sector0; + + if (UINT16BYTES(pfat_bsbpb->BPB_FATSz16) != 0) { + /* + * If the BPB_FATSz16 field is not zero and the string "FAT" is + * at the right place, this should be a FAT12 or FAT16 volume. + */ + if (strncmp(pfat_bsbpb->BS_FilSysType, "FAT", 3) != 0) { + goto error; + } + + /* A volume with no name should have "NO NAME " as label. */ + if (strncmp(pfat_bsbpb->BS_VolLab, LABEL_NO_NAME, + sizeof(pfat_bsbpb->BS_VolLab)) == 0) { + goto endofchecks; + } + strlcpy(label, pfat_bsbpb->BS_VolLab, + MIN(size, sizeof(pfat_bsbpb->BS_VolLab) + 1)); + } else if (UINT32BYTES(pfat32_bsbpb->BPB_FATSz32) != 0) { + uint32_t fat_FirstDataSector, fat_BytesPerSector, offset; + + /* + * If the BPB_FATSz32 field is not zero and the string "FAT" is + * at the right place, this should be a FAT32 volume. + */ + if (strncmp(pfat32_bsbpb->BS_FilSysType, "FAT", 3) != 0) { + goto error; + } + + /* + * If the volume label is not "NO NAME " we're done. + */ + if (strncmp(pfat32_bsbpb->BS_VolLab, LABEL_NO_NAME, + sizeof(pfat32_bsbpb->BS_VolLab)) != 0) { + strlcpy(label, pfat32_bsbpb->BS_VolLab, + MIN(size, sizeof(pfat32_bsbpb->BS_VolLab) + 1)); + goto endofchecks; + } + + /* + * If the volume label "NO NAME " is in the boot sector, the + * label of FAT32 volumes may be stored as a special entry in + * the root directory. + */ + fat_FirstDataSector = + UINT16BYTES(pfat32_bsbpb->BPB_RsvdSecCnt) + + (pfat32_bsbpb->BPB_NumFATs * + UINT32BYTES(pfat32_bsbpb->BPB_FATSz32)); + fat_BytesPerSector = UINT16BYTES(pfat32_bsbpb->BPB_BytsPerSec); + + // fat_FirstDataSector, fat_BytesPerSector); + + for (offset = fat_BytesPerSector * fat_FirstDataSector;; + offset += fat_BytesPerSector) { + sector = (uint8_t *)read_buf(fp, offset, fat_BytesPerSector); + if (sector == NULL) + goto error; + + pfat_entry = (FAT_DES *)sector; + do { + /* No more entries available. */ + if (pfat_entry->DIR_Name[0] == 0) { + goto endofchecks; + } + + /* Skip empty or long name entries. */ + if (pfat_entry->DIR_Name[0] == 0xe5 || + (pfat_entry->DIR_Attr & + FAT_DES_ATTR_LONG_NAME) == + FAT_DES_ATTR_LONG_NAME) { + continue; + } + + /* + * The name of the entry is the volume label if + * ATTR_VOLUME_ID is set. + */ + if (pfat_entry->DIR_Attr & + FAT_DES_ATTR_VOLUME_ID) { + strlcpy(label, pfat_entry->DIR_Name, + MIN(size, + sizeof(pfat_entry->DIR_Name) + 1)); + goto endofchecks; + } + } while((uint8_t *)(++pfat_entry) < + (uint8_t *)(sector + fat_BytesPerSector)); + free(sector); + } + } else { + goto error; + } + +endofchecks: + for (i = size - 1; i > 0; i--) { + if (label[i] == '\0') + continue; + else if (label[i] == ' ') + label[i] = '\0'; + else + break; + } + + free(sector0); + free(sector); + + return (0); + +error: + free(sector0); + free(sector); + + return (1); +} |