diff --git a/common/filetype.c b/common/filetype.c index c8f3582..810d9a5 100644 --- a/common/filetype.c +++ b/common/filetype.c @@ -24,6 +24,7 @@ #include #include #include +#include struct filetype_str { const char *name; /* human readable filetype */ @@ -87,6 +88,10 @@ #define MBR_PART_start_sect 8 #define MBR_OSTYPE_EFI_GPT 0xee +#define FAT_BS_reserved 14 +#define FAT_BS_fats 16 +#define FAT_BS_media 21 + static inline int pmbr_part_valid(const uint8_t *buf) { if (buf[MBR_PART_sys_ind] == MBR_OSTYPE_EFI_GPT && @@ -126,6 +131,49 @@ return 0; } +static inline int fat_valid_media(u8 media) +{ + return (0xf8 <= media || media == 0xf0); +} + +static int is_fat_with_no_mbr(const unsigned char *sect) +{ + if (!get_unaligned_le16(§[FAT_BS_reserved])) + return 0; + + if (!sect[FAT_BS_fats]) + return 0; + + if (!fat_valid_media(sect[FAT_BS_media])) + return 0; + + return 1; +} + +int is_fat_boot_sector(const void *sect) +{ + struct partition_entry *p; + int slot; + + p = (struct partition_entry *) (sect + MBR_Table); + /* max 4 partitions */ + for (slot = 1; slot <= 4; slot++, p++) { + if (p->boot_indicator && p->boot_indicator != 0x80) { + /* + * Even without a valid boot inidicator value + * its still possible this is valid FAT filesystem + * without a partition table. + */ + if (slot == 1 && is_fat_with_no_mbr(sect)) + return 1; + else + return -EINVAL; + } + } + + return 0; +} + enum filetype is_fat_or_mbr(const unsigned char *sector, unsigned long *bootsec) { /* diff --git a/common/partitions.c b/common/partitions.c index 694c6f6..37d9cb7 100644 --- a/common/partitions.c +++ b/common/partitions.c @@ -107,6 +107,8 @@ * useful for compatibility */ type = file_detect_partition_table(buf, SECTOR_SIZE); + if (type == filetype_fat && !is_fat_boot_sector(buf)) + type = filetype_mbr; list_for_each_entry(parser, &partition_parser_list, list) { if (parser->type == type) diff --git a/include/filetype.h b/include/filetype.h index eedf4b4..2c3c38d 100644 --- a/include/filetype.h +++ b/include/filetype.h @@ -44,6 +44,7 @@ enum filetype file_detect_type(const void *_buf, size_t bufsize); enum filetype file_name_detect_type(const char *filename); enum filetype is_fat_or_mbr(const unsigned char *sector, unsigned long *bootsec); +int is_fat_boot_sector(const void *_buf); #define ARM_HEAD_SIZE 0x30 #define ARM_HEAD_MAGICWORD_OFFSET 0x20