summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/filetype.c48
-rw-r--r--common/partitions.c2
-rw-r--r--include/filetype.h1
3 files changed, 51 insertions, 0 deletions
diff --git a/common/filetype.c b/common/filetype.c
index c8f3582cd1..810d9a505c 100644
--- a/common/filetype.c
+++ b/common/filetype.c
@@ -24,6 +24,7 @@
#include <malloc.h>
#include <errno.h>
#include <envfs.h>
+#include <disks.h>
struct filetype_str {
const char *name; /* human readable filetype */
@@ -87,6 +88,10 @@ const char *file_type_to_short_string(enum filetype f)
#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 @@ static int is_gpt_valid(const uint8_t *buf)
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(&sect[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 694c6f6dd5..37d9cb7edc 100644
--- a/common/partitions.c
+++ b/common/partitions.c
@@ -107,6 +107,8 @@ static struct partition_parser *partition_parser_get_by_filetype(uint8_t *buf)
* 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 eedf4b4afe..2c3c38ddd8 100644
--- a/include/filetype.h
+++ b/include/filetype.h
@@ -44,6 +44,7 @@ enum filetype file_detect_partition_table(const void *_buf, size_t bufsize);
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