* [PATCH v1 0/2] fs: fat: calculate FAT type based on cluster count @ 2023-11-08 12:12 christian.taedcke-oss 2023-11-08 12:12 ` [PATCH v1 1/2] fs: fat: add macro to convert u8[2] to u16 christian.taedcke-oss 2023-11-08 12:12 ` [PATCH v1 2/2] fs: fat: calculate FAT type based on cluster count christian.taedcke-oss 0 siblings, 2 replies; 7+ messages in thread From: christian.taedcke-oss @ 2023-11-08 12:12 UTC (permalink / raw) To: u-boot Cc: Christian Taedcke, Bin Meng, Heinrich Schuchardt, Ilias Apalodimas, Sean Anderson, Simon Glass From: Christian Taedcke <christian.taedcke@weidmueller.com> This series 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 ". This issue occures, for example, if a partition is formatted by swupdate using its diskformat handler. swupdate uses the FAT library from http://elm-chan.org/fsw/ff/ internally. See https://groups.google.com/g/swupdate/c/7Yc3NupjXx8 for a discussion in the swupdate mailing list. Please refer to the commit messages for more details. Christian Taedcke (2): fs: fat: add macro to convert u8[2] to u16 fs: fat: calculate FAT type based on cluster count fs/fat/fat.c | 67 +++++++++++++++++++++++----------------- include/fat.h | 6 ---- test/image/spl_load_fs.c | 2 +- 3 files changed, 40 insertions(+), 35 deletions(-) -- 2.34.1 ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v1 1/2] fs: fat: add macro to convert u8[2] to u16 2023-11-08 12:12 [PATCH v1 0/2] fs: fat: calculate FAT type based on cluster count christian.taedcke-oss @ 2023-11-08 12:12 ` christian.taedcke-oss 2023-11-08 12:47 ` Alexander Dahl 2023-11-08 12:12 ` [PATCH v1 2/2] fs: fat: calculate FAT type based on cluster count christian.taedcke-oss 1 sibling, 1 reply; 7+ messages in thread From: christian.taedcke-oss @ 2023-11-08 12:12 UTC (permalink / raw) To: u-boot Cc: Christian Taedcke, Bin Meng, Heinrich Schuchardt, Ilias Apalodimas, Simon Glass From: Christian Taedcke <christian.taedcke@weidmueller.com> This reduces code duplications. Signed-off-by: Christian Taedcke <christian.taedcke@weidmueller.com> --- fs/fat/fat.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/fs/fat/fat.c b/fs/fat/fat.c index 8ff1fd0ec8..8a0f4e4e6c 100644 --- a/fs/fat/fat.c +++ b/fs/fat/fat.c @@ -25,6 +25,8 @@ #include <linux/compiler.h> #include <linux/ctype.h> +#define FATU8ARRAY2CPU16(x) (((x)[1] << 8) + (x)[0]) + /* * Convert a string to lowercase. Converts at most 'len' characters, * 'len' may be larger than the length of 'str' if 'str' is NULL @@ -571,7 +573,7 @@ static int get_fs_info(fsdata *mydata) mydata->total_sect = bs.total_sect; } else { mydata->fatlength = bs.fat_length; - mydata->total_sect = (bs.sectors[1] << 8) + bs.sectors[0]; + mydata->total_sect = FATU8ARRAY2CPU16(bs.sectors); if (!mydata->total_sect) mydata->total_sect = bs.total_sect; } @@ -583,7 +585,7 @@ static int get_fs_info(fsdata *mydata) mydata->rootdir_sect = mydata->fat_sect + mydata->fatlength * bs.fats; - mydata->sect_size = (bs.sector_size[1] << 8) + bs.sector_size[0]; + mydata->sect_size = FATU8ARRAY2CPU16(bs.sector_size); mydata->clust_size = bs.cluster_size; if (mydata->sect_size != cur_part_info.blksz) { log_err("FAT sector size mismatch (fs=%u, dev=%lu)\n", @@ -607,8 +609,7 @@ static int get_fs_info(fsdata *mydata) (mydata->clust_size * 2); mydata->root_cluster = bs.root_cluster; } else { - mydata->rootdir_size = ((bs.dir_entries[1] * (int)256 + - bs.dir_entries[0]) * + mydata->rootdir_size = (FATU8ARRAY2CPU16(bs.dir_entries) * sizeof(dir_entry)) / mydata->sect_size; mydata->data_begin = mydata->rootdir_sect + -- 2.34.1 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v1 1/2] fs: fat: add macro to convert u8[2] to u16 2023-11-08 12:12 ` [PATCH v1 1/2] fs: fat: add macro to convert u8[2] to u16 christian.taedcke-oss @ 2023-11-08 12:47 ` Alexander Dahl 0 siblings, 0 replies; 7+ messages in thread From: Alexander Dahl @ 2023-11-08 12:47 UTC (permalink / raw) To: christian.taedcke-oss Cc: u-boot, Christian Taedcke, Bin Meng, Heinrich Schuchardt, Ilias Apalodimas, Simon Glass Hello Christian, Am Wed, Nov 08, 2023 at 01:12:38PM +0100 schrieb christian.taedcke-oss@weidmueller.com: > From: Christian Taedcke <christian.taedcke@weidmueller.com> > > This reduces code duplications. > > Signed-off-by: Christian Taedcke <christian.taedcke@weidmueller.com> > --- > > fs/fat/fat.c | 9 +++++---- > 1 file changed, 5 insertions(+), 4 deletions(-) > > diff --git a/fs/fat/fat.c b/fs/fat/fat.c > index 8ff1fd0ec8..8a0f4e4e6c 100644 > --- a/fs/fat/fat.c > +++ b/fs/fat/fat.c > @@ -25,6 +25,8 @@ > #include <linux/compiler.h> > #include <linux/ctype.h> > > +#define FATU8ARRAY2CPU16(x) (((x)[1] << 8) + (x)[0]) This does the same as the generic `get_unaligned_le16()` … why not use that? Greets Alex > + > /* > * Convert a string to lowercase. Converts at most 'len' characters, > * 'len' may be larger than the length of 'str' if 'str' is NULL > @@ -571,7 +573,7 @@ static int get_fs_info(fsdata *mydata) > mydata->total_sect = bs.total_sect; > } else { > mydata->fatlength = bs.fat_length; > - mydata->total_sect = (bs.sectors[1] << 8) + bs.sectors[0]; > + mydata->total_sect = FATU8ARRAY2CPU16(bs.sectors); > if (!mydata->total_sect) > mydata->total_sect = bs.total_sect; > } > @@ -583,7 +585,7 @@ static int get_fs_info(fsdata *mydata) > > mydata->rootdir_sect = mydata->fat_sect + mydata->fatlength * bs.fats; > > - mydata->sect_size = (bs.sector_size[1] << 8) + bs.sector_size[0]; > + mydata->sect_size = FATU8ARRAY2CPU16(bs.sector_size); > mydata->clust_size = bs.cluster_size; > if (mydata->sect_size != cur_part_info.blksz) { > log_err("FAT sector size mismatch (fs=%u, dev=%lu)\n", > @@ -607,8 +609,7 @@ static int get_fs_info(fsdata *mydata) > (mydata->clust_size * 2); > mydata->root_cluster = bs.root_cluster; > } else { > - mydata->rootdir_size = ((bs.dir_entries[1] * (int)256 + > - bs.dir_entries[0]) * > + mydata->rootdir_size = (FATU8ARRAY2CPU16(bs.dir_entries) * > sizeof(dir_entry)) / > mydata->sect_size; > mydata->data_begin = mydata->rootdir_sect + > -- > 2.34.1 > ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v1 2/2] fs: fat: calculate FAT type based on cluster count 2023-11-08 12:12 [PATCH v1 0/2] fs: fat: calculate FAT type based on cluster count christian.taedcke-oss 2023-11-08 12:12 ` [PATCH v1 1/2] fs: fat: add macro to convert u8[2] to u16 christian.taedcke-oss @ 2023-11-08 12:12 ` christian.taedcke-oss 2023-11-08 13:39 ` Heinrich Schuchardt 2023-11-08 18:57 ` Sean Anderson 1 sibling, 2 replies; 7+ messages in thread From: christian.taedcke-oss @ 2023-11-08 12:12 UTC (permalink / raw) To: u-boot Cc: Christian Taedcke, Bin Meng, Heinrich Schuchardt, Ilias Apalodimas, Sean Anderson, Simon Glass From: Christian Taedcke <christian.taedcke@weidmueller.com> 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> --- fs/fat/fat.c | 58 +++++++++++++++++++++++----------------- include/fat.h | 6 ----- test/image/spl_load_fs.c | 2 +- 3 files changed, 35 insertions(+), 31 deletions(-) diff --git a/fs/fat/fat.c b/fs/fat/fat.c index 8a0f4e4e6c..9179257ff2 100644 --- a/fs/fat/fat.c +++ b/fs/fat/fat.c @@ -27,6 +27,9 @@ #define FATU8ARRAY2CPU16(x) (((x)[1] << 8) + (x)[0]) +/* 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,32 @@ static __u8 mkcksum(struct nameext *nameext) return ret; } +/* + * Determine the FAT type + * + * Based on fat_fill_super() from the Linux kernel's fs/fat/inode.c + */ +static int +determine_fat_bits(const boot_sector *bs) +{ + if (!bs->fat_length && bs->fat32_length) { + return 32; + } else { + u16 fat_start = bs->reserved; + u32 dir_start = fat_start + bs->fats * bs->fat_length; + u32 rootdir_sectors = FATU8ARRAY2CPU16(bs->dir_entries) * + sizeof(dir_entry) / + FATU8ARRAY2CPU16(bs->sector_size); + u32 data_start = dir_start + rootdir_sectors; + u16 sectors = FATU8ARRAY2CPU16(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 */ @@ -493,7 +522,6 @@ read_bootsectandvi(boot_sector *bs, volume_info *volinfo, int *fatsize) { __u8 *block; volume_info *vistart; - int ret = 0; if (cur_dev == NULL) { debug("Error: no device selected\n"); @@ -508,7 +536,8 @@ read_bootsectandvi(boot_sector *bs, volume_info *volinfo, int *fatsize) if (disk_read(0, 1, block) < 0) { debug("Error: reading block\n"); - goto fail; + free(block); + return -1; } memcpy(bs, block, sizeof(boot_sector)); @@ -527,33 +556,15 @@ read_bootsectandvi(boot_sector *bs, volume_info *volinfo, int *fatsize) bs->info_sector = FAT2CPU16(bs->info_sector); bs->backup_boot = FAT2CPU16(bs->backup_boot); vistart = (volume_info *)(block + sizeof(boot_sector)); - *fatsize = 32; } else { vistart = (volume_info *)&(bs->fat32_length); - *fatsize = 0; } 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; - } - } + *fatsize = determine_fat_bits(bs); - debug("Error: broken fs_type sign\n"); -fail: - ret = -1; -exit: free(block); - return ret; + return 0; } static int get_fs_info(fsdata *mydata) @@ -1158,9 +1169,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; } diff --git a/include/fat.h b/include/fat.h index a9756fb4cd..3dce99a23c 100644 --- a/include/fat.h +++ b/include/fat.h @@ -34,12 +34,6 @@ struct disk_partition; /* Maximum number of entry for long file name according to spec */ #define MAX_LFN_SLOT 20 -/* Filesystem identifiers */ -#define FAT12_SIGN "FAT12 " -#define FAT16_SIGN "FAT16 " -#define FAT32_SIGN "FAT32 " -#define SIGNLEN 8 - /* File attributes */ #define ATTR_RO 1 #define ATTR_HIDDEN 2 diff --git a/test/image/spl_load_fs.c b/test/image/spl_load_fs.c index 297ab08a82..90e640b5de 100644 --- a/test/image/spl_load_fs.c +++ b/test/image/spl_load_fs.c @@ -220,7 +220,7 @@ static size_t create_fat(void *dst, size_t size, const char *filename, bs->root_cluster = cpu_to_le32(root_sector); vi->ext_boot_sign = 0x29; - memcpy(vi->fs_type, FAT32_SIGN, sizeof(vi->fs_type)); + memcpy(vi->fs_type, "FAT32 ", sizeof(vi->fs_type)); memcpy(dst + 0x1fe, "\x55\xAA", 2); -- 2.34.1 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v1 2/2] fs: fat: calculate FAT type based on cluster count 2023-11-08 12:12 ` [PATCH v1 2/2] fs: fat: calculate FAT type based on cluster count christian.taedcke-oss @ 2023-11-08 13:39 ` Heinrich Schuchardt 2023-11-08 18:57 ` Sean Anderson 1 sibling, 0 replies; 7+ messages in thread From: Heinrich Schuchardt @ 2023-11-08 13:39 UTC (permalink / raw) To: christian.taedcke-oss Cc: Christian Taedcke, Bin Meng, Ilias Apalodimas, Sean Anderson, Simon Glass, u-boot On 11/8/23 04:12, christian.taedcke-oss@weidmueller.com wrote: > From: Christian Taedcke <christian.taedcke@weidmueller.com> > > 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> > --- > > fs/fat/fat.c | 58 +++++++++++++++++++++++----------------- > include/fat.h | 6 ----- > test/image/spl_load_fs.c | 2 +- > 3 files changed, 35 insertions(+), 31 deletions(-) > > diff --git a/fs/fat/fat.c b/fs/fat/fat.c > index 8a0f4e4e6c..9179257ff2 100644 > --- a/fs/fat/fat.c > +++ b/fs/fat/fat.c > @@ -27,6 +27,9 @@ > > #define FATU8ARRAY2CPU16(x) (((x)[1] << 8) + (x)[0]) > > +/* 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,32 @@ static __u8 mkcksum(struct nameext *nameext) > return ret; > } > > +/* > + * Determine the FAT type > + * > + * Based on fat_fill_super() from the Linux kernel's fs/fat/inode.c > + */ > +static int > +determine_fat_bits(const boot_sector *bs) > +{ > + if (!bs->fat_length && bs->fat32_length) { > + return 32; > + } else { > + u16 fat_start = bs->reserved; > + u32 dir_start = fat_start + bs->fats * bs->fat_length; > + u32 rootdir_sectors = FATU8ARRAY2CPU16(bs->dir_entries) * > + sizeof(dir_entry) / > + FATU8ARRAY2CPU16(bs->sector_size); > + u32 data_start = dir_start + rootdir_sectors; > + u16 sectors = FATU8ARRAY2CPU16(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 > */ > @@ -493,7 +522,6 @@ read_bootsectandvi(boot_sector *bs, volume_info *volinfo, int *fatsize) > { > __u8 *block; > volume_info *vistart; > - int ret = 0; > > if (cur_dev == NULL) { > debug("Error: no device selected\n"); > @@ -508,7 +536,8 @@ read_bootsectandvi(boot_sector *bs, volume_info *volinfo, int *fatsize) > > if (disk_read(0, 1, block) < 0) { > debug("Error: reading block\n"); > - goto fail; > + free(block); > + return -1; Thanks for correcting the FAT type determination. The change above does not look wrong. But as it is an unrelated change, please, put it into a separate patch. > } > > memcpy(bs, block, sizeof(boot_sector)); > @@ -527,33 +556,15 @@ read_bootsectandvi(boot_sector *bs, volume_info *volinfo, int *fatsize) > bs->info_sector = FAT2CPU16(bs->info_sector); > bs->backup_boot = FAT2CPU16(bs->backup_boot); > vistart = (volume_info *)(block + sizeof(boot_sector)); > - *fatsize = 32; > } else { > vistart = (volume_info *)&(bs->fat32_length); > - *fatsize = 0; > } > 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; > - } > - } > + *fatsize = determine_fat_bits(bs); > > - debug("Error: broken fs_type sign\n"); > -fail: > - ret = -1; > -exit: > free(block); > - return ret; > + return 0; > } > > static int get_fs_info(fsdata *mydata) > @@ -1158,9 +1169,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; > } > diff --git a/include/fat.h b/include/fat.h > index a9756fb4cd..3dce99a23c 100644 > --- a/include/fat.h > +++ b/include/fat.h > @@ -34,12 +34,6 @@ struct disk_partition; > /* Maximum number of entry for long file name according to spec */ > #define MAX_LFN_SLOT 20 > > -/* Filesystem identifiers */ > -#define FAT12_SIGN "FAT12 " > -#define FAT16_SIGN "FAT16 " > -#define FAT32_SIGN "FAT32 " > -#define SIGNLEN 8 > - > /* File attributes */ > #define ATTR_RO 1 > #define ATTR_HIDDEN 2 > diff --git a/test/image/spl_load_fs.c b/test/image/spl_load_fs.c > index 297ab08a82..90e640b5de 100644 > --- a/test/image/spl_load_fs.c > +++ b/test/image/spl_load_fs.c > @@ -220,7 +220,7 @@ static size_t create_fat(void *dst, size_t size, const char *filename, > bs->root_cluster = cpu_to_le32(root_sector); > > vi->ext_boot_sign = 0x29; > - memcpy(vi->fs_type, FAT32_SIGN, sizeof(vi->fs_type)); > + memcpy(vi->fs_type, "FAT32 ", sizeof(vi->fs_type)); This change is not described in the commit message. Putting it into a separate patch would be preferable. Best regards Heinrich > > memcpy(dst + 0x1fe, "\x55\xAA", 2); > ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v1 2/2] fs: fat: calculate FAT type based on cluster count 2023-11-08 12:12 ` [PATCH v1 2/2] fs: fat: calculate FAT type based on cluster count christian.taedcke-oss 2023-11-08 13:39 ` Heinrich Schuchardt @ 2023-11-08 18:57 ` Sean Anderson 2023-11-08 18:59 ` Sean Anderson 1 sibling, 1 reply; 7+ messages in thread From: Sean Anderson @ 2023-11-08 18:57 UTC (permalink / raw) To: christian.taedcke-oss, u-boot Cc: Christian Taedcke, Bin Meng, Heinrich Schuchardt, Ilias Apalodimas, Simon Glass On 11/8/23 07:12, christian.taedcke-oss@weidmueller.com wrote: > From: Christian Taedcke <christian.taedcke@weidmueller.com> > > 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> Have you run bloat-o-meter on this? FAT is used in SPL a lot. Would it be possible to write a test for this, especially for a FAT12 filesystem with 4084 data sectors and a FAT16 filesystem with 4085? > --- > > fs/fat/fat.c | 58 +++++++++++++++++++++++----------------- > include/fat.h | 6 ----- > test/image/spl_load_fs.c | 2 +- > 3 files changed, 35 insertions(+), 31 deletions(-) > > diff --git a/fs/fat/fat.c b/fs/fat/fat.c > index 8a0f4e4e6c..9179257ff2 100644 > --- a/fs/fat/fat.c > +++ b/fs/fat/fat.c > @@ -27,6 +27,9 @@ > > #define FATU8ARRAY2CPU16(x) (((x)[1] << 8) + (x)[0]) > > +/* 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,32 @@ static __u8 mkcksum(struct nameext *nameext) > return ret; > } > > +/* > + * Determine the FAT type > + * > + * Based on fat_fill_super() from the Linux kernel's fs/fat/inode.c > + */ > +static int > +determine_fat_bits(const boot_sector *bs) > +{ > + if (!bs->fat_length && bs->fat32_length) { > + return 32; > + } else { > + u16 fat_start = bs->reserved; > + u32 dir_start = fat_start + bs->fats * bs->fat_length; > + u32 rootdir_sectors = FATU8ARRAY2CPU16(bs->dir_entries) * > + sizeof(dir_entry) / > + FATU8ARRAY2CPU16(bs->sector_size); Note that technically we are supposed to round up. > + u32 data_start = dir_start + rootdir_sectors; > + u16 sectors = FATU8ARRAY2CPU16(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; > + } > +} > + This should be merged with... > /* > * Read boot sector and volume info from a FAT filesystem > */ > @@ -493,7 +522,6 @@ read_bootsectandvi(boot_sector *bs, volume_info *volinfo, int *fatsize) > { > __u8 *block; > volume_info *vistart; > - int ret = 0; > > if (cur_dev == NULL) { > debug("Error: no device selected\n"); > @@ -508,7 +536,8 @@ read_bootsectandvi(boot_sector *bs, volume_info *volinfo, int *fatsize) > > if (disk_read(0, 1, block) < 0) { > debug("Error: reading block\n"); > - goto fail; > + free(block); > + return -1; > } > > memcpy(bs, block, sizeof(boot_sector)); > @@ -527,33 +556,15 @@ read_bootsectandvi(boot_sector *bs, volume_info *volinfo, int *fatsize) > bs->info_sector = FAT2CPU16(bs->info_sector); > bs->backup_boot = FAT2CPU16(bs->backup_boot); > vistart = (volume_info *)(block + sizeof(boot_sector)); > - *fatsize = 32; > } else { > vistart = (volume_info *)&(bs->fat32_length); > - *fatsize = 0; > } ... these if statements (above) > 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; > - } > - } I think we should still verify these as long as vistart->ext_boot_sign is 0x29. --Sean > + *fatsize = determine_fat_bits(bs); > > - debug("Error: broken fs_type sign\n"); > -fail: > - ret = -1; > -exit: > free(block); > - return ret; > + return 0; > } > > static int get_fs_info(fsdata *mydata) > @@ -1158,9 +1169,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; > } > diff --git a/include/fat.h b/include/fat.h > index a9756fb4cd..3dce99a23c 100644 > --- a/include/fat.h > +++ b/include/fat.h > @@ -34,12 +34,6 @@ struct disk_partition; > /* Maximum number of entry for long file name according to spec */ > #define MAX_LFN_SLOT 20 > > -/* Filesystem identifiers */ > -#define FAT12_SIGN "FAT12 " > -#define FAT16_SIGN "FAT16 " > -#define FAT32_SIGN "FAT32 " > -#define SIGNLEN 8 > - > /* File attributes */ > #define ATTR_RO 1 > #define ATTR_HIDDEN 2 > diff --git a/test/image/spl_load_fs.c b/test/image/spl_load_fs.c > index 297ab08a82..90e640b5de 100644 > --- a/test/image/spl_load_fs.c > +++ b/test/image/spl_load_fs.c > @@ -220,7 +220,7 @@ static size_t create_fat(void *dst, size_t size, const char *filename, > bs->root_cluster = cpu_to_le32(root_sector); > > vi->ext_boot_sign = 0x29; > - memcpy(vi->fs_type, FAT32_SIGN, sizeof(vi->fs_type)); > + memcpy(vi->fs_type, "FAT32 ", sizeof(vi->fs_type)); > > memcpy(dst + 0x1fe, "\x55\xAA", 2); > --Sean ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v1 2/2] fs: fat: calculate FAT type based on cluster count 2023-11-08 18:57 ` Sean Anderson @ 2023-11-08 18:59 ` Sean Anderson 0 siblings, 0 replies; 7+ messages in thread From: Sean Anderson @ 2023-11-08 18:59 UTC (permalink / raw) To: christian.taedcke-oss, u-boot Cc: Christian Taedcke, Bin Meng, Heinrich Schuchardt, Ilias Apalodimas, Simon Glass On 11/8/23 13:57, Sean Anderson wrote: > On 11/8/23 07:12, christian.taedcke-oss@weidmueller.com wrote: >> From: Christian Taedcke <christian.taedcke@weidmueller.com> >> >> 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> > > Have you run bloat-o-meter on this? FAT is used in SPL a lot. > > Would it be possible to write a test for this, especially for a FAT12 filesystem with > 4084 data sectors and a FAT16 filesystem with 4085? > >> --- >> >> fs/fat/fat.c | 58 +++++++++++++++++++++++----------------- >> include/fat.h | 6 ----- >> test/image/spl_load_fs.c | 2 +- >> 3 files changed, 35 insertions(+), 31 deletions(-) >> >> diff --git a/fs/fat/fat.c b/fs/fat/fat.c >> index 8a0f4e4e6c..9179257ff2 100644 >> --- a/fs/fat/fat.c >> +++ b/fs/fat/fat.c >> @@ -27,6 +27,9 @@ >> #define FATU8ARRAY2CPU16(x) (((x)[1] << 8) + (x)[0]) >> +/* 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,32 @@ static __u8 mkcksum(struct nameext *nameext) >> return ret; >> } >> +/* >> + * Determine the FAT type >> + * >> + * Based on fat_fill_super() from the Linux kernel's fs/fat/inode.c >> + */ >> +static int >> +determine_fat_bits(const boot_sector *bs) >> +{ >> + if (!bs->fat_length && bs->fat32_length) { >> + return 32; >> + } else { >> + u16 fat_start = bs->reserved; >> + u32 dir_start = fat_start + bs->fats * bs->fat_length; >> + u32 rootdir_sectors = FATU8ARRAY2CPU16(bs->dir_entries) * >> + sizeof(dir_entry) / >> + FATU8ARRAY2CPU16(bs->sector_size); > > Note that technically we are supposed to round up. > >> + u32 data_start = dir_start + rootdir_sectors; >> + u16 sectors = FATU8ARRAY2CPU16(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; >> + } >> +} >> + > > This should be merged with... > >> /* >> * Read boot sector and volume info from a FAT filesystem >> */ >> @@ -493,7 +522,6 @@ read_bootsectandvi(boot_sector *bs, volume_info *volinfo, int *fatsize) >> { >> __u8 *block; >> volume_info *vistart; >> - int ret = 0; >> if (cur_dev == NULL) { >> debug("Error: no device selected\n"); >> @@ -508,7 +536,8 @@ read_bootsectandvi(boot_sector *bs, volume_info *volinfo, int *fatsize) >> if (disk_read(0, 1, block) < 0) { >> debug("Error: reading block\n"); >> - goto fail; >> + free(block); >> + return -1; >> } >> memcpy(bs, block, sizeof(boot_sector)); >> @@ -527,33 +556,15 @@ read_bootsectandvi(boot_sector *bs, volume_info *volinfo, int *fatsize) >> bs->info_sector = FAT2CPU16(bs->info_sector); >> bs->backup_boot = FAT2CPU16(bs->backup_boot); >> vistart = (volume_info *)(block + sizeof(boot_sector)); >> - *fatsize = 32; >> } else { >> vistart = (volume_info *)&(bs->fat32_length); >> - *fatsize = 0; >> } > > ... these if statements (above) > >> 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; >> - } >> - } > > I think we should still verify these as long as vistart->ext_boot_sign is 0x29. To add to this, if we don't want to verify these we should at least check the heuristics from [1]. --Sean [1] https://www.win.tue.nl/~aeb/linux/fs/fat/fat-2.html >> + *fatsize = determine_fat_bits(bs); >> - debug("Error: broken fs_type sign\n"); >> -fail: >> - ret = -1; >> -exit: >> free(block); >> - return ret; >> + return 0; >> } >> static int get_fs_info(fsdata *mydata) >> @@ -1158,9 +1169,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; >> } >> diff --git a/include/fat.h b/include/fat.h >> index a9756fb4cd..3dce99a23c 100644 >> --- a/include/fat.h >> +++ b/include/fat.h >> @@ -34,12 +34,6 @@ struct disk_partition; >> /* Maximum number of entry for long file name according to spec */ >> #define MAX_LFN_SLOT 20 >> -/* Filesystem identifiers */ >> -#define FAT12_SIGN "FAT12 " >> -#define FAT16_SIGN "FAT16 " >> -#define FAT32_SIGN "FAT32 " >> -#define SIGNLEN 8 >> - >> /* File attributes */ >> #define ATTR_RO 1 >> #define ATTR_HIDDEN 2 >> diff --git a/test/image/spl_load_fs.c b/test/image/spl_load_fs.c >> index 297ab08a82..90e640b5de 100644 >> --- a/test/image/spl_load_fs.c >> +++ b/test/image/spl_load_fs.c >> @@ -220,7 +220,7 @@ static size_t create_fat(void *dst, size_t size, const char *filename, >> bs->root_cluster = cpu_to_le32(root_sector); >> vi->ext_boot_sign = 0x29; >> - memcpy(vi->fs_type, FAT32_SIGN, sizeof(vi->fs_type)); >> + memcpy(vi->fs_type, "FAT32 ", sizeof(vi->fs_type)); >> memcpy(dst + 0x1fe, "\x55\xAA", 2); > > --Sean ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2023-11-08 18:59 UTC | newest] Thread overview: 7+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2023-11-08 12:12 [PATCH v1 0/2] fs: fat: calculate FAT type based on cluster count christian.taedcke-oss 2023-11-08 12:12 ` [PATCH v1 1/2] fs: fat: add macro to convert u8[2] to u16 christian.taedcke-oss 2023-11-08 12:47 ` Alexander Dahl 2023-11-08 12:12 ` [PATCH v1 2/2] fs: fat: calculate FAT type based on cluster count christian.taedcke-oss 2023-11-08 13:39 ` Heinrich Schuchardt 2023-11-08 18:57 ` Sean Anderson 2023-11-08 18:59 ` Sean Anderson
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox