diff --git a/fs/fat/fs_configfat.c b/fs/fat/fs_configfat.c index 2974e9f028..13feeaf912 100644 --- a/fs/fat/fs_configfat.c +++ b/fs/fat/fs_configfat.c @@ -56,15 +56,198 @@ ****************************************************************************/ /**************************************************************************** - * Name: + * Name: mkfatfs_nfatsect12 * * Description: + * Calculate the number of sectors need for the fat in a FAT12 file system. * * Input: + * fmt - Caller specified format parameters + * var - Other format parameters that are not caller specifiable. (Most + * set by mkfatfs_configfatfs()). + * navailsects - The number of sectors available for both FAT and data. + * This is a precalculated value equal to the total number of sectors + * minus the number of root directory sectors and minus the number of + * reserved sectors. * * Return: + * 0: That calculation would have overflowed + * >0: The total size of the FAT in sectors. * ****************************************************************************/ +static inline uint32 mkfatfs_nfatsect12(FAR struct fat_format_s *fmt, + FAR struct fat_var_s *var, + uint32 navailsects) +{ + uint32 denom ; + uint32 numer; + + /* For FAT12, the cluster number is held in a 12-bit number or 1.5 bytes per + * cluster reference. So each FAT sector will hold sectorsize/1.5 cluster + * references (except for the first sector of each FAT which has two reserved + * 12-bit values). And the total number of FAT sectors needed is: + * + * nfatsects = nfats * (1.5 * (ndataclust + 2) / sectorsize) + * + * where: + * + * ndataclust = ndatasect / clustsize + * nvailsects = nfatsects + ndatasect + * + * The solution to this set of linear equations is: + * + * nfatsects = nfats * (3 * navailsects + 6 * clustersize) / + * (3 * nfats + 2 * sectorsize * clustersize) + * + * The numerator would overflow uint32 if: + * + * 3 * navailsects + 6 * clustersize > 0xffffffff + * + * Or + * + * navailsects > 0x55555555 - 2 * clustersize + */ + + if (navailsects <= (0x55555555 - (1 << (fmt->ff_clustshift + 1)))) + { + denom = (fmt->ff_nfats << 1) + fmt->ff_nfats + + (var->fv_sectorsize << (fmt->ff_clustshift + 1)); + numer = (navailsects << 1) + navailsects + + (1 << (fmt->ff_clustshift + 2)) + (1 << (fmt->ff_clustshift + 1)); + return fmt->ff_nfats * (numer + denom - 1) / denom; + } + else + { + return 0; + } +} + +/**************************************************************************** + * Name: mkfatfs_nfatsect16 + * + * Description: + * Calculate the number of sectors need for the fat in a FAT16 file system. + * + * Input: + * fmt - Caller specified format parameters + * var - Other format parameters that are not caller specifiable. (Most + * set by mkfatfs_configfatfs()). + * navailsects - The number of sectors available for both FAT and data. + * This is a precalculated value equal to the total number of sectors + * minus the number of root directory sectors and minus the number of + * reserved sectors. + * + * Return: + * The total size of the FAT in sectors. + * + ****************************************************************************/ +static inline uint32 mkfatfs_nfatsect16(FAR struct fat_format_s *fmt, + FAR struct fat_var_s *var, + uint32 navailsects) +{ + uint32 denom; + uint32 numer; + + /* For FAT16, the cluster number is held in a 16-bit number or 2 bytes per + * cluster reference. So each FAT sector will hold sectorsize/2 cluster + * references (except for the first sector of each FAT which has two reserved + * 16-bit values). And the total number of FAT sectors needed is: + * + * nfatsects = nfats * (2 * (ndataclust + 2) / sectorsize) + * + * where: + * + * ndataclust = ndatasect / clustsize + * nvailsects = nfatsects + ndatasect + * + * The solution to this set of linear equations is: + * + * nfatsects = nfats * (navailsects + 2 * clustersize) / + * (nfats + sectorsize * clustersize / 2) + * + * Overflow in the calculation of the numerator could occur if: + * + * navailsects > 0xffffffff - 2 * clustersize + */ + + if (fmt->ff_clustshift == 0) + { + denom = fmt->ff_nfats + (var->fv_sectorsize >> 1); + numer = navailsects + 2; + } + else + { + denom = fmt->ff_nfats + (var->fv_sectorsize << (fmt->ff_clustshift - 1)); + numer = navailsects + (1 << (fmt->ff_clustshift + 1)); + } + return fmt->ff_nfats * (numer + denom - 1) / denom; +} + +/**************************************************************************** + * Name: mkfatfs_nfatsect32 + * + * Description: + * Calculate the number of sectors need for the fat in a FAT32 file system. + * + * Input: + * fmt - Caller specified format parameters + * var - Other format parameters that are not caller specifiable. (Most + * set by mkfatfs_configfatfs()). + * navailsects - The number of sectors available for both FAT and data. + * This is a precalculated value equal to the total number of sectors + * minus the number of root directory sectors and minus the number of + * reserved sectors. + * + * Return: + * The total size of the FAT in sectors. + * + ****************************************************************************/ +static inline uint32 mkfatfs_nfatsect32(FAR struct fat_format_s *fmt, + FAR struct fat_var_s *var, + uint32 navailsects) +{ + uint32 denom; + uint32 numer; + + /* For FAT32, the cluster number is held in a 32-bit number or 4 bytes per + * cluster reference. So each FAT sector will hold sectorsize/4 cluster + * references (except for the first sector of each FAT which has three reserved + * 32-bit values). And the total number of FAT sectors needed is: + * + * nfatsects = nfats * (4 * (ndataclust + 3) / sectorsize) + * + * where: + * + * ndataclust = ndatasect / clustsize + * nvailsects = nfatsects + ndatasect + * + * The solution to this set of linear equations is: + * + * nfatsects = nfats * (navailsects + 3 * clustersize) / + * (nfats + sectorsize * clustersize / 4) + * + * Overflow in the calculation of the numerator could occur if: + * + * navailsects > 0xffffffff - 3 * clustersize + */ + + if (fmt->ff_clustshift == 0) + { + denom = fmt->ff_nfats + (var->fv_sectorsize >> 2); + numer = navailsects + 3; + } + else if (fmt->ff_clustshift == 1) + { + denom = fmt->ff_nfats + (var->fv_sectorsize >> 1); + numer = navailsects + 6; + } + else + { + denom = fmt->ff_nfats + (var->fv_sectorsize << (fmt->ff_clustshift - 2)); + numer = navailsects + (1 << (fmt->ff_clustshift + 1)) + (1 << fmt->ff_clustshift); + } + return fmt->ff_nfats * (numer + denom - 1) / denom; +} /**************************************************************************** * Global Functions diff --git a/fs/fat/fs_mkfatfs.h b/fs/fat/fs_mkfatfs.h index c8f22d815e..b149167563 100644 --- a/fs/fat/fs_mkfatfs.h +++ b/fs/fat/fs_mkfatfs.h @@ -99,12 +99,13 @@ struct fat_var_s ubyte fv_jump[3]; /* 3-byte boot jump instruction */ ubyte fv_sectshift; /* Log2 of fv_sectorsize */ ubyte fv_nrootdirsects; /* Number of root directory sectors */ + ubyte fv_fatsize; /* FAT size: 0 (not determined), 12, 16, or 32 */ uint16 fv_bootcodesize; /* Size of array at fv_bootcode */ uint32 fv_createtime; /* Creation time */ uint32 fv_sectorsize; /* Size of one hardware sector */ uint32 fv_nsectors; /* Number of sectors */ uint32 fv_nfatsects; /* Number of sectors in each FAT */ - uint32 fv_clustcount; /* Number of clusters */ + uint32 fv_nclusters; /* Number of clusters */ ubyte *fv_sect; /* Allocated working sector buffer */ const ubyte *fv_bootcode; /* Points to boot code to put into MBR */ }; diff --git a/fs/fat/fs_writefat.c b/fs/fat/fs_writefat.c index 287e4f0f84..2270869ffc 100644 --- a/fs/fat/fs_writefat.c +++ b/fs/fat/fs_writefat.c @@ -88,7 +88,7 @@ static inline void mkfatfs_initmbr(FAR struct fat_format_s *fmt, /* 1@13: Sectors per allocation unit: 2**n, n=0..7 */ - MBR_PUTSECPERCLUS(var->fv_sect, fmt->ff_clustsize); + MBR_PUTSECPERCLUS(var->fv_sect, (1 << fmt->ff_clustshift)); /* 2@14: Reserved sector count: Usually 32 */ @@ -250,7 +250,7 @@ static inline void mkfatfs_initfsinfo(FAR struct fat_format_s *fmt, /* 4@488: Last free cluster count on volume */ - FSI_PUTFREECOUNT(var->fv_sect, var->fv_clustcount - 1); + FSI_PUTFREECOUNT(var->fv_sect, var->fv_nclusters - 1); /* 4@492: Cluster number of 1st free cluster */ diff --git a/include/nuttx/mkfatfs.h b/include/nuttx/mkfatfs.h index c0ca82280f..1a7595f6e5 100644 --- a/include/nuttx/mkfatfs.h +++ b/include/nuttx/mkfatfs.h @@ -49,7 +49,7 @@ #define MKFATFS_DEFAULT_BBCHECK FALSE /* FALSE: No bad block check */ #define MKFATFS_DEFAULT_NFATS 2 /* 2: Default number of FATs */ -#define MKFATFS_DEFAULT_FATSIZE 0 /* 0: Autoselect FAT size */ +#define MKFATFS_DEFAULT_FATSIZE 0xff /* 0: Autoselect FAT size */ #define MKFATFS_DEFAULT_CLUSTSIZE 0 /* 0: Autoselect cluster size */ #define MKFATFS_DEFAULT_VOLUMELABEL { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } #define MKFATFS_DEFAULT_BKUPBOOT 0 /* 0: Determine sector number of the backup boot sector */ @@ -86,7 +86,7 @@ struct fat_format_s { ubyte ff_nfats; /* Number of FATs */ ubyte ff_fatsize; /* FAT size: 0 (autoselect), 12, 16, or 32 */ - ubyte ff_clustsize; /* Number of sectors per cluster: 0 (autoselect) */ + ubyte ff_clustshift; /* Log2 of sectors per cluster: 0-5, 0xff (autoselect) */ ubyte ff_volumelabel[11]; /* Volume label */ uint16 ff_backupboot; /* Sector number of the backup boot sector (0=use default)*/ uint16 ff_rootdirentries; /* Number of root directory entries */