* [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
* [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 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
* 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