diff --git a/thirdparty/fatfs/00history.txt b/thirdparty/fatfs/00history.txt index c0e3e74..74ff3e0 100644 --- a/thirdparty/fatfs/00history.txt +++ b/thirdparty/fatfs/00history.txt @@ -328,3 +328,13 @@ R0.13c (October 14, 2018) Fixed creating a sub-directory in the fragmented sub-directory on the exFAT volume collapses FAT chain of the parent directory. (appeared at R0.12) Fixed f_getcwd() cause output buffer overrun when the buffer has a valid drive number. (appeared at R0.13b) + + +R0.14 (October 14, 2019) + Added support for 64-bit LBA and GUID partition table (FF_LBA64 = 1) + Changed some API functions, f_mkfs() and f_fdisk(). + Fixed f_open() function cannot find the file with file name in length of FF_MAX_LFN characters. + Fixed f_readdir() function cannot retrieve long file names in length of FF_MAX_LFN - 1 characters. + Fixed f_readdir() function returns file names with wrong case conversion. (appeared at R0.12) + Fixed f_mkfs() function can fail to create exFAT volume in the second partition. (appeared at R0.12) + diff --git a/thirdparty/fatfs/00readme.txt b/thirdparty/fatfs/00readme.txt index 53de9aa..f39a89a 100644 --- a/thirdparty/fatfs/00readme.txt +++ b/thirdparty/fatfs/00readme.txt @@ -1,4 +1,4 @@ -FatFs Module Source Files R0.13c +FatFs Module Source Files R0.14 FILES diff --git a/thirdparty/fatfs/LICENSE.txt b/thirdparty/fatfs/LICENSE.txt new file mode 100644 index 0000000..bdce118 --- /dev/null +++ b/thirdparty/fatfs/LICENSE.txt @@ -0,0 +1,24 @@ +FatFs License + +FatFs has being developped as a personal project of the author, ChaN. It is free from the code anyone else wrote at current release. Following code block shows a copy of the FatFs license document that heading the source files. + +/*----------------------------------------------------------------------------/ +/ FatFs - Generic FAT Filesystem Module Rx.xx / +/-----------------------------------------------------------------------------/ +/ +/ Copyright (C) 20xx, ChaN, all right reserved. +/ +/ FatFs module is an open source software. Redistribution and use of FatFs in +/ source and binary forms, with or without modification, are permitted provided +/ that the following condition is met: +/ +/ 1. Redistributions of source code must retain the above copyright notice, +/ this condition and the following disclaimer. +/ +/ This software is provided by the copyright holder and contributors "AS IS" +/ and any warranties related to this software are DISCLAIMED. +/ The copyright owner or contributors be NOT LIABLE for any damages caused +/ by use of this software. +/----------------------------------------------------------------------------*/ + +Therefore FatFs license is one of the BSD-style licenses but there is a significant feature. FatFs is mainly intended for embedded systems. In order to extend the usability for commercial products, the redistributions of FatFs in binary form, such as embedded code, binary library and any forms without source code, does not need to include about FatFs in the documentations. This is equivalent to the 1-clause BSD license. Of course FatFs is compatible with the most of open source software licenses including GNU GPL. When you redistribute the FatFs source code with any changes or create a fork, the license can also be changed to GNU GPL, BSD-style license or any open source software license that not conflict with FatFs license. diff --git a/thirdparty/fatfs/diskio.c b/thirdparty/fatfs/diskio.c index 902903a..291cffb 100644 --- a/thirdparty/fatfs/diskio.c +++ b/thirdparty/fatfs/diskio.c @@ -1,5 +1,5 @@ /*-----------------------------------------------------------------------*/ -/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2016 */ +/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2019 */ /*-----------------------------------------------------------------------*/ /* If a working storage control module is available, it should be */ /* attached to the FatFs via a glue function rather than modifying it. */ @@ -60,7 +60,7 @@ DSTATUS disk_initialize ( DRESULT disk_read ( BYTE pdrv, /* Physical drive nmuber to identify the drive */ BYTE *buff, /* Data buffer to store read data */ - DWORD sector, /* Sector address in LBA */ + LBA_t sector, /* Start sector in LBA */ UINT count /* Number of sectors to read */ ) { @@ -84,7 +84,7 @@ DRESULT disk_read ( DRESULT disk_write ( BYTE pdrv, /* Physical drive nmuber to identify the drive */ const BYTE *buff, /* Data to be written */ - DWORD sector, /* Sector address in LBA */ + LBA_t sector, /* Start sector in LBA */ UINT count /* Number of sectors to write */ ) { diff --git a/thirdparty/fatfs/diskio.h b/thirdparty/fatfs/diskio.h index 8496625..c22afaa 100644 --- a/thirdparty/fatfs/diskio.h +++ b/thirdparty/fatfs/diskio.h @@ -1,5 +1,5 @@ /*-----------------------------------------------------------------------/ -/ Low level disk interface modlue include file (C)ChaN, 2014 / +/ Low level disk interface modlue include file (C)ChaN, 2019 / /-----------------------------------------------------------------------*/ #ifndef _DISKIO_DEFINED @@ -9,7 +9,6 @@ extern "C" { #endif - /* Status of Disk Functions */ typedef BYTE DSTATUS; @@ -29,8 +28,8 @@ typedef enum { DSTATUS disk_initialize (BYTE pdrv); DSTATUS disk_status (BYTE pdrv); -DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count); -DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count); +DRESULT disk_read (BYTE pdrv, BYTE* buff, LBA_t sector, UINT count); +DRESULT disk_write (BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count); DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff); diff --git a/thirdparty/fatfs/ff.c b/thirdparty/fatfs/ff.c index 4a1a2bf..e2a57a6 100644 --- a/thirdparty/fatfs/ff.c +++ b/thirdparty/fatfs/ff.c @@ -1,8 +1,8 @@ /*----------------------------------------------------------------------------/ -/ FatFs - Generic FAT Filesystem Module R0.13c / +/ FatFs - Generic FAT Filesystem Module R0.14 / /-----------------------------------------------------------------------------/ / -/ Copyright (C) 2018, ChaN, all right reserved. +/ Copyright (C) 2019, ChaN, all right reserved. / / FatFs module is an open source software. Redistribution and use of FatFs in / source and binary forms, with or without modification, are permitted provided @@ -29,7 +29,7 @@ ---------------------------------------------------------------------------*/ -#if FF_DEFINED != 86604 /* Revision ID */ +#if FF_DEFINED != 86606 /* Revision ID */ #error Wrong include file (ff.h). #endif @@ -204,6 +204,27 @@ #define PTE_StLba 8 /* MBR PTE: Start in LBA */ #define PTE_SizLba 12 /* MBR PTE: Size in LBA */ +#define GPTH_Sign 0 /* GPT: Header signature (8-byte) */ +#define GPTH_Rev 8 /* GPT: Revision (DWORD) */ +#define GPTH_Size 12 /* GPT: Header size (DWORD) */ +#define GPTH_Bcc 16 /* GPT: Header BCC (DWORD) */ +#define GPTH_CurLba 24 /* GPT: Main header LBA (QWORD) */ +#define GPTH_BakLba 32 /* GPT: Backup header LBA (QWORD) */ +#define GPTH_FstLba 40 /* GPT: First LBA for partitions (QWORD) */ +#define GPTH_LstLba 48 /* GPT: Last LBA for partitions (QWORD) */ +#define GPTH_DskGuid 56 /* GPT: Disk GUID (16-byte) */ +#define GPTH_PtOfs 72 /* GPT: Partation table LBA (QWORD) */ +#define GPTH_PtNum 80 /* GPT: Number of table entries (DWORD) */ +#define GPTH_PteSize 84 /* GPT: Size of table entry (DWORD) */ +#define GPTH_PtBcc 88 /* GPT: Partation table BCC (DWORD) */ +#define SZ_GPTE 128 /* GPT: Size of partition table entry */ +#define GPTE_PtGuid 0 /* GPT PTE: Partition type GUID (16-byte) */ +#define GPTE_UpGuid 16 /* GPT PTE: Partition unique GUID (16-byte) */ +#define GPTE_FstLba 32 /* GPT PTE: First LBA (QWORD) */ +#define GPTE_LstLba 40 /* GPT PTE: Last LBA inclusive (QWORD) */ +#define GPTE_Flags 48 /* GPT PTE: Flags (QWORD) */ +#define GPTE_Name 56 /* GPT PTE: Name */ + /* Post process on fatal error in the file operations */ #define ABORT(fs, res) { fp->err = (BYTE)(res); LEAVE_FF(fs, res); } @@ -220,12 +241,12 @@ #endif -/* Definitions of volume - physical location conversion */ +/* Definitions of logical drive - physical location conversion */ #if FF_MULTI_PARTITION #define LD2PD(vol) VolToPart[vol].pd /* Get physical drive number */ #define LD2PT(vol) VolToPart[vol].pt /* Get partition index */ #else -#define LD2PD(vol) (BYTE)(vol) /* Each logical drive is bound to the same physical drive number */ +#define LD2PD(vol) (BYTE)(vol) /* Each logical drive is associated with the same physical drive number */ #define LD2PT(vol) 0 /* Find first valid partition or in SFD */ #endif @@ -406,6 +427,7 @@ typedef struct { /* DBCS code range |----- 1st byte -----| |----------- 2nd byte -----------| */ +/* <------> <------> <------> <------> <------> */ #define TBL_DC932 {0x81, 0x9F, 0xE0, 0xFC, 0x40, 0x7E, 0x80, 0xFC, 0x00, 0x00} #define TBL_DC936 {0x81, 0xFE, 0x00, 0x00, 0x40, 0x7E, 0x80, 0xFE, 0x00, 0x00} #define TBL_DC949 {0x81, 0xFE, 0x00, 0x00, 0x41, 0x5A, 0x61, 0x7A, 0x81, 0xFE} @@ -452,6 +474,14 @@ static const char* const VolumeStr[FF_VOLUMES] = {FF_VOLUME_STRS}; /* Pre-define #endif #endif +#if FF_LBA64 +#if FF_MIN_GPT > 0x100000000 +#error Wrong FF_MIN_GPT setting +#endif +static const BYTE GUID_MS_Basic[16] = {0xA2,0xA0,0xD0,0xEB,0xE5,0xB9,0x33,0x44,0x87,0xC0,0x68,0xB6,0xB7,0x26,0x99,0xC7}; +#endif + + /*--------------------------------*/ /* LFN/Directory working buffer */ @@ -697,7 +727,7 @@ static int chk_chr (const char* str, int chr) /* NZ:contained, ZR:not contained } -/* Test if the character is DBC 1st byte */ +/* Test if the byte is DBC 1st byte */ static int dbc_1st (BYTE c) { #if FF_CODE_PAGE == 0 /* Variable code page */ @@ -717,7 +747,7 @@ static int dbc_1st (BYTE c) } -/* Test if the character is DBC 2nd byte */ +/* Test if the byte is DBC 2nd byte */ static int dbc_2nd (BYTE c) { #if FF_CODE_PAGE == 0 /* Variable code page */ @@ -741,8 +771,8 @@ static int dbc_2nd (BYTE c) #if FF_USE_LFN -/* Get a character from TCHAR string in defined API encodeing */ -static DWORD tchar2uni ( /* Returns character in UTF-16 encoding (>=0x10000 on double encoding unit, 0xFFFFFFFF on decode error) */ +/* Get a Unicode code point from the TCHAR string in defined API encodeing */ +static DWORD tchar2uni ( /* Returns a character in UTF-16 encoding (>=0x10000 on surrogate pair, 0xFFFFFFFF on decode error) */ const TCHAR** str /* Pointer to pointer to TCHAR string in configured encoding */ ) { @@ -763,7 +793,7 @@ static DWORD tchar2uni ( /* Returns character in UTF-16 encoding (>=0x10000 on d BYTE b; int nf; - uc = (BYTE)*p++; /* Get a unit */ + uc = (BYTE)*p++; /* Get an encoding unit */ if (uc & 0x80) { /* Multiple byte code? */ if ((uc & 0xE0) == 0xC0) { /* 2-byte sequence? */ uc &= 0x1F; nf = 1; @@ -789,7 +819,7 @@ static DWORD tchar2uni ( /* Returns character in UTF-16 encoding (>=0x10000 on d #elif FF_LFN_UNICODE == 3 /* UTF-32 input */ uc = (TCHAR)*p++; /* Get a unit */ - if (uc >= 0x110000) return 0xFFFFFFFF; /* Wrong code? */ + if (uc >= 0x110000 || IsSurrogate(uc)) return 0xFFFFFFFF; /* Wrong code? */ if (uc >= 0x010000) uc = 0xD800DC00 | ((uc - 0x10000) << 6 & 0x3FF0000) | (uc & 0x3FF); /* Make a surrogate pair if needed */ #else /* ANSI/OEM input */ @@ -816,7 +846,7 @@ static DWORD tchar2uni ( /* Returns character in UTF-16 encoding (>=0x10000 on d /* Output a TCHAR string in defined API encoding */ static BYTE put_utf ( /* Returns number of encoding units written (0:buffer overflow or wrong encoding) */ - DWORD chr, /* UTF-16 encoded character (Double encoding unit char if >=0x10000) */ + DWORD chr, /* UTF-16 encoded character (Surrogate pair if >=0x10000) */ TCHAR* buf, /* Output buffer */ UINT szb /* Size of the buffer */ ) @@ -976,9 +1006,9 @@ static UINT inc_lock ( /* Increment object open counter and returns its index (0 for (i = 0; i < FF_FS_LOCK; i++) { /* Find the object */ - if (Files[i].fs == dp->obj.fs && - Files[i].clu == dp->obj.sclust && - Files[i].ofs == dp->dptr) break; + if (Files[i].fs == dp->obj.fs + && Files[i].clu == dp->obj.sclust + && Files[i].ofs == dp->dptr) break; } if (i == FF_FS_LOCK) { /* Not opened. Register it as new. */ @@ -1046,8 +1076,8 @@ static FRESULT sync_window ( /* Returns FR_OK or FR_DISK_ERR */ FRESULT res = FR_OK; - if (fs->wflag) { /* Is the disk access window dirty */ - if (disk_write(fs->pdrv, fs->win, fs->winsect, 1) == RES_OK) { /* Write back the window */ + if (fs->wflag) { /* Is the disk access window dirty? */ + if (disk_write(fs->pdrv, fs->win, fs->winsect, 1) == RES_OK) { /* Write it back into the volume */ fs->wflag = 0; /* Clear window dirty flag */ if (fs->winsect - fs->fatbase < fs->fsize) { /* Is it in the 1st FAT? */ if (fs->n_fats == 2) disk_write(fs->pdrv, fs->win, fs->winsect + fs->fsize, 1); /* Reflect it to 2nd FAT if needed */ @@ -1062,23 +1092,23 @@ static FRESULT sync_window ( /* Returns FR_OK or FR_DISK_ERR */ static FRESULT move_window ( /* Returns FR_OK or FR_DISK_ERR */ - FATFS* fs, /* Filesystem object */ - DWORD sector /* Sector number to make appearance in the fs->win[] */ + FATFS* fs, /* Filesystem object */ + LBA_t sect /* Sector LBA to make appearance in the fs->win[] */ ) { FRESULT res = FR_OK; - if (sector != fs->winsect) { /* Window offset changed? */ + if (sect != fs->winsect) { /* Window offset changed? */ #if !FF_FS_READONLY - res = sync_window(fs); /* Write-back changes */ + res = sync_window(fs); /* Flush the window */ #endif if (res == FR_OK) { /* Fill sector window with new data */ - if (disk_read(fs->pdrv, fs->win, sector, 1) != RES_OK) { - sector = 0xFFFFFFFF; /* Invalidate window if read data is not valid */ + if (disk_read(fs->pdrv, fs->win, sect, 1) != RES_OK) { + sect = (LBA_t)0 - 1; /* Invalidate window if read data is not valid */ res = FR_DISK_ERR; } - fs->winsect = sector; + fs->winsect = sect; } } return res; @@ -1129,14 +1159,14 @@ static FRESULT sync_fs ( /* Returns FR_OK or FR_DISK_ERR */ /* Get physical sector number from cluster number */ /*-----------------------------------------------------------------------*/ -static DWORD clst2sect ( /* !=0:Sector number, 0:Failed (invalid cluster#) */ +static LBA_t clst2sect ( /* !=0:Sector number, 0:Failed (invalid cluster#) */ FATFS* fs, /* Filesystem object */ DWORD clst /* Cluster# to be converted */ ) { clst -= 2; /* Cluster number is origin from 2 */ if (clst >= fs->n_fatent - 2) return 0; /* Is it invalid cluster number? */ - return fs->database + fs->csize * clst; /* Start sector number of the cluster */ + return fs->database + (LBA_t)fs->csize * clst; /* Start sector number of the cluster */ } @@ -1185,7 +1215,7 @@ static DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x7FFFFFF case FS_EXFAT : if ((obj->objsize != 0 && obj->sclust != 0) || obj->stat == 0) { /* Object except root dir must have valid data length */ DWORD cofs = clst - obj->sclust; /* Offset from start cluster */ - DWORD clen = (DWORD)((obj->objsize - 1) / SS(fs)) / fs->csize; /* Number of clusters - 1 */ + DWORD clen = (DWORD)((LBA_t)((obj->objsize - 1) / SS(fs)) / fs->csize); /* Number of clusters - 1 */ if (obj->stat == 2 && cofs <= clen) { /* Is it a contiguous chain? */ val = (cofs == clen) ? 0x7FFFFFFF : clst + 1; /* No data on the FAT, generate the value */ @@ -1241,12 +1271,12 @@ static FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */ res = move_window(fs, fs->fatbase + (bc / SS(fs))); if (res != FR_OK) break; p = fs->win + bc++ % SS(fs); - *p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val; /* Put 1st byte */ + *p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val; /* Update 1st byte */ fs->wflag = 1; res = move_window(fs, fs->fatbase + (bc / SS(fs))); if (res != FR_OK) break; p = fs->win + bc % SS(fs); - *p = (clst & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F)); /* Put 2nd byte */ + *p = (clst & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F)); /* Update 2nd byte */ fs->wflag = 1; break; @@ -1337,7 +1367,7 @@ static FRESULT change_bitmap ( { BYTE bm; UINT i; - DWORD sect; + LBA_t sect; clst -= 2; /* The first bit corresponds to cluster #2 */ @@ -1426,7 +1456,7 @@ static FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ DWORD scl = clst, ecl = clst; #endif #if FF_USE_TRIM - DWORD rt[2]; + LBA_t rt[2]; #endif if (clst < 2 || clst >= fs->n_fatent) return FR_INT_ERR; /* Check if in valid range */ @@ -1462,9 +1492,9 @@ static FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ } #endif #if FF_USE_TRIM - rt[0] = clst2sect(fs, scl); /* Start of data area freed */ - rt[1] = clst2sect(fs, ecl) + fs->csize - 1; /* End of data area freed */ - disk_ioctl(fs->pdrv, CTRL_TRIM, rt); /* Inform device the data in the block is no longer needed */ + rt[0] = clst2sect(fs, scl); /* Start of data area to be freed */ + rt[1] = clst2sect(fs, ecl) + fs->csize - 1; /* End of data area to be freed */ + disk_ioctl(fs->pdrv, CTRL_TRIM, rt); /* Inform storage device that the data in the block may be erased */ #endif scl = ecl = nxt; } @@ -1646,7 +1676,7 @@ static FRESULT dir_clear ( /* Returns FR_OK or FR_DISK_ERR */ DWORD clst /* Directory table to clear */ ) { - DWORD sect; + LBA_t sect; UINT n, szb; BYTE *ibuf; @@ -1695,7 +1725,7 @@ static FRESULT dir_sdi ( /* FR_OK(0):succeeded, !=0:error */ dp->dptr = ofs; /* Set current offset */ clst = dp->obj.sclust; /* Table start cluster (0:root) */ if (clst == 0 && fs->fs_type >= FS_FAT32) { /* Replace cluster# 0 with root cluster# */ - clst = fs->dirbase; + clst = (DWORD)fs->dirbase; if (FF_FS_EXFAT) dp->obj.stat = 0; /* exFAT: Root dir has an FAT chain */ } @@ -1963,7 +1993,7 @@ static void put_lfn ( do { if (wc != 0xFFFF) wc = lfn[i++]; /* Get an effective character */ st_word(dir + LfnOfs[s], wc); /* Put it */ - if (wc == 0) wc = 0xFFFF; /* Padding characters for left locations */ + if (wc == 0) wc = 0xFFFF; /* Padding characters for following items */ } while (++s < 13); if (wc == 0xFFFF || !lfn[i]) ord |= LLEF; /* Last LFN part is the start of LFN sequence */ dir[LDIR_Ord] = ord; /* Set the LFN order */ @@ -1989,22 +2019,22 @@ static void gen_numname ( BYTE ns[8], c; UINT i, j; WCHAR wc; - DWORD sr; + DWORD sreg; mem_cpy(dst, src, 11); if (seq > 5) { /* In case of many collisions, generate a hash number instead of sequential number */ - sr = seq; + sreg = seq; while (*lfn) { /* Create a CRC as hash value */ wc = *lfn++; for (i = 0; i < 16; i++) { - sr = (sr << 1) + (wc & 1); + sreg = (sreg << 1) + (wc & 1); wc >>= 1; - if (sr & 0x10000) sr ^= 0x11021; + if (sreg & 0x10000) sreg ^= 0x11021; } } - seq = (UINT)sr; + seq = (UINT)sreg; } /* itoa (hexdecimal) */ @@ -2523,9 +2553,9 @@ static FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too res = load_obj_xdir(&dj, &dp->obj); /* Load the object status */ if (res != FR_OK) return res; dp->obj.objsize += (DWORD)fs->csize * SS(fs); /* Increase the directory size by cluster size */ - st_qword(fs->dirbuf + XDIR_FileSize, dp->obj.objsize); /* Update the allocation status */ + st_qword(fs->dirbuf + XDIR_FileSize, dp->obj.objsize); st_qword(fs->dirbuf + XDIR_ValidFileSize, dp->obj.objsize); - fs->dirbuf[XDIR_GenFlags] = dp->obj.stat | 1; + fs->dirbuf[XDIR_GenFlags] = dp->obj.stat | 1; /* Update the allocation status */ res = store_xdir(&dj); /* Store the object status */ if (res != FR_OK) return res; } @@ -2851,9 +2881,13 @@ static FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not cr if (di >= FF_MAX_LFN) return FR_INVALID_NAME; /* Reject too long name */ lfn[di++] = wc; /* Store the Unicode character */ } - while (*p == '/' || *p == '\\') p++; /* Skip duplicated separators if exist */ - *path = p; /* Return pointer to the next segment */ - cf = (wc < ' ') ? NS_LAST : 0; /* Set last segment flag if end of the path */ + if (wc < ' ') { /* End of path? */ + cf = NS_LAST; /* Set last segment flag */ + } else { + cf = 0; /* Next segment follows */ + while (*p == '/' || *p == '\\') p++; /* Skip duplicated separators if exist */ + } + *path = p; /* Return pointer to the next segment */ #if FF_FS_RPATH != 0 if ((di == 1 && lfn[di - 1] == '.') || @@ -3180,23 +3214,94 @@ static int get_ldnumber ( /* Returns logical drive number (-1:invalid drive numb +/*-----------------------------------------------------------------------*/ +/* GPT support functions */ +/*-----------------------------------------------------------------------*/ + +#if FF_LBA64 + +/* Calculate CRC32 in byte-by-byte */ + +static DWORD crc32 ( /* Returns next CRC value */ + DWORD crc, /* Current CRC value */ + BYTE d /* A byte to be processed */ +) +{ + BYTE b; + + + for (b = 1; b; b <<= 1) { + crc ^= (d & b) ? 1 : 0; + crc = (crc & 1) ? crc >> 1 ^ 0xEDB88320 : crc >> 1; + } + return crc; +} + + +/* Check validity of GPT header */ + +static int test_gpt_header ( /* 0:Invalid, 1:Valid */ + const BYTE* gpth /* Pointer to the GPT header */ +) +{ + UINT i; + DWORD bcc; + + + if (mem_cmp(gpth + GPTH_Sign, "EFI PART" "\0\0\1\0" "\x5C\0\0", 16)) return 0; /* Check sign, version (1.0) and length (92) */ + for (i = 0, bcc = 0xFFFFFFFF; i < 92; i++) { /* Check header BCC */ + bcc = crc32(bcc, i - GPTH_Bcc < 4 ? 0 : gpth[i]); + } + if (~bcc != ld_dword(gpth + GPTH_Bcc)) return 0; + if (ld_dword(gpth + GPTH_PteSize) != SZ_GPTE) return 0; /* Table entry size (must be SZ_GPTE bytes) */ + if (ld_dword(gpth + GPTH_PtNum) > 128) return 0; /* Table size (must be 128 entries or less) */ + + return 1; +} + +#if !FF_FS_READONLY && FF_USE_MKFS + +/* Generate random value */ +static DWORD make_rand ( + DWORD seed, /* Seed value */ + BYTE* buff, /* Output buffer */ + UINT n /* Data length */ +) +{ + UINT r; + + + if (seed == 0) seed = 1; + do { + for (r = 0; r < 8; r++) seed = seed & 1 ? seed >> 1 ^ 0xA3000000 : seed >> 1; /* Shift 8 bits the 32-bit LFSR */ + *buff++ = (BYTE)seed; + } while (--n); + return seed; +} + +#endif +#endif + + + /*-----------------------------------------------------------------------*/ /* Load a sector and check if it is an FAT VBR */ /*-----------------------------------------------------------------------*/ -static BYTE check_fs ( /* 0:FAT, 1:exFAT, 2:Valid BS but not FAT, 3:Not a BS, 4:Disk error */ +/* Check what the sector is */ + +static UINT check_fs ( /* 0:FAT VBR, 1:exFAT VBR, 2:Valid BS but not FAT, 3:Invalid BS, 4:Disk error */ FATFS* fs, /* Filesystem object */ - DWORD sect /* Sector# (lba) to load and check if it is an FAT-VBR or not */ + LBA_t sect /* Sector to load and check if it is an FAT-VBR or not */ ) { - fs->wflag = 0; fs->winsect = 0xFFFFFFFF; /* Invaidate window */ - if (move_window(fs, sect) != FR_OK) return 4; /* Load boot record */ + fs->wflag = 0; fs->winsect = (LBA_t)0 - 1; /* Invaidate window */ + if (move_window(fs, sect) != FR_OK) return 4; /* Load the boot sector */ - if (ld_word(fs->win + BS_55AA) != 0xAA55) return 3; /* Check boot record signature (always here regardless of the sector size) */ + if (ld_word(fs->win + BS_55AA) != 0xAA55) return 3; /* Check boot signature (always here regardless of the sector size) */ + + if (FF_FS_EXFAT && !mem_cmp(fs->win + BS_JmpBoot, "\xEB\x76\x90" "EXFAT ", 11)) return 1; /* Check if exFAT VBR */ -#if FF_FS_EXFAT - if (!mem_cmp(fs->win + BS_JmpBoot, "\xEB\x76\x90" "EXFAT ", 11)) return 1; /* Check if exFAT VBR */ -#endif if (fs->win[BS_JmpBoot] == 0xE9 || fs->win[BS_JmpBoot] == 0xEB || fs->win[BS_JmpBoot] == 0xE8) { /* Valid JumpBoot code? */ if (!mem_cmp(fs->win + BS_FilSysType, "FAT", 3)) return 0; /* Is it an FAT VBR? */ if (!mem_cmp(fs->win + BS_FilSysType32, "FAT32", 5)) return 0; /* Is it an FAT32 VBR? */ @@ -3205,25 +3310,76 @@ static BYTE check_fs ( /* 0:FAT, 1:exFAT, 2:Valid BS but not FAT, 3:Not a BS, 4: } +/* Find an FAT volume */ +/* (It supports only generic partitioning rules, MBR, GPT and SFD) */ + +static UINT find_volume ( /* Returns BS status found in the hosting drive */ + FATFS* fs, /* Filesystem object */ + UINT part /* Partition to fined = 0:auto, 1..:forced */ +) +{ + UINT fmt, i; + DWORD mbr_pt[4]; + + + fmt = check_fs(fs, 0); /* Load sector 0 and check if it is an FAT VBR as SFD */ + if (fmt != 2 && (fmt >= 3 || part == 0)) return fmt; /* Returns if it is a FAT VBR as auto scan, not a BS or disk error */ + + /* Sector 0 is not an FAT VBR or forced partition number wants a partition */ + +#if FF_LBA64 + if (fs->win[MBR_Table + PTE_System] == 0xEE) { /* GPT protective MBR? */ + DWORD n_ent, v_ent, ofs; + QWORD pt_lba; + + if (move_window(fs, 1) != FR_OK) return 4; /* Load GPT header sector (next to MBR) */ + if (!test_gpt_header(fs->win)) return 3; /* Check if GPT header is valid */ + n_ent = ld_dword(fs->win + GPTH_PtNum); /* Number of entries */ + pt_lba = ld_qword(fs->win + GPTH_PtOfs); /* Table location */ + for (v_ent = i = 0; i < n_ent; i++) { /* Find FAT partition */ + if (move_window(fs, pt_lba + i * SZ_GPTE / SS(fs)) != FR_OK) return 4; /* PT sector */ + ofs = i * SZ_GPTE % SS(fs); /* Offset in the sector */ + if (!mem_cmp(fs->win + ofs + GPTE_PtGuid, GUID_MS_Basic, 16)) { /* MS basic data partition? */ + v_ent++; + fmt = check_fs(fs, ld_qword(fs->win + ofs + GPTE_FstLba)); /* Load VBR and check status */ + if (part == 0 && fmt <= 1) return fmt; /* Auto search (valid FAT volume found first) */ + if (part != 0 && v_ent == part) return fmt; /* Forced partition order (regardless of it is valid or not) */ + } + } + return 3; /* Not found */ + } +#endif + if (FF_MULTI_PARTITION && part > 4) return 3; /* MBR has 4 partitions max */ + for (i = 0; i < 4; i++) { /* Load partition offset in the MBR */ + mbr_pt[i] = ld_dword(fs->win + MBR_Table + i * SZ_PTE + PTE_StLba); + } + i = part ? part - 1 : 0; /* Table index to find first */ + do { /* Find an FAT volume */ + fmt = mbr_pt[i] ? check_fs(fs, mbr_pt[i]) : 3; /* Check if the partition is FAT */ + } while (part == 0 && fmt >= 2 && ++i < 4); + return fmt; +} + + /*-----------------------------------------------------------------------*/ /* Determine logical drive number and mount the volume if needed */ /*-----------------------------------------------------------------------*/ -static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */ +static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ const TCHAR** path, /* Pointer to pointer to the path name (drive number) */ FATFS** rfs, /* Pointer to pointer to the found filesystem object */ BYTE mode /* !=0: Check write protection for write access */ ) { - BYTE fmt, *pt; int vol; DSTATUS stat; - DWORD bsect, fasize, tsect, sysect, nclst, szbfat, br[4]; + LBA_t bsect; + DWORD tsect, sysect, fasize, nclst, szbfat; WORD nrsv; FATFS *fs; - UINT i; + UINT fmt; /* Get logical drive number */ @@ -3246,15 +3402,15 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */ if (!FF_FS_READONLY && mode && (stat & STA_PROTECT)) { /* Check write protection if needed */ return FR_WRITE_PROTECTED; } - return FR_OK; /* The filesystem object is valid */ + return FR_OK; /* The filesystem object is already valid */ } } /* The filesystem object is not valid. */ - /* Following code attempts to mount the volume. (analyze BPB and initialize the filesystem object) */ + /* Following code attempts to mount the volume. (find a FAT volume, analyze the BPB and initialize the filesystem object) */ fs->fs_type = 0; /* Clear the filesystem object */ - fs->pdrv = LD2PD(vol); /* Bind the logical drive and a physical drive */ + fs->pdrv = LD2PD(vol); /* Volume hosting physical drive */ stat = disk_initialize(fs->pdrv); /* Initialize the physical drive */ if (stat & STA_NOINIT) { /* Check if the initialization succeeded */ return FR_NOT_READY; /* Failed to initialize due to no medium or hard error */ @@ -3267,30 +3423,18 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */ if (SS(fs) > FF_MAX_SS || SS(fs) < FF_MIN_SS || (SS(fs) & (SS(fs) - 1))) return FR_DISK_ERR; #endif - /* Find an FAT partition on the drive. Supports only generic partitioning rules, FDISK (MBR) and SFD (w/o partition). */ - bsect = 0; - fmt = check_fs(fs, bsect); /* Load sector 0 and check if it is an FAT-VBR as SFD */ - if (fmt == 2 || (fmt < 2 && LD2PT(vol) != 0)) { /* Not an FAT-VBR or forced partition number */ - for (i = 0; i < 4; i++) { /* Get partition offset */ - pt = fs->win + (MBR_Table + i * SZ_PTE); - br[i] = pt[PTE_System] ? ld_dword(pt + PTE_StLba) : 0; - } - i = LD2PT(vol); /* Partition number: 0:auto, 1-4:forced */ - if (i != 0) i--; - do { /* Find an FAT volume */ - bsect = br[i]; - fmt = bsect ? check_fs(fs, bsect) : 3; /* Check the partition */ - } while (LD2PT(vol) == 0 && fmt >= 2 && ++i < 4); - } + /* Find an FAT volume on the drive */ + fmt = find_volume(fs, LD2PT(vol)); if (fmt == 4) return FR_DISK_ERR; /* An error occured in the disk I/O layer */ if (fmt >= 2) return FR_NO_FILESYSTEM; /* No FAT volume is found */ + bsect = fs->winsect; /* Volume location */ /* An FAT volume is found (bsect). Following code initializes the filesystem object */ #if FF_FS_EXFAT if (fmt == 1) { QWORD maxlba; - DWORD so, cv, bcl; + DWORD so, cv, bcl, i; for (i = BPB_ZeroedEx; i < BPB_ZeroedEx + 53 && fs->win[i] == 0; i++) ; /* Check zero filler */ if (i < BPB_ZeroedEx + 53) return FR_NO_FILESYSTEM; @@ -3302,7 +3446,7 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */ } maxlba = ld_qword(fs->win + BPB_TotSecEx) + bsect; /* Last LBA + 1 of the volume */ - if (maxlba >= 0x100000000) return FR_NO_FILESYSTEM; /* (It cannot be handled in 32-bit LBA) */ + if (!FF_LBA64 && maxlba >= 0x100000000) return FR_NO_FILESYSTEM; /* (It cannot be handled in 32-bit LBA) */ fs->fsize = ld_dword(fs->win + BPB_FatSzEx); /* Number of sectors per FAT */ @@ -3328,7 +3472,7 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */ for (;;) { /* Find the bitmap entry in the root directory (in only first cluster) */ if (i == 0) { if (so >= fs->csize) return FR_NO_FILESYSTEM; /* Not found? */ - if (move_window(fs, clst2sect(fs, fs->dirbase) + so) != FR_OK) return FR_DISK_ERR; + if (move_window(fs, clst2sect(fs, (DWORD)fs->dirbase) + so) != FR_OK) return FR_DISK_ERR; so++; } if (fs->win[i] == ET_BITMAP) break; /* Is it a bitmap entry? */ @@ -3428,7 +3572,7 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */ #endif /* !FF_FS_READONLY */ } - fs->fs_type = fmt; /* FAT sub-type */ + fs->fs_type = (BYTE)fmt;/* FAT sub-type */ fs->id = ++Fsid; /* Volume mount ID */ #if FF_USE_LFN == 1 fs->lfnbuf = LfnBuf; /* Static LFN working buffer */ @@ -3533,7 +3677,7 @@ FRESULT f_mount ( if (opt == 0) return FR_OK; /* Do not mount now, it will be mounted later */ - res = find_volume(&path, &fs, 0); /* Force mounted the volume */ + res = mount_volume(&path, &fs, 0); /* Force mounted the volume */ LEAVE_FF(fs, res); } @@ -3554,7 +3698,8 @@ FRESULT f_open ( DIR dj; FATFS *fs; #if !FF_FS_READONLY - DWORD dw, cl, bcs, clst, sc; + DWORD cl, bcs, clst; + LBA_t sc; FSIZE_t ofs; #endif DEF_NAMBUF @@ -3564,7 +3709,7 @@ FRESULT f_open ( /* Get logical drive number */ mode &= FF_FS_READONLY ? FA_READ : FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_CREATE_NEW | FA_OPEN_ALWAYS | FA_OPEN_APPEND; - res = find_volume(&path, &fs, mode); + res = mount_volume(&path, &fs, mode); if (res == FR_OK) { dj.obj.fs = fs; INIT_NAMBUF(fs); @@ -3627,10 +3772,10 @@ FRESULT f_open ( st_dword(dj.dir + DIR_FileSize, 0); fs->wflag = 1; if (cl != 0) { /* Remove the cluster chain if exist */ - dw = fs->winsect; + sc = fs->winsect; res = remove_chain(&dj.obj, cl, 0); if (res == FR_OK) { - res = move_window(fs, dw); + res = move_window(fs, sc); fs->last_clst = cl - 1; /* Reuse the cluster hole */ } } @@ -3706,7 +3851,8 @@ FRESULT f_open ( } fp->clust = clst; if (res == FR_OK && ofs % SS(fs)) { /* Fill sector buffer if not on the sector boundary */ - if ((sc = clst2sect(fs, clst)) == 0) { + sc = clst2sect(fs, clst); + if (sc == 0) { res = FR_INT_ERR; } else { fp->sect = sc + (DWORD)(ofs / SS(fs)); @@ -3743,7 +3889,8 @@ FRESULT f_read ( { FRESULT res; FATFS *fs; - DWORD clst, sect; + DWORD clst; + LBA_t sect; FSIZE_t remain; UINT rcnt, cc, csect; BYTE *rbuff = (BYTE*)buff; @@ -3813,7 +3960,7 @@ FRESULT f_read ( #endif fp->sect = sect; } - rcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes left in the sector */ + rcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes remains in the sector */ if (rcnt > btr) rcnt = btr; /* Clip it by btr if needed */ #if FF_FS_TINY if (move_window(fs, fp->sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window */ @@ -3843,7 +3990,8 @@ FRESULT f_write ( { FRESULT res; FATFS *fs; - DWORD clst, sect; + DWORD clst; + LBA_t sect; UINT wcnt, cc, csect; const BYTE *wbuff = (const BYTE*)buff; @@ -3931,7 +4079,7 @@ FRESULT f_write ( #endif fp->sect = sect; } - wcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes left in the sector */ + wcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes remains in the sector */ if (wcnt > btw) wcnt = btw; /* Clip it by btw if needed */ #if FF_FS_TINY if (move_window(fs, fp->sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window */ @@ -3991,9 +4139,9 @@ FRESULT f_sync ( if (res == FR_OK) { fs->dirbuf[XDIR_Attr] |= AM_ARC; /* Set archive attribute to indicate that the file has been changed */ fs->dirbuf[XDIR_GenFlags] = fp->obj.stat | 1; /* Update file allocation information */ - st_dword(fs->dirbuf + XDIR_FstClus, fp->obj.sclust); - st_qword(fs->dirbuf + XDIR_FileSize, fp->obj.objsize); - st_qword(fs->dirbuf + XDIR_ValidFileSize, fp->obj.objsize); + st_dword(fs->dirbuf + XDIR_FstClus, fp->obj.sclust); /* Update start cluster */ + st_qword(fs->dirbuf + XDIR_FileSize, fp->obj.objsize); /* Update file size */ + st_qword(fs->dirbuf + XDIR_ValidFileSize, fp->obj.objsize); /* (FatFs does not support Valid File Size feature) */ st_dword(fs->dirbuf + XDIR_ModTime, tm); /* Update modified time */ fs->dirbuf[XDIR_ModTime10] = 0; st_dword(fs->dirbuf + XDIR_AccTime, 0); @@ -4103,7 +4251,7 @@ FRESULT f_chdir ( /* Get logical drive */ - res = find_volume(&path, &fs, 0); + res = mount_volume(&path, &fs, 0); if (res == FR_OK) { dj.obj.fs = fs; INIT_NAMBUF(fs); @@ -4174,7 +4322,7 @@ FRESULT f_getcwd ( /* Get logical drive */ buff[0] = 0; /* Set null string to get current volume */ - res = find_volume((const TCHAR**)&buff, &fs, 0); /* Get current volume */ + res = mount_volume((const TCHAR**)&buff, &fs, 0); /* Get current volume */ if (res == FR_OK) { dj.obj.fs = fs; INIT_NAMBUF(fs); @@ -4258,10 +4406,12 @@ FRESULT f_lseek ( { FRESULT res; FATFS *fs; - DWORD clst, bcs, nsect; + DWORD clst, bcs; + LBA_t nsect; FSIZE_t ifptr; #if FF_USE_FASTSEEK - DWORD cl, pcl, ncl, tcl, dsc, tlen, ulen, *tbl; + DWORD cl, pcl, ncl, tcl, tlen, ulen, *tbl; + LBA_t dsc; #endif res = validate(&fp->obj, &fs); /* Check validity of the file object */ @@ -4425,7 +4575,7 @@ FRESULT f_opendir ( if (!dp) return FR_INVALID_OBJECT; /* Get logical drive */ - res = find_volume(&path, &fs, 0); + res = mount_volume(&path, &fs, 0); if (res == FR_OK) { dp->obj.fs = fs; INIT_NAMBUF(fs); @@ -4607,7 +4757,7 @@ FRESULT f_stat ( /* Get logical drive */ - res = find_volume(&path, &dj.obj.fs, 0); + res = mount_volume(&path, &dj.obj.fs, 0); if (res == FR_OK) { INIT_NAMBUF(dj.obj.fs); res = follow_path(&dj, path); /* Follow the file path */ @@ -4639,13 +4789,14 @@ FRESULT f_getfree ( { FRESULT res; FATFS *fs; - DWORD nfree, clst, sect, stat; + DWORD nfree, clst, stat; + LBA_t sect; UINT i; FFOBJID obj; /* Get logical drive */ - res = find_volume(&path, &fs, 0); + res = mount_volume(&path, &fs, 0); if (res == FR_OK) { *fatfs = fs; /* Return ptr to the fs object */ /* If free_clst is valid, return it without full FAT scan */ @@ -4785,7 +4936,7 @@ FRESULT f_unlink ( /* Get logical drive */ - res = find_volume(&path, &fs, FA_WRITE); + res = mount_volume(&path, &fs, FA_WRITE); if (res == FR_OK) { dj.obj.fs = fs; INIT_NAMBUF(fs); @@ -4876,7 +5027,7 @@ FRESULT f_mkdir ( DEF_NAMBUF - res = find_volume(&path, &fs, FA_WRITE); /* Get logical drive */ + res = mount_volume(&path, &fs, FA_WRITE); /* Get logical drive */ if (res == FR_OK) { dj.obj.fs = fs; INIT_NAMBUF(fs); @@ -4915,7 +5066,7 @@ FRESULT f_mkdir ( if (fs->fs_type == FS_EXFAT) { /* Initialize directory entry block */ st_dword(fs->dirbuf + XDIR_ModTime, tm); /* Created time */ st_dword(fs->dirbuf + XDIR_FstClus, dcl); /* Table start cluster */ - st_dword(fs->dirbuf + XDIR_FileSize, (DWORD)fs->csize * SS(fs)); /* File size needs to be valid */ + st_dword(fs->dirbuf + XDIR_FileSize, (DWORD)fs->csize * SS(fs)); /* Directory size needs to be valid */ st_dword(fs->dirbuf + XDIR_ValidFileSize, (DWORD)fs->csize * SS(fs)); fs->dirbuf[XDIR_GenFlags] = 3; /* Initialize the object flag */ fs->dirbuf[XDIR_Attr] = AM_DIR; /* Attribute */ @@ -4957,12 +5108,12 @@ FRESULT f_rename ( DIR djo, djn; FATFS *fs; BYTE buf[FF_FS_EXFAT ? SZDIRE * 2 : SZDIRE], *dir; - DWORD dw; + LBA_t sect; DEF_NAMBUF get_ldnumber(&path_new); /* Snip the drive number of new name off */ - res = find_volume(&path_old, &fs, FA_WRITE); /* Get logical drive of the old object */ + res = mount_volume(&path_old, &fs, FA_WRITE); /* Get logical drive of the old object */ if (res == FR_OK) { djo.obj.fs = fs; INIT_NAMBUF(fs); @@ -5016,12 +5167,12 @@ FRESULT f_rename ( if (!(dir[DIR_Attr] & AM_DIR)) dir[DIR_Attr] |= AM_ARC; /* Set archive attribute if it is a file */ fs->wflag = 1; if ((dir[DIR_Attr] & AM_DIR) && djo.obj.sclust != djn.obj.sclust) { /* Update .. entry in the sub-directory if needed */ - dw = clst2sect(fs, ld_clust(fs, dir)); - if (dw == 0) { + sect = clst2sect(fs, ld_clust(fs, dir)); + if (sect == 0) { res = FR_INT_ERR; } else { /* Start of critical section where an interruption can cause a cross-link */ - res = move_window(fs, dw); + res = move_window(fs, sect); dir = fs->win + SZDIRE * 1; /* Ptr to .. entry */ if (res == FR_OK && dir[1] == '.') { st_clust(fs, dir, djn.obj.sclust); @@ -5070,7 +5221,7 @@ FRESULT f_chmod ( DEF_NAMBUF - res = find_volume(&path, &fs, FA_WRITE); /* Get logical drive */ + res = mount_volume(&path, &fs, FA_WRITE); /* Get logical drive */ if (res == FR_OK) { dj.obj.fs = fs; INIT_NAMBUF(fs); @@ -5116,7 +5267,7 @@ FRESULT f_utime ( DEF_NAMBUF - res = find_volume(&path, &fs, FA_WRITE); /* Get logical drive */ + res = mount_volume(&path, &fs, FA_WRITE); /* Get logical drive */ if (res == FR_OK) { dj.obj.fs = fs; INIT_NAMBUF(fs); @@ -5165,7 +5316,7 @@ FRESULT f_getlabel ( WCHAR wc; /* Get logical drive */ - res = find_volume(&path, &fs, 0); + res = mount_volume(&path, &fs, 0); /* Get volume label */ if (res == FR_OK && label) { @@ -5263,7 +5414,7 @@ FRESULT f_setlabel ( #endif /* Get logical drive */ - res = find_volume(&label, &fs, FA_WRITE); + res = mount_volume(&label, &fs, FA_WRITE); if (res != FR_OK) LEAVE_FF(fs, res); #if FF_FS_EXFAT @@ -5466,7 +5617,8 @@ FRESULT f_forward ( { FRESULT res; FATFS *fs; - DWORD clst, sect; + DWORD clst; + LBA_t sect; FSIZE_t remain; UINT rcnt, csect; BYTE *dbuf; @@ -5511,7 +5663,7 @@ FRESULT f_forward ( dbuf = fp->buf; #endif fp->sect = sect; - rcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes left in the sector */ + rcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes remains in the sector */ if (rcnt > btf) rcnt = btf; /* Clip it by btr if needed */ rcnt = (*func)(dbuf + ((UINT)fp->fptr % SS(fs)), rcnt); /* Forward the file data */ if (rcnt == 0) ABORT(fs, FR_INT_ERR); @@ -5523,137 +5675,326 @@ FRESULT f_forward ( -#if FF_USE_MKFS && !FF_FS_READONLY +#if !FF_FS_READONLY && FF_USE_MKFS /*-----------------------------------------------------------------------*/ /* Create an FAT/exFAT volume */ /*-----------------------------------------------------------------------*/ -FRESULT f_mkfs ( - const TCHAR* path, /* Logical drive number */ - BYTE opt, /* Format option */ - DWORD au, /* Size of allocation unit (cluster) [byte] */ - void* work, /* Pointer to working buffer (null: use heap memory) */ - UINT len /* Size of working buffer [byte] */ +#define N_SEC_TRACK 63 /* Sectors per track for determination of drive CHS */ +#define GPT_ALIGN 0x100000 /* Alignment of partitions in GPT [byte] (>=128KB) */ +#define GPT_ITEMS 128 /* Number of GPT table size (>=128, sector aligned) */ + + +/* Create partitions on the physical drive */ + +static FRESULT create_partition ( + BYTE drv, /* Physical drive number */ + const LBA_t plst[], /* Partition list */ + UINT sys, /* System ID (for only MBR, temp setting) and bit8:GPT */ + BYTE* buf /* Working buffer for a sector */ +) +{ + UINT i, cy; + LBA_t sz_drv; + DWORD sz_drv32, s_lba32, n_lba32; + BYTE *pte, hd, n_hd, sc, n_sc; + + /* Get drive size */ + if (disk_ioctl(drv, GET_SECTOR_COUNT, &sz_drv) != RES_OK) return FR_DISK_ERR; + +#if FF_LBA64 + if (sz_drv >= FF_MIN_GPT) { /* Create partitions in GPT */ + WORD ss; + UINT sz_pt, pi, si, ofs; + DWORD bcc, rnd, align; + QWORD s_lba64, n_lba64, sz_pool, s_bpt; + static const BYTE gpt_mbr[16] = {0x00, 0x00, 0x02, 0x00, 0xEE, 0xFE, 0xFF, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF}; + +#if FF_MAX_SS != FF_MIN_SS + if (disk_ioctl(drv, GET_SECTOR_SIZE, &ss) != RES_OK) return FR_DISK_ERR; /* Get sector size */ + if (ss > FF_MAX_SS || ss < FF_MIN_SS || (ss & (ss - 1))) return FR_DISK_ERR; +#else + ss = FF_MAX_SS; +#endif + rnd = GET_FATTIME(); /* Random seed */ + align = GPT_ALIGN / ss; /* Partition alignment [sector] */ + sz_pt = GPT_ITEMS * SZ_GPTE / ss; /* Size of PT [sector] */ + s_bpt = sz_drv - sz_pt - 1; /* Backup PT start sector */ + s_lba64 = 2 + sz_pt; /* First allocatable sector */ + sz_pool = s_bpt - s_lba64; /* Size of allocatable area */ + bcc = 0xFFFFFFFF; n_lba64 = 1; + pi = si = 0; /* partition table index, size table index */ + do { + if (pi * SZ_GPTE % ss == 0) mem_set(buf, 0, ss); /* Clean the buffer if needed */ + if (n_lba64 != 0) { /* Is the size table not termintated? */ + s_lba64 = (s_lba64 + align - 1) & ((QWORD)0 - align); /* Align partition start */ + n_lba64 = plst[si++]; /* Get a partition size */ + if (n_lba64 <= 100) { /* Is the size in percentage? */ + n_lba64 = sz_pool * n_lba64 / 100; + n_lba64 = (n_lba64 + align - 1) & ((QWORD)0 - align); /* Align partition end (only if in percentage) */ + } + if (s_lba64 + n_lba64 > s_bpt) { /* Clip at end of the pool */ + n_lba64 = (s_lba64 < s_bpt) ? s_bpt - s_lba64 : 0; + } + } + if (n_lba64 != 0) { /* Add a partition? */ + ofs = pi * SZ_GPTE % ss; + mem_cpy(buf + ofs + GPTE_PtGuid, GUID_MS_Basic, 16); /* Partition GUID (Microsoft Basic Data) */ + rnd = make_rand(rnd, buf + ofs + GPTE_UpGuid, 16); /* Unique partition GUID */ + st_qword(buf + ofs + GPTE_FstLba, s_lba64); /* Partition start LBA */ + st_qword(buf + ofs + GPTE_LstLba, s_lba64 + n_lba64 - 1); /* Partition end LBA */ + s_lba64 += n_lba64; /* Next partition LBA */ + } + if ((pi + 1) * SZ_GPTE % ss == 0) { /* Write the buffer if it is filled up */ + for (i = 0; i < ss; bcc = crc32(bcc, buf[i++])) ; /* Calculate table check sum */ + if (disk_write(drv, buf, 2 + pi * SZ_GPTE / ss, 1) != RES_OK) return FR_DISK_ERR; /* Primary table */ + if (disk_write(drv, buf, s_bpt + pi * SZ_GPTE / ss, 1) != RES_OK) return FR_DISK_ERR; /* Secondary table */ + } + } while (++pi < GPT_ITEMS); + + /* Create primary GPT header */ + mem_set(buf, 0, ss); + mem_cpy(buf + GPTH_Sign, "EFI PART" "\0\0\1\0" "\x5C\0\0", 16); /* Signature, version (1.0) and size (92) */ + st_dword(buf + GPTH_PtBcc, ~bcc); /* Table check sum */ + st_qword(buf + GPTH_CurLba, 1); /* LBA of this header */ + st_qword(buf + GPTH_BakLba, sz_drv - 1); /* LBA of another header */ + st_qword(buf + GPTH_FstLba, 2 + sz_pt); /* LBA of first allocatable sector */ + st_qword(buf + GPTH_LstLba, s_bpt - 1); /* LBA of last allocatable sector */ + st_dword(buf + GPTH_PteSize, SZ_GPTE); /* Size of a table entry */ + st_dword(buf + GPTH_PtNum, GPT_ITEMS); /* Number of table entries */ + st_dword(buf + GPTH_PtOfs, 2); /* LBA of this table */ + rnd = make_rand(rnd, buf + GPTH_DskGuid, 16); /* Disk GUID */ + for (i = 0, bcc= 0xFFFFFFFF; i < 92; bcc = crc32(bcc, buf[i++])) ; /* Calculate header check sum */ + st_dword(buf + GPTH_Bcc, ~bcc); /* Header check sum */ + if (disk_write(drv, buf, 1, 1) != RES_OK) return FR_DISK_ERR; + + /* Create secondary GPT header */ + st_qword(buf + GPTH_CurLba, sz_drv - 1); /* LBA of this header */ + st_qword(buf + GPTH_BakLba, 1); /* LBA of another header */ + st_qword(buf + GPTH_PtOfs, s_bpt); /* LBA of this table */ + st_dword(buf + GPTH_Bcc, 0); + for (i = 0, bcc= 0xFFFFFFFF; i < 92; bcc = crc32(bcc, buf[i++])) ; /* Calculate header check sum */ + st_dword(buf + GPTH_Bcc, ~bcc); /* Header check sum */ + if (disk_write(drv, buf, sz_drv - 1, 1) != RES_OK) return FR_DISK_ERR; + + /* Create protective MBR */ + mem_set(buf, 0, ss); + mem_cpy(buf + MBR_Table, gpt_mbr, 16); /* Create a GPT partition */ + st_word(buf + BS_55AA, 0xAA55); + if (disk_write(drv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; + + } else +#endif + { /* Create partitions in MBR */ + sz_drv32 = (DWORD)sz_drv; + n_sc = N_SEC_TRACK; /* Determine drive CHS without any consideration of the drive geometry */ + for (n_hd = 8; n_hd != 0 && sz_drv32 / n_hd / n_sc > 1024; n_hd *= 2) ; + if (n_hd == 0) n_hd = 255; /* Number of heads needs to be <256 */ + + mem_set(buf, 0, FF_MAX_SS); /* Clear MBR */ + pte = buf + MBR_Table; /* Partition table in the MBR */ + for (i = 0, s_lba32 = n_sc; i < 4 && s_lba32 != 0 && s_lba32 < sz_drv32; i++, s_lba32 += n_lba32) { + n_lba32 = (DWORD)plst[i]; /* Get partition size */ + if (n_lba32 <= 100) n_lba32 = (n_lba32 == 100) ? sz_drv32 : sz_drv32 / 100 * n_lba32; /* Size in percentage? */ + if (s_lba32 + n_lba32 > sz_drv32 || s_lba32 + n_lba32 < s_lba32) n_lba32 = sz_drv32 - s_lba32; /* Clip at drive size */ + if (n_lba32 == 0) break; /* End of table or no sector to allocate? */ + + st_dword(pte + PTE_StLba, s_lba32); /* Start LBA */ + st_dword(pte + PTE_SizLba, n_lba32); /* Number of sectors */ + pte[PTE_System] = (BYTE)sys; /* System type */ + + cy = (UINT)(s_lba32 / n_sc / n_hd); /* Start cylinder */ + hd = (BYTE)(s_lba32 / n_sc % n_hd); /* Start head */ + sc = (BYTE)(s_lba32 % n_sc + 1); /* Start sector */ + pte[PTE_StHead] = hd; + pte[PTE_StSec] = (BYTE)((cy >> 2 & 0xC0) | sc); + pte[PTE_StCyl] = (BYTE)cy; + + cy = (UINT)((s_lba32 + n_lba32 - 1) / n_sc / n_hd); /* End cylinder */ + hd = (BYTE)((s_lba32 + n_lba32 - 1) / n_sc % n_hd); /* End head */ + sc = (BYTE)((s_lba32 + n_lba32 - 1) % n_sc + 1); /* End sector */ + pte[PTE_EdHead] = hd; + pte[PTE_EdSec] = (BYTE)((cy >> 2 & 0xC0) | sc); + pte[PTE_EdCyl] = (BYTE)cy; + + pte += SZ_PTE; /* Next entry */ + } + + st_word(buf + BS_55AA, 0xAA55); /* MBR signature */ + if (disk_write(drv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; /* Write it to the MBR */ + } + + return FR_OK; +} + + + +FRESULT f_mkfs ( + const TCHAR* path, /* Logical drive number */ + const MKFS_PARM* opt, /* Format options */ + void* work, /* Pointer to working buffer (null: use heap memory) */ + UINT len /* Size of working buffer [byte] */ ) { - const UINT n_fats = 1; /* Number of FATs for FAT/FAT32 volume (1 or 2) */ - const UINT n_rootdir = 512; /* Number of root directory entries for FAT volume */ static const WORD cst[] = {1, 4, 16, 64, 256, 512, 0}; /* Cluster size boundary for FAT volume (4Ks unit) */ static const WORD cst32[] = {1, 2, 4, 8, 16, 32, 0}; /* Cluster size boundary for FAT32 volume (128Ks unit) */ - BYTE fmt, sys, *buf, *pte, pdrv, part; + static const MKFS_PARM defopt = {FM_ANY, 0, 0, 0, 0}; /* Default parameter */ + BYTE fsopt, fsty, sys, *buf, *pte, pdrv, ipart; WORD ss; /* Sector size */ - DWORD szb_buf, sz_buf, sz_blk, n_clst, pau, sect, nsect, n; - DWORD b_vol, b_fat, b_data; /* Base LBA for volume, fat, data */ - DWORD sz_vol, sz_rsv, sz_fat, sz_dir; /* Size for volume, fat, dir, data */ - UINT i; + DWORD sz_buf, sz_blk, n_clst, pau, nsect, n; + LBA_t sz_vol, b_vol, b_fat, b_data; /* Size of volume, Base LBA of volume, fat, data */ + LBA_t sect, lba[2]; + DWORD sz_rsv, sz_fat, sz_dir, sz_au; /* Size of reserved, fat, dir, data, cluster */ + UINT n_fat, n_root, i; /* Index, Number of FATs and Number of roor dir entries */ int vol; - DSTATUS stat; -#if FF_USE_TRIM || FF_FS_EXFAT - DWORD tbl[3]; -#endif + DSTATUS ds; + FRESULT fr; /* Check mounted drive and clear work area */ vol = get_ldnumber(&path); /* Get target logical drive */ if (vol < 0) return FR_INVALID_DRIVE; - if (FatFs[vol]) FatFs[vol]->fs_type = 0; /* Clear the volume if mounted */ - pdrv = LD2PD(vol); /* Physical drive */ - part = LD2PT(vol); /* Partition (0:create as new, 1-4:get from partition table) */ + if (FatFs[vol]) FatFs[vol]->fs_type = 0; /* Clear the fs object if mounted */ + pdrv = LD2PD(vol); /* Physical drive */ + ipart = LD2PT(vol); /* Partition (0:create as new, 1..:get from partition table) */ + if (!opt) opt = &defopt; /* Use default parameter if it is not given */ - /* Check physical drive status */ - stat = disk_initialize(pdrv); - if (stat & STA_NOINIT) return FR_NOT_READY; - if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; - if (disk_ioctl(pdrv, GET_BLOCK_SIZE, &sz_blk) != RES_OK || !sz_blk || sz_blk > 32768 || (sz_blk & (sz_blk - 1))) sz_blk = 1; /* Erase block to align data area */ -#if FF_MAX_SS != FF_MIN_SS /* Get sector size of the medium if variable sector size cfg. */ + /* Get physical drive status (sz_drv, sz_blk, ss) */ + ds = disk_initialize(pdrv); + if (ds & STA_NOINIT) return FR_NOT_READY; + if (ds & STA_PROTECT) return FR_WRITE_PROTECTED; + sz_blk = opt->align; + if (sz_blk == 0 && disk_ioctl(pdrv, GET_BLOCK_SIZE, &sz_blk) != RES_OK) sz_blk = 1; + if (sz_blk == 0 || sz_blk > 0x8000 || (sz_blk & (sz_blk - 1))) sz_blk = 1; +#if FF_MAX_SS != FF_MIN_SS if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &ss) != RES_OK) return FR_DISK_ERR; if (ss > FF_MAX_SS || ss < FF_MIN_SS || (ss & (ss - 1))) return FR_DISK_ERR; #else ss = FF_MAX_SS; #endif - if ((au != 0 && au < ss) || au > 0x1000000 || (au & (au - 1))) return FR_INVALID_PARAMETER; /* Check if au is valid */ - au /= ss; /* Cluster size in unit of sector */ + /* Options for FAT sub-type and FAT parameters */ + fsopt = opt->fmt & (FM_ANY | FM_SFD); + n_fat = (opt->n_fat >= 1 && opt->n_fat <= 2) ? opt->n_fat : 1; + n_root = (opt->n_root >= 1 && opt->n_root <= 32768 && (opt->n_root % (ss / SZDIRE)) == 0) ? opt->n_root : 512; + sz_au = (opt->au_size <= 0x1000000 && (opt->au_size & (opt->au_size - 1)) == 0) ? opt->au_size : 0; + sz_au /= ss; /* Byte --> Sector */ /* Get working buffer */ + sz_buf = len / ss; /* Size of working buffer [sector] */ + if (sz_buf == 0) return FR_NOT_ENOUGH_CORE; + buf = (BYTE*)work; /* Working buffer */ #if FF_USE_LFN == 3 - if (!work) { /* Use heap memory for working buffer */ - for (szb_buf = MAX_MALLOC, buf = 0; szb_buf >= ss && (buf = ff_memalloc(szb_buf)) == 0; szb_buf /= 2) ; - sz_buf = szb_buf / ss; /* Size of working buffer (sector) */ - } else + if (!buf) buf = ff_memalloc(sz_buf * ss); /* Use heap memory for working buffer */ #endif - { - buf = (BYTE*)work; /* Working buffer */ - sz_buf = len / ss; /* Size of working buffer (sector) */ - szb_buf = sz_buf * ss; /* Size of working buffer (byte) */ - } - if (!buf || sz_buf == 0) return FR_NOT_ENOUGH_CORE; + if (!buf) return FR_NOT_ENOUGH_CORE; /* Determine where the volume to be located (b_vol, sz_vol) */ - if (FF_MULTI_PARTITION && part != 0) { - /* Get partition information from partition table in the MBR */ + b_vol = sz_vol = 0; + if (FF_MULTI_PARTITION && ipart != 0) { /* Is the volume associated with any specific partition? */ + /* Get partition location from the existing partition table */ if (disk_read(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Load MBR */ if (ld_word(buf + BS_55AA) != 0xAA55) LEAVE_MKFS(FR_MKFS_ABORTED); /* Check if MBR is valid */ - pte = buf + (MBR_Table + (part - 1) * SZ_PTE); - if (pte[PTE_System] == 0) LEAVE_MKFS(FR_MKFS_ABORTED); /* No partition? */ - b_vol = ld_dword(pte + PTE_StLba); /* Get volume start sector */ - sz_vol = ld_dword(pte + PTE_SizLba); /* Get volume size */ - } else { - /* Create a single-partition in this function */ +#if FF_LBA64 + if (buf[MBR_Table + PTE_System] == 0xEE) { /* GPT protective MBR? */ + DWORD n_ent, ofs; + QWORD pt_lba; + + /* Get the partition location from GPT */ + if (disk_read(pdrv, buf, 1, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Load GPT header sector (next to MBR) */ + if (!test_gpt_header(buf)) LEAVE_MKFS(FR_MKFS_ABORTED); /* Check if GPT header is valid */ + n_ent = ld_dword(buf + GPTH_PtNum); /* Number of entries */ + pt_lba = ld_qword(buf + GPTH_PtOfs); /* Table start sector */ + ofs = i = 0; + while (n_ent) { /* Find MS Basic partition with order of ipart */ + if (ofs == 0 && disk_read(pdrv, buf, pt_lba++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Get PT sector */ + if (!mem_cmp(buf + ofs + GPTE_PtGuid, GUID_MS_Basic, 16) && ++i == ipart) { /* MS basic data partition? */ + b_vol = ld_qword(buf + ofs + GPTE_FstLba); + sz_vol = ld_qword(buf + ofs + GPTE_LstLba) - b_vol + 1; + break; + } + n_ent--; ofs = (ofs + SZ_GPTE) % ss; /* Next entry */ + } + if (n_ent == 0) LEAVE_MKFS(FR_MKFS_ABORTED); /* Partition not found */ + fsopt |= 0x80; /* Partitioning is in GPT */ + } else +#endif + { /* Get the partition location from MBR partition table */ + pte = buf + (MBR_Table + (ipart - 1) * SZ_PTE); + if (ipart > 4 || pte[PTE_System] == 0) LEAVE_MKFS(FR_MKFS_ABORTED); /* No partition? */ + b_vol = ld_dword(pte + PTE_StLba); /* Get volume start sector */ + sz_vol = ld_dword(pte + PTE_SizLba); /* Get volume size */ + } + } else { /* The volume is associated with a physical drive */ if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_vol) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); - b_vol = (opt & FM_SFD) ? 0 : 63; /* Volume start sector */ - if (sz_vol < b_vol) LEAVE_MKFS(FR_MKFS_ABORTED); - sz_vol -= b_vol; /* Volume size */ + if (!(fsopt & FM_SFD)) { /* To be partitioned? */ + /* Create a single-partition on the drive in this function */ +#if FF_LBA64 + if (sz_vol >= FF_MIN_GPT) { /* Which partition type to create, MBR or GPT? */ + fsopt |= 0x80; /* Partitioning is in GPT */ + b_vol = GPT_ALIGN / ss; sz_vol -= b_vol + GPT_ITEMS * SZ_GPTE / ss + 1; /* Estimated partition offset and size */ + } else +#endif + { /* Partitioning is in MBR */ + if (sz_vol > N_SEC_TRACK) { + b_vol = N_SEC_TRACK; sz_vol -= b_vol; /* Estimated partition offset and size */ + } + } + } } if (sz_vol < 128) LEAVE_MKFS(FR_MKFS_ABORTED); /* Check if volume size is >=128s */ - /* Pre-determine the FAT type */ - do { - if (FF_FS_EXFAT && (opt & FM_EXFAT)) { /* exFAT possible? */ - if ((opt & FM_ANY) == FM_EXFAT || sz_vol >= 0x4000000 || au > 128) { /* exFAT only, vol >= 64Ms or au > 128s ? */ - fmt = FS_EXFAT; break; + /* Now start to create a FAT volume at b_vol and sz_vol */ + + do { /* Pre-determine the FAT type */ + if (FF_FS_EXFAT && (fsopt & FM_EXFAT)) { /* exFAT possible? */ + if ((fsopt & FM_ANY) == FM_EXFAT || sz_vol >= 0x4000000 || sz_au > 128) { /* exFAT only, vol >= 64MS or sz_au > 128S ? */ + fsty = FS_EXFAT; break; } } - if (au > 128) LEAVE_MKFS(FR_INVALID_PARAMETER); /* Too large au for FAT/FAT32 */ - if (opt & FM_FAT32) { /* FAT32 possible? */ - if ((opt & FM_ANY) == FM_FAT32 || !(opt & FM_FAT)) { /* FAT32 only or no-FAT? */ - fmt = FS_FAT32; break; +#if FF_LBA64 + if (sz_vol >= 0x100000000) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too large volume for FAT/FAT32 */ +#endif + if (sz_au > 128) sz_au = 128; /* Invalid AU for FAT/FAT32? */ + if (fsopt & FM_FAT32) { /* FAT32 possible? */ + if (!(fsopt & FM_FAT)) { /* no-FAT? */ + fsty = FS_FAT32; break; } } - if (!(opt & FM_FAT)) LEAVE_MKFS(FR_INVALID_PARAMETER); /* no-FAT? */ - fmt = FS_FAT16; + if (!(fsopt & FM_FAT)) LEAVE_MKFS(FR_INVALID_PARAMETER); /* no-FAT? */ + fsty = FS_FAT16; } while (0); #if FF_FS_EXFAT - if (fmt == FS_EXFAT) { /* Create an exFAT volume */ - DWORD szb_bit, szb_case, sum, nb, cl; + if (fsty == FS_EXFAT) { /* Create an exFAT volume */ + DWORD szb_bit, szb_case, sum, nb, cl, tbl[3]; WCHAR ch, si; UINT j, st; BYTE b; - if (sz_vol < 0x1000) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume? */ + if (sz_vol < 0x1000) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume for exFAT? */ #if FF_USE_TRIM - tbl[0] = b_vol; tbl[1] = b_vol + sz_vol - 1; /* Inform the device the volume area may be erased */ - disk_ioctl(pdrv, CTRL_TRIM, tbl); + lba[0] = b_vol; lba[1] = b_vol + sz_vol - 1; /* Inform storage device that the volume area may be erased */ + disk_ioctl(pdrv, CTRL_TRIM, lba); #endif /* Determine FAT location, data location and number of clusters */ - if (au == 0) { /* au auto-selection */ - au = 8; - if (sz_vol >= 0x80000) au = 64; /* >= 512Ks */ - if (sz_vol >= 0x4000000) au = 256; /* >= 64Ms */ + if (sz_au == 0) { /* AU auto-selection */ + sz_au = 8; + if (sz_vol >= 0x80000) sz_au = 64; /* >= 512Ks */ + if (sz_vol >= 0x4000000) sz_au = 256; /* >= 64Ms */ } b_fat = b_vol + 32; /* FAT start at offset 32 */ - sz_fat = ((sz_vol / au + 2) * 4 + ss - 1) / ss; /* Number of FAT sectors */ - b_data = (b_fat + sz_fat + sz_blk - 1) & ~(sz_blk - 1); /* Align data area to the erase block boundary */ + sz_fat = (DWORD)((sz_vol / sz_au + 2) * 4 + ss - 1) / ss; /* Number of FAT sectors */ + b_data = (b_fat + sz_fat + sz_blk - 1) & ~((LBA_t)sz_blk - 1); /* Align data area to the erase block boundary */ if (b_data - b_vol >= sz_vol / 2) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume? */ - n_clst = (sz_vol - (b_data - b_vol)) / au; /* Number of clusters */ + n_clst = (DWORD)(sz_vol - (b_data - b_vol)) / sz_au; /* Number of clusters */ if (n_clst <16) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too few clusters? */ if (n_clst > MAX_EXFAT) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too many clusters? */ - szb_bit = (n_clst + 7) / 8; /* Size of allocation bitmap */ - tbl[0] = (szb_bit + au * ss - 1) / (au * ss); /* Number of allocation bitmap clusters */ + szb_bit = (n_clst + 7) / 8; /* Size of allocation bitmap */ + tbl[0] = (szb_bit + sz_au * ss - 1) / (sz_au * ss); /* Number of allocation bitmap clusters */ /* Create a compressed up-case table */ - sect = b_data + au * tbl[0]; /* Table start sector */ + sect = b_data + sz_au * tbl[0]; /* Table start sector */ sum = 0; /* Table checksum to be stored in the 82 entry */ st = 0; si = 0; i = 0; j = 0; szb_case = 0; do { @@ -5681,22 +6022,22 @@ FRESULT f_mkfs ( sum = xsum32(buf[i + 0] = (BYTE)ch, sum); /* Put it into the write buffer */ sum = xsum32(buf[i + 1] = (BYTE)(ch >> 8), sum); i += 2; szb_case += 2; - if (si == 0 || i == szb_buf) { /* Write buffered data when buffer full or end of process */ + if (si == 0 || i == sz_buf * ss) { /* Write buffered data when buffer full or end of process */ n = (i + ss - 1) / ss; if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); sect += n; i = 0; } } while (si); - tbl[1] = (szb_case + au * ss - 1) / (au * ss); /* Number of up-case table clusters */ + tbl[1] = (szb_case + sz_au * ss - 1) / (sz_au * ss); /* Number of up-case table clusters */ tbl[2] = 1; /* Number of root dir clusters */ /* Initialize the allocation bitmap */ sect = b_data; nsect = (szb_bit + ss - 1) / ss; /* Start of bitmap and number of sectors */ nb = tbl[0] + tbl[1] + tbl[2]; /* Number of clusters in-use by system */ do { - mem_set(buf, 0, szb_buf); - for (i = 0; nb >= 8 && i < szb_buf; buf[i++] = 0xFF, nb -= 8) ; - for (b = 1; nb != 0 && i < szb_buf; buf[i] |= b, b <<= 1, nb--) ; + mem_set(buf, 0, sz_buf * ss); + for (i = 0; nb >= 8 && i < sz_buf * ss; buf[i++] = 0xFF, nb -= 8) ; + for (b = 1; nb != 0 && i < sz_buf * ss; buf[i] |= b, b <<= 1, nb--) ; n = (nsect > sz_buf) ? sz_buf : nsect; /* Write the buffered data */ if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); sect += n; nsect -= n; @@ -5706,34 +6047,34 @@ FRESULT f_mkfs ( sect = b_fat; nsect = sz_fat; /* Start of FAT and number of FAT sectors */ j = nb = cl = 0; do { - mem_set(buf, 0, szb_buf); i = 0; /* Clear work area and reset write index */ - if (cl == 0) { /* Set entry 0 and 1 */ + mem_set(buf, 0, sz_buf * ss); i = 0; /* Clear work area and reset write index */ + if (cl == 0) { /* Set FAT [0] and FAT[1] */ st_dword(buf + i, 0xFFFFFFF8); i += 4; cl++; st_dword(buf + i, 0xFFFFFFFF); i += 4; cl++; } do { /* Create chains of bitmap, up-case and root dir */ - while (nb != 0 && i < szb_buf) { /* Create a chain */ + while (nb != 0 && i < sz_buf * ss) { /* Create a chain */ st_dword(buf + i, (nb > 1) ? cl + 1 : 0xFFFFFFFF); i += 4; cl++; nb--; } if (nb == 0 && j < 3) nb = tbl[j++]; /* Next chain */ - } while (nb != 0 && i < szb_buf); + } while (nb != 0 && i < sz_buf * ss); n = (nsect > sz_buf) ? sz_buf : nsect; /* Write the buffered data */ if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); sect += n; nsect -= n; } while (nsect); /* Initialize the root directory */ - mem_set(buf, 0, szb_buf); - buf[SZDIRE * 0 + 0] = ET_VLABEL; /* Volume label entry */ - buf[SZDIRE * 1 + 0] = ET_BITMAP; /* Bitmap entry */ - st_dword(buf + SZDIRE * 1 + 20, 2); /* cluster */ - st_dword(buf + SZDIRE * 1 + 24, szb_bit); /* size */ - buf[SZDIRE * 2 + 0] = ET_UPCASE; /* Up-case table entry */ - st_dword(buf + SZDIRE * 2 + 4, sum); /* sum */ - st_dword(buf + SZDIRE * 2 + 20, 2 + tbl[0]); /* cluster */ - st_dword(buf + SZDIRE * 2 + 24, szb_case); /* size */ - sect = b_data + au * (tbl[0] + tbl[1]); nsect = au; /* Start of the root directory and number of sectors */ + mem_set(buf, 0, sz_buf * ss); + buf[SZDIRE * 0 + 0] = ET_VLABEL; /* Volume label entry (no label) */ + buf[SZDIRE * 1 + 0] = ET_BITMAP; /* Bitmap entry */ + st_dword(buf + SZDIRE * 1 + 20, 2); /* cluster */ + st_dword(buf + SZDIRE * 1 + 24, szb_bit); /* size */ + buf[SZDIRE * 2 + 0] = ET_UPCASE; /* Up-case table entry */ + st_dword(buf + SZDIRE * 2 + 4, sum); /* sum */ + st_dword(buf + SZDIRE * 2 + 20, 2 + tbl[0]); /* cluster */ + st_dword(buf + SZDIRE * 2 + 24, szb_case); /* size */ + sect = b_data + sz_au * (tbl[0] + tbl[1]); nsect = sz_au; /* Start of the root directory and number of sectors */ do { /* Fill root directory sectors */ n = (nsect > sz_buf) ? sz_buf : nsect; if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); @@ -5747,17 +6088,17 @@ FRESULT f_mkfs ( /* Main record (+0) */ mem_set(buf, 0, ss); mem_cpy(buf + BS_JmpBoot, "\xEB\x76\x90" "EXFAT ", 11); /* Boot jump code (x86), OEM name */ - st_dword(buf + BPB_VolOfsEx, b_vol); /* Volume offset in the physical drive [sector] */ - st_dword(buf + BPB_TotSecEx, sz_vol); /* Volume size [sector] */ - st_dword(buf + BPB_FatOfsEx, b_fat - b_vol); /* FAT offset [sector] */ + st_qword(buf + BPB_VolOfsEx, b_vol); /* Volume offset in the physical drive [sector] */ + st_qword(buf + BPB_TotSecEx, sz_vol); /* Volume size [sector] */ + st_dword(buf + BPB_FatOfsEx, (DWORD)(b_fat - b_vol)); /* FAT offset [sector] */ st_dword(buf + BPB_FatSzEx, sz_fat); /* FAT size [sector] */ - st_dword(buf + BPB_DataOfsEx, b_data - b_vol); /* Data offset [sector] */ + st_dword(buf + BPB_DataOfsEx, (DWORD)(b_data - b_vol)); /* Data offset [sector] */ st_dword(buf + BPB_NumClusEx, n_clst); /* Number of clusters */ st_dword(buf + BPB_RootClusEx, 2 + tbl[0] + tbl[1]); /* Root dir cluster # */ st_dword(buf + BPB_VolIDEx, GET_FATTIME()); /* VSN */ st_word(buf + BPB_FSVerEx, 0x100); /* Filesystem version (1.00) */ for (buf[BPB_BytsPerSecEx] = 0, i = ss; i >>= 1; buf[BPB_BytsPerSecEx]++) ; /* Log2 of sector size [byte] */ - for (buf[BPB_SecPerClusEx] = 0, i = au; i >>= 1; buf[BPB_SecPerClusEx]++) ; /* Log2 of cluster size [sector] */ + for (buf[BPB_SecPerClusEx] = 0, i = sz_au; i >>= 1; buf[BPB_SecPerClusEx]++) ; /* Log2 of cluster size [sector] */ buf[BPB_NumFATsEx] = 1; /* Number of FATs */ buf[BPB_DrvNumEx] = 0x80; /* Drive number (for int13) */ st_word(buf + BS_BootCodeEx, 0xFEEB); /* Boot code (x86) */ @@ -5788,79 +6129,82 @@ FRESULT f_mkfs ( #endif /* FF_FS_EXFAT */ { /* Create an FAT/FAT32 volume */ do { - pau = au; + pau = sz_au; /* Pre-determine number of clusters and FAT sub-type */ - if (fmt == FS_FAT32) { /* FAT32 volume */ - if (pau == 0) { /* au auto-selection */ - n = sz_vol / 0x20000; /* Volume size in unit of 128KS */ + if (fsty == FS_FAT32) { /* FAT32 volume */ + if (pau == 0) { /* AU auto-selection */ + n = (DWORD)sz_vol / 0x20000; /* Volume size in unit of 128KS */ for (i = 0, pau = 1; cst32[i] && cst32[i] <= n; i++, pau <<= 1) ; /* Get from table */ } - n_clst = sz_vol / pau; /* Number of clusters */ + n_clst = (DWORD)sz_vol / pau; /* Number of clusters */ sz_fat = (n_clst * 4 + 8 + ss - 1) / ss; /* FAT size [sector] */ sz_rsv = 32; /* Number of reserved sectors */ sz_dir = 0; /* No static directory */ if (n_clst <= MAX_FAT16 || n_clst > MAX_FAT32) LEAVE_MKFS(FR_MKFS_ABORTED); } else { /* FAT volume */ if (pau == 0) { /* au auto-selection */ - n = sz_vol / 0x1000; /* Volume size in unit of 4KS */ + n = (DWORD)sz_vol / 0x1000; /* Volume size in unit of 4KS */ for (i = 0, pau = 1; cst[i] && cst[i] <= n; i++, pau <<= 1) ; /* Get from table */ } - n_clst = sz_vol / pau; + n_clst = (DWORD)sz_vol / pau; if (n_clst > MAX_FAT12) { n = n_clst * 2 + 4; /* FAT size [byte] */ } else { - fmt = FS_FAT12; + fsty = FS_FAT12; n = (n_clst * 3 + 1) / 2 + 3; /* FAT size [byte] */ } sz_fat = (n + ss - 1) / ss; /* FAT size [sector] */ sz_rsv = 1; /* Number of reserved sectors */ - sz_dir = (DWORD)n_rootdir * SZDIRE / ss; /* Rootdir size [sector] */ + sz_dir = (DWORD)n_root * SZDIRE / ss; /* Root dir size [sector] */ } b_fat = b_vol + sz_rsv; /* FAT base */ - b_data = b_fat + sz_fat * n_fats + sz_dir; /* Data base */ + b_data = b_fat + sz_fat * n_fat + sz_dir; /* Data base */ - /* Align data base to erase block boundary (for flash memory media) */ - n = ((b_data + sz_blk - 1) & ~(sz_blk - 1)) - b_data; /* Next nearest erase block from current data base */ - if (fmt == FS_FAT32) { /* FAT32: Move FAT base */ + /* Align data area to erase block boundary (for flash memory media) */ + n = (DWORD)(((b_data + sz_blk - 1) & ~(sz_blk - 1)) - b_data); /* Sectors to next nearest from current data base */ + if (fsty == FS_FAT32) { /* FAT32: Move FAT */ sz_rsv += n; b_fat += n; - } else { /* FAT: Expand FAT size */ - sz_fat += n / n_fats; + } else { /* FAT: Expand FAT */ + if (n % n_fat) { /* Adjust fractional error if needed */ + n--; sz_rsv++; b_fat++; + } + sz_fat += n / n_fat; } /* Determine number of clusters and final check of validity of the FAT sub-type */ - if (sz_vol < b_data + pau * 16 - b_vol) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume */ - n_clst = (sz_vol - sz_rsv - sz_fat * n_fats - sz_dir) / pau; - if (fmt == FS_FAT32) { - if (n_clst <= MAX_FAT16) { /* Too few clusters for FAT32 */ - if (au == 0 && (au = pau / 2) != 0) continue; /* Adjust cluster size and retry */ + if (sz_vol < b_data + pau * 16 - b_vol) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume? */ + n_clst = ((DWORD)sz_vol - sz_rsv - sz_fat * n_fat - sz_dir) / pau; + if (fsty == FS_FAT32) { + if (n_clst <= MAX_FAT16) { /* Too few clusters for FAT32? */ + if (sz_au == 0 && (sz_au = pau / 2) != 0) continue; /* Adjust cluster size and retry */ LEAVE_MKFS(FR_MKFS_ABORTED); } } - if (fmt == FS_FAT16) { + if (fsty == FS_FAT16) { if (n_clst > MAX_FAT16) { /* Too many clusters for FAT16 */ - if (au == 0 && (pau * 2) <= 64) { - au = pau * 2; continue; /* Adjust cluster size and retry */ + if (sz_au == 0 && (pau * 2) <= 64) { + sz_au = pau * 2; continue; /* Adjust cluster size and retry */ } - if ((opt & FM_FAT32)) { - fmt = FS_FAT32; continue; /* Switch type to FAT32 and retry */ + if ((fsopt & FM_FAT32)) { + fsty = FS_FAT32; continue; /* Switch type to FAT32 and retry */ } - if (au == 0 && (au = pau * 2) <= 128) continue; /* Adjust cluster size and retry */ + if (sz_au == 0 && (sz_au = pau * 2) <= 128) continue; /* Adjust cluster size and retry */ LEAVE_MKFS(FR_MKFS_ABORTED); } if (n_clst <= MAX_FAT12) { /* Too few clusters for FAT16 */ - if (au == 0 && (au = pau * 2) <= 128) continue; /* Adjust cluster size and retry */ + if (sz_au == 0 && (sz_au = pau * 2) <= 128) continue; /* Adjust cluster size and retry */ LEAVE_MKFS(FR_MKFS_ABORTED); } } - if (fmt == FS_FAT12 && n_clst > MAX_FAT12) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too many clusters for FAT12 */ + if (fsty == FS_FAT12 && n_clst > MAX_FAT12) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too many clusters for FAT12 */ /* Ok, it is the valid cluster configuration */ break; } while (1); #if FF_USE_TRIM - tbl[0] = b_vol; tbl[1] = b_vol + sz_vol - 1; /* Inform the device the volume area can be erased */ - disk_ioctl(pdrv, CTRL_TRIM, tbl); + lba[0] = b_vol; lba[1] = b_vol + sz_vol - 1; /* Inform storage device that the volume area may be erased */ + disk_ioctl(pdrv, CTRL_TRIM, lba); #endif /* Create FAT VBR */ mem_set(buf, 0, ss); @@ -5868,18 +6212,18 @@ FRESULT f_mkfs ( st_word(buf + BPB_BytsPerSec, ss); /* Sector size [byte] */ buf[BPB_SecPerClus] = (BYTE)pau; /* Cluster size [sector] */ st_word(buf + BPB_RsvdSecCnt, (WORD)sz_rsv); /* Size of reserved area */ - buf[BPB_NumFATs] = (BYTE)n_fats; /* Number of FATs */ - st_word(buf + BPB_RootEntCnt, (WORD)((fmt == FS_FAT32) ? 0 : n_rootdir)); /* Number of root directory entries */ + buf[BPB_NumFATs] = (BYTE)n_fat; /* Number of FATs */ + st_word(buf + BPB_RootEntCnt, (WORD)((fsty == FS_FAT32) ? 0 : n_root)); /* Number of root directory entries */ if (sz_vol < 0x10000) { st_word(buf + BPB_TotSec16, (WORD)sz_vol); /* Volume size in 16-bit LBA */ } else { - st_dword(buf + BPB_TotSec32, sz_vol); /* Volume size in 32-bit LBA */ + st_dword(buf + BPB_TotSec32, (DWORD)sz_vol); /* Volume size in 32-bit LBA */ } buf[BPB_Media] = 0xF8; /* Media descriptor byte */ st_word(buf + BPB_SecPerTrk, 63); /* Number of sectors per track (for int13) */ st_word(buf + BPB_NumHeads, 255); /* Number of heads (for int13) */ - st_dword(buf + BPB_HiddSec, b_vol); /* Volume offset in the physical drive [sector] */ - if (fmt == FS_FAT32) { + st_dword(buf + BPB_HiddSec, (DWORD)b_vol); /* Volume offset in the physical drive [sector] */ + if (fsty == FS_FAT32) { st_dword(buf + BS_VolID32, GET_FATTIME()); /* VSN */ st_dword(buf + BPB_FATSz32, sz_fat); /* FAT size [sector] */ st_dword(buf + BPB_RootClus32, 2); /* Root directory cluster # (2) */ @@ -5899,7 +6243,7 @@ FRESULT f_mkfs ( if (disk_write(pdrv, buf, b_vol, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Write it to the VBR sector */ /* Create FSINFO record if needed */ - if (fmt == FS_FAT32) { + if (fsty == FS_FAT32) { disk_write(pdrv, buf, b_vol + 6, 1); /* Write backup VBR (VBR + 6) */ mem_set(buf, 0, ss); st_dword(buf + FSI_LeadSig, 0x41615252); @@ -5912,27 +6256,27 @@ FRESULT f_mkfs ( } /* Initialize FAT area */ - mem_set(buf, 0, (UINT)szb_buf); + mem_set(buf, 0, sz_buf * ss); sect = b_fat; /* FAT start sector */ - for (i = 0; i < n_fats; i++) { /* Initialize FATs each */ - if (fmt == FS_FAT32) { - st_dword(buf + 0, 0xFFFFFFF8); /* Entry 0 */ - st_dword(buf + 4, 0xFFFFFFFF); /* Entry 1 */ - st_dword(buf + 8, 0x0FFFFFFF); /* Entry 2 (root directory) */ + for (i = 0; i < n_fat; i++) { /* Initialize FATs each */ + if (fsty == FS_FAT32) { + st_dword(buf + 0, 0xFFFFFFF8); /* FAT[0] */ + st_dword(buf + 4, 0xFFFFFFFF); /* FAT[1] */ + st_dword(buf + 8, 0x0FFFFFFF); /* FAT[2] (root directory) */ } else { - st_dword(buf + 0, (fmt == FS_FAT12) ? 0xFFFFF8 : 0xFFFFFFF8); /* Entry 0 and 1 */ + st_dword(buf + 0, (fsty == FS_FAT12) ? 0xFFFFF8 : 0xFFFFFFF8); /* FAT[0] and FAT[1] */ } nsect = sz_fat; /* Number of FAT sectors */ do { /* Fill FAT sectors */ n = (nsect > sz_buf) ? sz_buf : nsect; if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); - mem_set(buf, 0, ss); + mem_set(buf, 0, ss); /* Rest of FAT all are cleared */ sect += n; nsect -= n; } while (nsect); } /* Initialize root directory (fill with zero) */ - nsect = (fmt == FS_FAT32) ? pau : sz_dir; /* Number of root directory sectors */ + nsect = (fsty == FS_FAT32) ? pau : sz_dir; /* Number of root directory sectors */ do { n = (nsect > sz_buf) ? sz_buf : nsect; if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); @@ -5940,44 +6284,36 @@ FRESULT f_mkfs ( } while (nsect); } - /* Determine system ID in the partition table */ - if (FF_FS_EXFAT && fmt == FS_EXFAT) { - sys = 0x07; /* HPFS/NTFS/exFAT */ + /* A FAT volume has been created here */ + + /* Determine system ID in the MBR partition table */ + if (FF_FS_EXFAT && fsty == FS_EXFAT) { + sys = 0x07; /* exFAT */ } else { - if (fmt == FS_FAT32) { + if (fsty == FS_FAT32) { sys = 0x0C; /* FAT32X */ } else { if (sz_vol >= 0x10000) { sys = 0x06; /* FAT12/16 (large) */ } else { - sys = (fmt == FS_FAT16) ? 0x04 : 0x01; /* FAT16 : FAT12 */ + sys = (fsty == FS_FAT16) ? 0x04 : 0x01; /* FAT16 : FAT12 */ } } } /* Update partition information */ - if (FF_MULTI_PARTITION && part != 0) { /* Created in the existing partition */ - /* Update system ID in the partition table */ - if (disk_read(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Read the MBR */ - buf[MBR_Table + (part - 1) * SZ_PTE + PTE_System] = sys; /* Set system ID */ - if (disk_write(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Write it back to the MBR */ - } else { /* Created as a new single partition */ - if (!(opt & FM_SFD)) { /* Create partition table if in FDISK format */ - mem_set(buf, 0, ss); - st_word(buf + BS_55AA, 0xAA55); /* MBR signature */ - pte = buf + MBR_Table; /* Create partition table for single partition in the drive */ - pte[PTE_Boot] = 0; /* Boot indicator */ - pte[PTE_StHead] = 1; /* Start head */ - pte[PTE_StSec] = 1; /* Start sector */ - pte[PTE_StCyl] = 0; /* Start cylinder */ - pte[PTE_System] = sys; /* System type */ - n = (b_vol + sz_vol) / (63 * 255); /* (End CHS may be invalid) */ - pte[PTE_EdHead] = 254; /* End head */ - pte[PTE_EdSec] = (BYTE)(((n >> 2) & 0xC0) | 63); /* End sector */ - pte[PTE_EdCyl] = (BYTE)n; /* End cylinder */ - st_dword(pte + PTE_StLba, b_vol); /* Start offset in LBA */ - st_dword(pte + PTE_SizLba, sz_vol); /* Size in sectors */ - if (disk_write(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Write it to the MBR */ + if (FF_MULTI_PARTITION && ipart != 0) { /* Volume is in the existing partition */ + if (!FF_LBA64 || !(fsopt & 0x80)) { + /* Update system ID in the partition table */ + if (disk_read(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Read the MBR */ + buf[MBR_Table + (ipart - 1) * SZ_PTE + PTE_System] = sys; /* Set system ID */ + if (disk_write(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Write it back to the MBR */ + } + } else { /* Volume as a new single partition */ + if (!(fsopt & FM_SFD)) { /* Create partition table if not in SFD */ + lba[0] = sz_vol, lba[1] = 0; + fr = create_partition(pdrv, lba, sys, buf); + if (fr != FR_OK) LEAVE_MKFS(fr); } } @@ -5988,6 +6324,7 @@ FRESULT f_mkfs ( + #if FF_MULTI_PARTITION /*-----------------------------------------------------------------------*/ /* Create Partition Table on the Physical Drive */ @@ -5995,75 +6332,27 @@ FRESULT f_mkfs ( FRESULT f_fdisk ( BYTE pdrv, /* Physical drive number */ - const DWORD* szt, /* Pointer to the size table for each partitions */ + const LBA_t ptbl[], /* Pointer to the size table for each partitions */ void* work /* Pointer to the working buffer (null: use heap memory) */ ) { - UINT i, n, sz_cyl, tot_cyl, b_cyl, e_cyl, p_cyl; - BYTE s_hd, e_hd, *p, *buf = (BYTE*)work; + BYTE *buf = (BYTE*)work; DSTATUS stat; - DWORD sz_disk, sz_part, s_part; - FRESULT res; stat = disk_initialize(pdrv); if (stat & STA_NOINIT) return FR_NOT_READY; if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; - if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_disk)) return FR_DISK_ERR; - - buf = (BYTE*)work; #if FF_USE_LFN == 3 if (!buf) buf = ff_memalloc(FF_MAX_SS); /* Use heap memory for working buffer */ #endif if (!buf) return FR_NOT_ENOUGH_CORE; - /* Determine the CHS without any consideration of the drive geometry */ - for (n = 16; n < 256 && sz_disk / n / 63 > 1024; n *= 2) ; - if (n == 256) n--; - e_hd = (BYTE)(n - 1); - sz_cyl = 63 * n; - tot_cyl = sz_disk / sz_cyl; - - /* Create partition table */ - mem_set(buf, 0, FF_MAX_SS); - p = buf + MBR_Table; b_cyl = 0; - for (i = 0; i < 4; i++, p += SZ_PTE) { - p_cyl = (szt[i] <= 100U) ? (DWORD)tot_cyl * szt[i] / 100 : szt[i] / sz_cyl; /* Number of cylinders */ - if (p_cyl == 0) continue; - s_part = (DWORD)sz_cyl * b_cyl; - sz_part = (DWORD)sz_cyl * p_cyl; - if (i == 0) { /* Exclude first track of cylinder 0 */ - s_hd = 1; - s_part += 63; sz_part -= 63; - } else { - s_hd = 0; - } - e_cyl = b_cyl + p_cyl - 1; /* End cylinder */ - if (e_cyl >= tot_cyl) LEAVE_MKFS(FR_INVALID_PARAMETER); - - /* Set partition table */ - p[1] = s_hd; /* Start head */ - p[2] = (BYTE)(((b_cyl >> 2) & 0xC0) | 1); /* Start sector */ - p[3] = (BYTE)b_cyl; /* Start cylinder */ - p[4] = 0x07; /* System type (temporary setting) */ - p[5] = e_hd; /* End head */ - p[6] = (BYTE)(((e_cyl >> 2) & 0xC0) | 63); /* End sector */ - p[7] = (BYTE)e_cyl; /* End cylinder */ - st_dword(p + 8, s_part); /* Start sector in LBA */ - st_dword(p + 12, sz_part); /* Number of sectors */ - - /* Next partition */ - b_cyl += p_cyl; - } - st_word(p, 0xAA55); /* MBR signature (always at offset 510) */ - - /* Write it to the MBR */ - res = (disk_write(pdrv, buf, 0, 1) == RES_OK && disk_ioctl(pdrv, CTRL_SYNC, 0) == RES_OK) ? FR_OK : FR_DISK_ERR; - LEAVE_MKFS(res); + LEAVE_MKFS(create_partition(pdrv, ptbl, 0x07, buf)); } #endif /* FF_MULTI_PARTITION */ -#endif /* FF_USE_MKFS && !FF_FS_READONLY */ +#endif /* !FF_FS_READONLY && FF_USE_MKFS */ @@ -6077,7 +6366,7 @@ FRESULT f_fdisk ( /*-----------------------------------------------------------------------*/ TCHAR* f_gets ( - TCHAR* buff, /* Pointer to the string buffer to read */ + TCHAR* buff, /* Pointer to the buffer to store read string */ int len, /* Size of string buffer (items) */ FIL* fp /* Pointer to the file object */ ) @@ -6100,49 +6389,51 @@ TCHAR* f_gets ( if (FF_LFN_UNICODE == 2) len -= (FF_STRF_ENCODE == 0) ? 3 : 4; if (FF_LFN_UNICODE == 3) len -= 1; while (nc < len) { -#if FF_STRF_ENCODE == 0 /* Read a character in ANSI/OEM */ - f_read(fp, s, 1, &rc); - if (rc != 1) break; +#if FF_STRF_ENCODE == 0 /* Read a character in ANSI/OEM */ + f_read(fp, s, 1, &rc); /* Get a code unit */ + if (rc != 1) break; /* EOF? */ wc = s[0]; - if (dbc_1st((BYTE)wc)) { - f_read(fp, s, 1, &rc); - if (rc != 1 || !dbc_2nd(s[0])) continue; + if (dbc_1st((BYTE)wc)) { /* DBC 1st byte? */ + f_read(fp, s, 1, &rc); /* Get DBC 2nd byte */ + if (rc != 1 || !dbc_2nd(s[0])) continue; /* Wrong code? */ wc = wc << 8 | s[0]; } - dc = ff_oem2uni(wc, CODEPAGE); + dc = ff_oem2uni(wc, CODEPAGE); /* OEM --> */ if (dc == 0) continue; #elif FF_STRF_ENCODE == 1 || FF_STRF_ENCODE == 2 /* Read a character in UTF-16LE/BE */ - f_read(fp, s, 2, &rc); - if (rc != 2) break; + f_read(fp, s, 2, &rc); /* Get a code unit */ + if (rc != 2) break; /* EOF? */ dc = (FF_STRF_ENCODE == 1) ? ld_word(s) : s[0] << 8 | s[1]; - if (IsSurrogateL(dc)) continue; - if (IsSurrogateH(dc)) { - f_read(fp, s, 2, &rc); - if (rc != 2) break; + if (IsSurrogateL(dc)) continue; /* Broken surrogate pair? */ + if (IsSurrogateH(dc)) { /* High surrogate? */ + f_read(fp, s, 2, &rc); /* Get low surrogate */ + if (rc != 2) break; /* EOF? */ wc = (FF_STRF_ENCODE == 1) ? ld_word(s) : s[0] << 8 | s[1]; - if (!IsSurrogateL(wc)) continue; - dc = ((dc & 0x3FF) + 0x40) << 10 | (wc & 0x3FF); + if (!IsSurrogateL(wc)) continue; /* Broken surrogate pair? */ + dc = ((dc & 0x3FF) + 0x40) << 10 | (wc & 0x3FF); /* Merge surrogate pair */ } #else /* Read a character in UTF-8 */ - f_read(fp, s, 1, &rc); - if (rc != 1) break; + f_read(fp, s, 1, &rc); /* Get a code unit */ + if (rc != 1) break; /* EOF? */ dc = s[0]; - if (dc >= 0x80) { /* Multi-byte character? */ + if (dc >= 0x80) { /* Multi-byte sequence? */ ct = 0; - if ((dc & 0xE0) == 0xC0) { dc &= 0x1F; ct = 1; } /* 2-byte? */ - if ((dc & 0xF0) == 0xE0) { dc &= 0x0F; ct = 2; } /* 3-byte? */ - if ((dc & 0xF8) == 0xF0) { dc &= 0x07; ct = 3; } /* 4-byte? */ + if ((dc & 0xE0) == 0xC0) { dc &= 0x1F; ct = 1; } /* 2-byte sequence? */ + if ((dc & 0xF0) == 0xE0) { dc &= 0x0F; ct = 2; } /* 3-byte sequence? */ + if ((dc & 0xF8) == 0xF0) { dc &= 0x07; ct = 3; } /* 4-byte sequence? */ if (ct == 0) continue; f_read(fp, s, ct, &rc); /* Get trailing bytes */ if (rc != ct) break; rc = 0; - do { /* Merge trailing bytes */ + do { /* Merge the byte sequence */ if ((s[rc] & 0xC0) != 0x80) break; dc = dc << 6 | (s[rc] & 0x3F); } while (++rc < ct); if (rc != ct || dc < 0x80 || IsSurrogate(dc) || dc >= 0x110000) continue; /* Wrong encoding? */ } #endif + /* A code point is avaialble in dc to be output */ + if (FF_USE_STRFUNC == 2 && dc == '\r') continue; /* Strip \r off if needed */ #if FF_LFN_UNICODE == 1 || FF_LFN_UNICODE == 3 /* Output it in UTF-16/32 encoding */ if (FF_LFN_UNICODE == 1 && dc >= 0x10000) { /* Out of BMP at UTF-16? */ @@ -6152,22 +6443,22 @@ TCHAR* f_gets ( *p++ = (TCHAR)dc; nc++; if (dc == '\n') break; /* End of line? */ #elif FF_LFN_UNICODE == 2 /* Output it in UTF-8 encoding */ - if (dc < 0x80) { /* 1-byte */ + if (dc < 0x80) { /* Single byte? */ *p++ = (TCHAR)dc; nc++; if (dc == '\n') break; /* End of line? */ } else { - if (dc < 0x800) { /* 2-byte */ + if (dc < 0x800) { /* 2-byte sequence? */ *p++ = (TCHAR)(0xC0 | (dc >> 6 & 0x1F)); *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); nc += 2; } else { - if (dc < 0x10000) { /* 3-byte */ + if (dc < 0x10000) { /* 3-byte sequence? */ *p++ = (TCHAR)(0xE0 | (dc >> 12 & 0x0F)); *p++ = (TCHAR)(0x80 | (dc >> 6 & 0x3F)); *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); nc += 3; - } else { /* 4-byte */ + } else { /* 4-byte sequence? */ *p++ = (TCHAR)(0xF0 | (dc >> 18 & 0x07)); *p++ = (TCHAR)(0x80 | (dc >> 12 & 0x3F)); *p++ = (TCHAR)(0x80 | (dc >> 6 & 0x3F)); @@ -6179,11 +6470,11 @@ TCHAR* f_gets ( #endif } -#else /* Byte-by-byte without any conversion (ANSI/OEM API) */ +#else /* Byte-by-byte read without any conversion (ANSI/OEM API) */ len -= 1; /* Make a room for the terminator */ while (nc < len) { - f_read(fp, s, 1, &rc); - if (rc != 1) break; + f_read(fp, s, 1, &rc); /* Get a byte */ + if (rc != 1) break; /* EOF? */ dc = s[0]; if (FF_USE_STRFUNC == 2 && dc == '\r') continue; *p++ = (TCHAR)dc; nc++; @@ -6201,10 +6492,12 @@ TCHAR* f_gets ( #if !FF_FS_READONLY #include /*-----------------------------------------------------------------------*/ -/* Put a Character to the File */ +/* Put a Character to the File (sub-functions) */ /*-----------------------------------------------------------------------*/ -typedef struct { /* Putchar output buffer and work area */ +/* Putchar output buffer and work area */ + +typedef struct { FIL *fp; /* Ptr to the writing file */ int idx, nchr; /* Write index of buf[] (-1:error), number of encoding units written */ #if FF_USE_LFN && FF_LFN_UNICODE == 1 @@ -6217,10 +6510,9 @@ typedef struct { /* Putchar output buffer and work area */ } putbuff; -static void putc_bfd ( /* Buffered write with code conversion */ - putbuff* pb, - TCHAR c -) +/* Buffered write with code conversion */ + +static void putc_bfd (putbuff* pb, TCHAR c) { UINT n; int i, nc; @@ -6242,24 +6534,24 @@ static void putc_bfd ( /* Buffered write with code conversion */ #if FF_USE_LFN && FF_LFN_UNICODE #if FF_LFN_UNICODE == 1 /* UTF-16 input */ - if (IsSurrogateH(c)) { - pb->hs = c; return; + if (IsSurrogateH(c)) { /* High surrogate? */ + pb->hs = c; return; /* Save it for next */ } hs = pb->hs; pb->hs = 0; - if (hs != 0) { - if (!IsSurrogateL(c)) hs = 0; + if (hs != 0) { /* There is a leading high surrogate */ + if (!IsSurrogateL(c)) hs = 0; /* Discard high surrogate if not a surrogate pair */ } else { - if (IsSurrogateL(c)) return; + if (IsSurrogateL(c)) return; /* Discard stray low surrogate */ } wc = c; #elif FF_LFN_UNICODE == 2 /* UTF-8 input */ for (;;) { if (pb->ct == 0) { /* Out of multi-byte sequence? */ pb->bs[pb->wi = 0] = (BYTE)c; /* Save 1st byte */ - if ((BYTE)c < 0x80) break; /* 1-byte? */ - if (((BYTE)c & 0xE0) == 0xC0) pb->ct = 1; /* 2-byte? */ - if (((BYTE)c & 0xF0) == 0xE0) pb->ct = 2; /* 3-byte? */ - if (((BYTE)c & 0xF1) == 0xF0) pb->ct = 3; /* 4-byte? */ + if ((BYTE)c < 0x80) break; /* Single byte? */ + if (((BYTE)c & 0xE0) == 0xC0) pb->ct = 1; /* 2-byte sequence? */ + if (((BYTE)c & 0xF0) == 0xE0) pb->ct = 2; /* 3-byte sequence? */ + if (((BYTE)c & 0xF1) == 0xF0) pb->ct = 3; /* 4-byte sequence? */ return; } else { /* In the multi-byte sequence */ if (((BYTE)c & 0xC0) != 0x80) { /* Broken sequence? */ @@ -6272,12 +6564,12 @@ static void putc_bfd ( /* Buffered write with code conversion */ } tp = (TCHAR*)pb->bs; dc = tchar2uni(&tp); /* UTF-8 ==> UTF-16 */ - if (dc == 0xFFFFFFFF) return; + if (dc == 0xFFFFFFFF) return; /* Wrong code? */ wc = (WCHAR)dc; hs = (WCHAR)(dc >> 16); #elif FF_LFN_UNICODE == 3 /* UTF-32 input */ - if (IsSurrogate(c) || c >= 0x110000) return; - if (c >= 0x10000) { + if (IsSurrogate(c) || c >= 0x110000) return; /* Discard invalid code */ + if (c >= 0x10000) { /* Out of BMP? */ hs = (WCHAR)(0xD800 | ((c >> 10) - 0x40)); /* Make high surrogate */ wc = 0xDC00 | (c & 0x3FF); /* Make low surrogate */ } else { @@ -6285,25 +6577,26 @@ static void putc_bfd ( /* Buffered write with code conversion */ wc = (WCHAR)c; } #endif + /* A code point in UTF-16 is available in hs and wc */ -#if FF_STRF_ENCODE == 1 /* Write a character in UTF-16LE */ - if (hs != 0) { +#if FF_STRF_ENCODE == 1 /* Write a code point in UTF-16LE */ + if (hs != 0) { /* Surrogate pair? */ st_word(&pb->buf[i], hs); i += 2; nc++; } st_word(&pb->buf[i], wc); i += 2; -#elif FF_STRF_ENCODE == 2 /* Write a character in UTF-16BE */ - if (hs != 0) { +#elif FF_STRF_ENCODE == 2 /* Write a code point in UTF-16BE */ + if (hs != 0) { /* Surrogate pair? */ pb->buf[i++] = (BYTE)(hs >> 8); pb->buf[i++] = (BYTE)hs; nc++; } pb->buf[i++] = (BYTE)(wc >> 8); pb->buf[i++] = (BYTE)wc; -#elif FF_STRF_ENCODE == 3 /* Write it in UTF-8 */ - if (hs != 0) { /* 4-byte */ +#elif FF_STRF_ENCODE == 3 /* Write a code point in UTF-8 */ + if (hs != 0) { /* 4-byte sequence? */ nc += 3; hs = (hs & 0x3FF) + 0x40; pb->buf[i++] = (BYTE)(0xF0 | hs >> 8); @@ -6311,13 +6604,13 @@ static void putc_bfd ( /* Buffered write with code conversion */ pb->buf[i++] = (BYTE)(0x80 | (hs & 3) << 4 | (wc >> 6 & 0x0F)); pb->buf[i++] = (BYTE)(0x80 | (wc & 0x3F)); } else { - if (wc < 0x80) { /* 1-byte */ + if (wc < 0x80) { /* Single byte? */ pb->buf[i++] = (BYTE)wc; } else { - if (wc < 0x800) { /* 2-byte */ + if (wc < 0x800) { /* 2-byte sequence? */ nc += 1; pb->buf[i++] = (BYTE)(0xC0 | wc >> 6); - } else { /* 3-byte */ + } else { /* 3-byte sequence */ nc += 2; pb->buf[i++] = (BYTE)(0xE0 | wc >> 12); pb->buf[i++] = (BYTE)(0x80 | (wc >> 6 & 0x3F)); @@ -6325,7 +6618,7 @@ static void putc_bfd ( /* Buffered write with code conversion */ pb->buf[i++] = (BYTE)(0x80 | (wc & 0x3F)); } } -#else /* Write it in ANSI/OEM */ +#else /* Write a code point in ANSI/OEM */ if (hs != 0) return; wc = ff_uni2oem(wc, CODEPAGE); /* UTF-16 ==> ANSI/OEM */ if (wc == 0) return; @@ -6335,7 +6628,7 @@ static void putc_bfd ( /* Buffered write with code conversion */ pb->buf[i++] = (BYTE)wc; #endif -#else /* ANSI/OEM input (without re-encode) */ +#else /* ANSI/OEM input (without re-encoding) */ pb->buf[i++] = (BYTE)c; #endif @@ -6348,9 +6641,9 @@ static void putc_bfd ( /* Buffered write with code conversion */ } -static int putc_flush ( /* Flush left characters in the buffer */ - putbuff* pb -) +/* Flush remaining characters in the buffer */ + +static int putc_flush (putbuff* pb) { UINT nw; @@ -6361,10 +6654,9 @@ static int putc_flush ( /* Flush left characters in the buffer */ } -static void putc_init ( /* Initialize write buffer */ - putbuff* pb, - FIL* fp -) +/* Initialize write buffer */ + +static void putc_init (putbuff* pb, FIL* fp) { mem_set(pb, 0, sizeof (putbuff)); pb->fp = fp; diff --git a/thirdparty/fatfs/ff.h b/thirdparty/fatfs/ff.h index e5f14a8..706ec35 100644 --- a/thirdparty/fatfs/ff.h +++ b/thirdparty/fatfs/ff.h @@ -1,8 +1,8 @@ /*----------------------------------------------------------------------------/ -/ FatFs - Generic FAT Filesystem module R0.13c / +/ FatFs - Generic FAT Filesystem module R0.14 / /-----------------------------------------------------------------------------/ / -/ Copyright (C) 2018, ChaN, all right reserved. +/ Copyright (C) 2019, ChaN, all right reserved. / / FatFs module is an open source software. Redistribution and use of FatFs in / source and binary forms, with or without modification, are permitted provided @@ -20,7 +20,7 @@ #ifndef FF_DEFINED -#define FF_DEFINED 86604 /* Revision ID */ +#define FF_DEFINED 86606 /* Revision ID */ #ifdef __cplusplus extern "C" { @@ -45,16 +45,16 @@ typedef unsigned __int64 QWORD; typedef unsigned int UINT; /* int must be 16-bit or 32-bit */ typedef unsigned char BYTE; /* char must be 8-bit */ typedef uint16_t WORD; /* 16-bit unsigned integer */ -typedef uint16_t WCHAR; /* 16-bit unsigned integer */ typedef uint32_t DWORD; /* 32-bit unsigned integer */ typedef uint64_t QWORD; /* 64-bit unsigned integer */ +typedef WORD WCHAR; /* UTF-16 character type */ #else /* Earlier than C99 */ #define FF_INTDEF 1 typedef unsigned int UINT; /* int must be 16-bit or 32-bit */ typedef unsigned char BYTE; /* char must be 8-bit */ typedef unsigned short WORD; /* 16-bit unsigned integer */ -typedef unsigned short WCHAR; /* 16-bit unsigned integer */ typedef unsigned long DWORD; /* 32-bit unsigned integer */ +typedef WORD WCHAR; /* UTF-16 character type */ #endif @@ -65,7 +65,7 @@ typedef struct { BYTE pd; /* Physical drive number */ BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */ } PARTITION; -extern PARTITION VolToPart[]; /* Volume - Partition resolution table */ +extern PARTITION VolToPart[]; /* Volume - Partition mapping table */ #endif #if FF_STR_VOLUME_ID @@ -105,15 +105,24 @@ typedef char TCHAR; -/* Type of file size variables */ +/* Type of file size and LBA variables */ #if FF_FS_EXFAT #if FF_INTDEF != 2 #error exFAT feature wants C99 or later #endif typedef QWORD FSIZE_t; +#if FF_LBA64 +typedef QWORD LBA_t; #else +typedef DWORD LBA_t; +#endif +#else +#if FF_LBA64 +#error exFAT needs to be enabled when enable 64-bit LBA +#endif typedef DWORD FSIZE_t; +typedef DWORD LBA_t; #endif @@ -155,14 +164,14 @@ typedef struct { #endif DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */ DWORD fsize; /* Size of an FAT [sectors] */ - DWORD volbase; /* Volume base sector */ - DWORD fatbase; /* FAT base sector */ - DWORD dirbase; /* Root directory base sector/cluster */ - DWORD database; /* Data base sector */ + LBA_t volbase; /* Volume base sector */ + LBA_t fatbase; /* FAT base sector */ + LBA_t dirbase; /* Root directory base sector/cluster */ + LBA_t database; /* Data base sector */ #if FF_FS_EXFAT - DWORD bitbase; /* Allocation bitmap base sector */ + LBA_t bitbase; /* Allocation bitmap base sector */ #endif - DWORD winsect; /* Current sector appearing in the win[] */ + LBA_t winsect; /* Current sector appearing in the win[] */ BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */ } FATFS; @@ -199,9 +208,9 @@ typedef struct { BYTE err; /* Abort flag (error code) */ FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */ DWORD clust; /* Current cluster of fpter (invalid when fptr is 0) */ - DWORD sect; /* Sector number appearing in buf[] (0:invalid) */ + LBA_t sect; /* Sector number appearing in buf[] (0:invalid) */ #if !FF_FS_READONLY - DWORD dir_sect; /* Sector number containing the directory entry (not used at exFAT) */ + LBA_t dir_sect; /* Sector number containing the directory entry (not used at exFAT) */ BYTE* dir_ptr; /* Pointer to the directory entry in the win[] (not used at exFAT) */ #endif #if FF_USE_FASTSEEK @@ -220,7 +229,7 @@ typedef struct { FFOBJID obj; /* Object identifier */ DWORD dptr; /* Current read/write offset */ DWORD clust; /* Current cluster */ - DWORD sect; /* Current sector (0:Read operation has terminated) */ + LBA_t sect; /* Current sector (0:Read operation has terminated) */ BYTE* dir; /* Pointer to the directory item in the win[] */ BYTE fn[12]; /* SFN (in/out) {body[8],ext[3],status[1]} */ #if FF_USE_LFN @@ -250,6 +259,18 @@ typedef struct { +/* Format parameter structure (MKFS_PARM) */ + +typedef struct { + BYTE fmt; /* Format option (FM_FAT, FM_FAT32, FM_EXFAT and FM_SFD) */ + BYTE n_fat; /* Number of FATs */ + UINT align; /* Data area alignment (sector) */ + UINT n_root; /* Number of root directory entries */ + DWORD au_size; /* Cluster size (byte) */ +} MKFS_PARM; + + + /* File function return code (FRESULT) */ typedef enum { @@ -305,10 +326,10 @@ FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get numbe FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */ FRESULT f_setlabel (const TCHAR* label); /* Set volume label */ FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */ -FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */ +FRESULT f_expand (FIL* fp, FSIZE_t fsz, BYTE opt); /* Allocate a contiguous block to the file */ FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */ -FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */ -FRESULT f_fdisk (BYTE pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */ +FRESULT f_mkfs (const TCHAR* path, const MKFS_PARM* opt, void* work, UINT len); /* Create a FAT volume */ +FRESULT f_fdisk (BYTE pdrv, const LBA_t ptbl[], void* work); /* Divide a physical drive into some partitions */ FRESULT f_setcp (WORD cp); /* Set current code page */ int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */ int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */ diff --git a/thirdparty/fatfs/ffconf.h b/thirdparty/fatfs/ffconf.h index dc04940..cbfc685 100644 --- a/thirdparty/fatfs/ffconf.h +++ b/thirdparty/fatfs/ffconf.h @@ -2,7 +2,7 @@ / FatFs Functional Configurations /---------------------------------------------------------------------------*/ -#define FFCONF_DEF 86604 /* Revision ID */ +#define FFCONF_DEF 86606 /* Revision ID */ /*---------------------------------------------------------------------------/ / Function Configurations @@ -102,7 +102,7 @@ /* The FF_USE_LFN switches the support for LFN (long file name). / / 0: Disable LFN. FF_MAX_LFN has no effect. -/ 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe. +/ 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe. / 2: Enable LFN with dynamic working buffer on the STACK. / 3: Enable LFN with dynamic working buffer on the HEAP. / @@ -110,11 +110,11 @@ / requiers certain internal working buffer occupies (FF_MAX_LFN + 1) * 2 bytes and / additional (FF_MAX_LFN + 44) / 15 * 32 bytes when exFAT is enabled. / The FF_MAX_LFN defines size of the working buffer in UTF-16 code unit and it can -/ be in range of 12 to 255. It is recommended to be set 255 to fully support LFN +/ be in range of 12 to 255. It is recommended to be set it 255 to fully support LFN / specification. / When use stack for the working buffer, take care on stack overflow. When use heap / memory for the working buffer, memory management functions, ff_memalloc() and -/ ff_memfree() in ffsystem.c, need to be added to the project. */ +/ ff_memfree() exemplified in ffsystem.c, need to be added to the project. */ #define FF_LFN_UNICODE 2 @@ -200,30 +200,28 @@ / GET_SECTOR_SIZE command. */ +#define FF_LBA64 0 +/* This option switches support for 64-bit LBA. (0:Disable or 1:Enable) +/ To enable the 64-bit LBA, also exFAT needs to be enabled. (FF_FS_EXFAT == 1) */ + + +#define FF_MIN_GPT 0x100000000 +/* Minimum number of sectors to switch GPT format to create partition in f_mkfs and +/ f_fdisk function. 0x100000000 max. This option has no effect when FF_LBA64 == 0. */ + + #define FF_USE_TRIM 0 /* This option switches support for ATA-TRIM. (0:Disable or 1:Enable) / To enable Trim function, also CTRL_TRIM command should be implemented to the / disk_ioctl() function. */ -#define FF_FS_NOFSINFO 0 -/* If you need to know correct free space on the FAT32 volume, set bit 0 of this -/ option, and f_getfree() function at first time after volume mount will force -/ a full FAT scan. Bit 1 controls the use of last allocated cluster number. -/ -/ bit0=0: Use free cluster count in the FSINFO if available. -/ bit0=1: Do not trust free cluster count in the FSINFO. -/ bit1=0: Use last allocated cluster number in the FSINFO if available. -/ bit1=1: Do not trust last allocated cluster number in the FSINFO. -*/ - - /*---------------------------------------------------------------------------/ / System Configurations /---------------------------------------------------------------------------*/ -#define FF_FS_TINY 1 +#define FF_FS_TINY 0 /* This option switches tiny buffer configuration. (0:Normal or 1:Tiny) / At the tiny configuration, size of file object (FIL) is shrinked FF_MAX_SS bytes. / Instead of private sector buffer eliminated from the file object, common sector @@ -237,8 +235,8 @@ #define FF_FS_NORTC 1 -#define FF_NORTC_MON 1 -#define FF_NORTC_MDAY 1 +#define FF_NORTC_MON 11 +#define FF_NORTC_MDAY 23 #define FF_NORTC_YEAR 2020 /* The option FF_FS_NORTC switches timestamp functiton. If the system does not have / any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable @@ -247,7 +245,19 @@ / To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be / added to the project to read current time form real-time clock. FF_NORTC_MON, / FF_NORTC_MDAY and FF_NORTC_YEAR have no effect. -/ These options have no effect at read-only configuration (FF_FS_READONLY = 1). */ +/ These options have no effect in read-only configuration (FF_FS_READONLY = 1). */ + + +#define FF_FS_NOFSINFO 0 +/* If you need to know correct free space on the FAT32 volume, set bit 0 of this +/ option, and f_getfree() function at first time after volume mount will force +/ a full FAT scan. Bit 1 controls the use of last allocated cluster number. +/ +/ bit0=0: Use free cluster count in the FSINFO if available. +/ bit0=1: Do not trust free cluster count in the FSINFO. +/ bit1=0: Use last allocated cluster number in the FSINFO if available. +/ bit1=1: Do not trust last allocated cluster number in the FSINFO. +*/ #define FF_FS_LOCK 0 diff --git a/thirdparty/fatfs/ffunicode.c b/thirdparty/fatfs/ffunicode.c index 3705770..784a10e 100644 --- a/thirdparty/fatfs/ffunicode.c +++ b/thirdparty/fatfs/ffunicode.c @@ -1,5 +1,5 @@ /*------------------------------------------------------------------------*/ -/* Unicode handling functions for FatFs R0.13c */ +/* Unicode handling functions for FatFs R0.13+ */ /*------------------------------------------------------------------------*/ /* This module will occupy a huge memory in the .const section when the / / FatFs is configured for LFN with DBCS. If the system has any Unicode / @@ -7,7 +7,7 @@ / that function to avoid silly memory consumption. / /-------------------------------------------------------------------------*/ /* -/ Copyright (C) 2018, ChaN, all right reserved. +/ Copyright (C) 2014, ChaN, all right reserved. / / FatFs module is an open source software. Redistribution and use of FatFs in / source and binary forms, with or without modification, are permitted provided @@ -25,11 +25,7 @@ #include "ff.h" -#if FF_USE_LFN /* This module will be blanked at non-LFN configuration */ - -#if FF_DEFINED != 86604 /* Revision ID */ -#error Wrong include file (ff.h). -#endif +#if FF_USE_LFN /* This module will be blanked if non-LFN configuration */ #define MERGE2(a, b) a ## b #define CVTBL(tbl, cp) MERGE2(tbl, cp) @@ -15245,7 +15241,7 @@ WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */ return c; } -WCHAR ff_oem2uni ( /* Returns Unicode character, zero on error */ +WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */ WCHAR oem, /* OEM code to be converted */ WORD cp /* Code page for the conversion */ ) @@ -15312,7 +15308,7 @@ WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */ } -WCHAR ff_oem2uni ( /* Returns Unicode character, zero on error */ +WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */ WCHAR oem, /* OEM code to be converted */ WORD cp /* Code page for the conversion */ ) @@ -15411,7 +15407,7 @@ WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */ } -WCHAR ff_oem2uni ( /* Returns Unicode character, zero on error */ +WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */ WCHAR oem, /* OEM code to be converted (DBC if >=0x100) */ WORD cp /* Code page for the conversion */ )