diff options
author | Christian Taedcke <christian.taedcke@weidmueller.com> | 2023-11-15 13:44:18 +0100 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2023-11-28 20:10:24 -0500 |
commit | 08f622a12708a0a787c8345532e0b1665b993cab (patch) | |
tree | cb779c9738d596dcb1b5539c10524ff41db372db /fs/fat | |
parent | 601d33f31aebf5b76053c501a91a43e0840b1913 (diff) | |
download | u-boot-08f622a12708a0a787c8345532e0b1665b993cab.tar.gz u-boot-08f622a12708a0a787c8345532e0b1665b993cab.tar.bz2 u-boot-08f622a12708a0a787c8345532e0b1665b993cab.zip |
fs: fat: calculate FAT type based on cluster count
This fixes an issue where the FAT type (FAT12, FAT16) is not
correctly detected, e.g. when the BPB field BS_FilSysType contains the
valid value "FAT ".
According to the FAT spec the field BS_FilSysType has only
informational character and does not determine the FAT type.
The logic of this code is based on the linux kernel implementation
from the file fs/fat/inode.c function fat_fill_super().
For details about FAT see http://elm-chan.org/docs/fat_e.html
Signed-off-by: Christian Taedcke <christian.taedcke@weidmueller.com>
Diffstat (limited to 'fs/fat')
-rw-r--r-- | fs/fat/fat.c | 48 |
1 files changed, 28 insertions, 20 deletions
diff --git a/fs/fat/fat.c b/fs/fat/fat.c index a3522340ef..c368c3b076 100644 --- a/fs/fat/fat.c +++ b/fs/fat/fat.c @@ -26,6 +26,9 @@ #include <linux/compiler.h> #include <linux/ctype.h> +/* maximum number of clusters for FAT12 */ +#define MAX_FAT12 0xFF4 + /* * Convert a string to lowercase. Converts at most 'len' characters, * 'len' may be larger than the length of 'str' if 'str' is NULL @@ -485,6 +488,27 @@ static __u8 mkcksum(struct nameext *nameext) } /* + * Determine if the FAT type is FAT12 or FAT16 + * + * Based on fat_fill_super() from the Linux kernel's fs/fat/inode.c + */ +static int determine_legacy_fat_bits(const boot_sector *bs) +{ + u16 fat_start = bs->reserved; + u32 dir_start = fat_start + bs->fats * bs->fat_length; + u32 rootdir_sectors = get_unaligned_le16(bs->dir_entries) * + sizeof(dir_entry) / + get_unaligned_le16(bs->sector_size); + u32 data_start = dir_start + rootdir_sectors; + u16 sectors = get_unaligned_le16(bs->sectors); + u32 total_sectors = sectors ? sectors : bs->total_sect; + u32 total_clusters = (total_sectors - data_start) / + bs->cluster_size; + + return (total_clusters > MAX_FAT12) ? 16 : 12; +} + +/* * Read boot sector and volume info from a FAT filesystem */ static int @@ -518,7 +542,7 @@ read_bootsectandvi(boot_sector *bs, volume_info *volinfo, int *fatsize) bs->total_sect = FAT2CPU32(bs->total_sect); /* FAT32 entries */ - if (bs->fat_length == 0) { + if (!bs->fat_length && bs->fat32_length) { /* Assume FAT32 */ bs->fat32_length = FAT2CPU32(bs->fat32_length); bs->flags = FAT2CPU16(bs->flags); @@ -529,25 +553,10 @@ read_bootsectandvi(boot_sector *bs, volume_info *volinfo, int *fatsize) *fatsize = 32; } else { vistart = (volume_info *)&(bs->fat32_length); - *fatsize = 0; + *fatsize = determine_legacy_fat_bits(bs); } memcpy(volinfo, vistart, sizeof(volume_info)); - - if (*fatsize == 32) { - if (strncmp(FAT32_SIGN, vistart->fs_type, SIGNLEN) == 0) - goto exit; - } else { - if (strncmp(FAT12_SIGN, vistart->fs_type, SIGNLEN) == 0) { - *fatsize = 12; - goto exit; - } - if (strncmp(FAT16_SIGN, vistart->fs_type, SIGNLEN) == 0) { - *fatsize = 16; - goto exit; - } - } - - debug("Error: broken fs_type sign\n"); + goto exit; fail: ret = -1; exit: @@ -1157,9 +1166,8 @@ int file_fat_detectfs(void) memcpy(vol_label, volinfo.volume_label, 11); vol_label[11] = '\0'; - volinfo.fs_type[5] = '\0'; - printf("Filesystem: %s \"%s\"\n", volinfo.fs_type, vol_label); + printf("Filesystem: FAT%d \"%s\"\n", fatsize, vol_label); return 0; } |