diff --git a/components/dfs/dfs_v1/filesystems/elmfat/00history.txt b/components/dfs/dfs_v1/filesystems/elmfat/00history.txt index 8a0169b1ff1..11982e0410d 100644 --- a/components/dfs/dfs_v1/filesystems/elmfat/00history.txt +++ b/components/dfs/dfs_v1/filesystems/elmfat/00history.txt @@ -357,3 +357,33 @@ R0.14b (April 17, 2021) Fixed some compiler warnings. + +R0.15 (November 6, 2022) + Changed user provided synchronization functions in order to completely eliminate the platform dependency from FatFs code. + FF_SYNC_t is removed from the configuration options. + Fixed a potential error in f_mount when FF_FS_REENTRANT. + Fixed file lock control FF_FS_LOCK is not mutal excluded when FF_FS_REENTRANT && FF_VOLUMES > 1 is true. + Fixed f_mkfs() creates broken exFAT volume when the size of volume is >= 2^32 sectors. + Fixed string functions cannot write the unicode characters not in BMP when FF_LFN_UNICODE == 2 (UTF-8). + Fixed a compatibility issue in identification of GPT header. + + + +R0.15a (November 22, 2024) + Fixed a complie error when FF_FS_LOCK != 0. + Fixed a potential issue when work FatFs concurrency with FF_FS_REENTRANT, FF_VOLUMES >= 2 and FF_FS_LOCK > 0. + Made f_setlabel() accept a volume label in Unix style volume ID when FF_STR_VOLUME_ID == 2. + Made FatFs update PercInUse field in exFAT VBR. (A preceding f_getfree() is needed for the accuracy) + + + +R0.15b (June 21, 2025) + Added support for timestamp of created time. (FF_FS_CRTIME) + Fixed FatFs fails to load the FsInfo in FAT32 volumes and the f_getfree always be forced a full FAT scan which takes a long time. (appeared at R0.15a) + + + +R0.16 (July 22, 2025) + Removed a long-pending limitation that f_getcwd and double-dot .. in the path name did not work on the exFAT volume. + Fixed f_readdir cannot detect end of directory and it leads the application process into infinite loop. (appeared at R0.15b) + Fixed dot names with terminating separator or duplicated separator are rejected when LFN is not enabled. diff --git a/components/dfs/dfs_v1/filesystems/elmfat/00readme.txt b/components/dfs/dfs_v1/filesystems/elmfat/00readme.txt index 4960997b30d..2dae010cc7a 100644 --- a/components/dfs/dfs_v1/filesystems/elmfat/00readme.txt +++ b/components/dfs/dfs_v1/filesystems/elmfat/00readme.txt @@ -1,4 +1,4 @@ -FatFs Module Source Files R0.14b +FatFs Module Source Files R0.16 FILES diff --git a/components/dfs/dfs_v1/filesystems/elmfat/dfs_elm.c b/components/dfs/dfs_v1/filesystems/elmfat/dfs_elm.c index 43c72c66750..77793e3af11 100644 --- a/components/dfs/dfs_v1/filesystems/elmfat/dfs_elm.c +++ b/components/dfs/dfs_v1/filesystems/elmfat/dfs_elm.c @@ -999,41 +999,41 @@ DWORD get_fattime(void) } #if FF_FS_REENTRANT -int ff_cre_syncobj(BYTE drv, FF_SYNC_t *m) +static rt_mutex_t Mutex[FF_VOLUMES + 1]; + +int ff_mutex_create (int vol) { char name[8]; rt_mutex_t mutex; - rt_snprintf(name, sizeof(name), "fat%d", drv); + rt_snprintf(name, sizeof(name), "fat%d", vol); mutex = rt_mutex_create(name, RT_IPC_FLAG_PRIO); if (mutex != RT_NULL) { - *m = mutex; + Mutex[vol] = mutex; return RT_TRUE; } return RT_FALSE; } -int ff_del_syncobj(FF_SYNC_t m) +void ff_mutex_delete (int vol) { - if (m != RT_NULL) - rt_mutex_delete(m); - - return RT_TRUE; + if (Mutex[vol] != RT_NULL) + rt_mutex_delete(Mutex[vol]); } -int ff_req_grant(FF_SYNC_t m) +int ff_mutex_take (int vol) { - if (rt_mutex_take(m, FF_FS_TIMEOUT) == RT_EOK) + if (rt_mutex_take(Mutex[vol], FF_FS_TIMEOUT) == RT_EOK) return RT_TRUE; return RT_FALSE; } -void ff_rel_grant(FF_SYNC_t m) +void ff_mutex_give (int vol) { - rt_mutex_release(m); + rt_mutex_release(Mutex[vol]); } #endif diff --git a/components/dfs/dfs_v1/filesystems/elmfat/diskio.h b/components/dfs/dfs_v1/filesystems/elmfat/diskio.h index e4ead783803..195f4325475 100644 --- a/components/dfs/dfs_v1/filesystems/elmfat/diskio.h +++ b/components/dfs/dfs_v1/filesystems/elmfat/diskio.h @@ -1,5 +1,5 @@ /*-----------------------------------------------------------------------/ -/ Low level disk interface modlue include file (C)ChaN, 2019 / +/ Low level disk interface modlue include file (C)ChaN, 2025 / /-----------------------------------------------------------------------*/ #ifndef _DISKIO_DEFINED @@ -55,7 +55,7 @@ DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff); #define CTRL_EJECT 7 /* Eject media */ #define CTRL_FORMAT 8 /* Create physical format on the media */ -/* MMC/SDC specific ioctl command */ +/* MMC/SDC specific ioctl command (Not used by FatFs) */ #define MMC_GET_TYPE 10 /* Get card type */ #define MMC_GET_CSD 11 /* Get CSD */ #define MMC_GET_CID 12 /* Get CID */ @@ -65,7 +65,7 @@ DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff); #define ISDIO_WRITE 56 /* Write data to SD iSDIO register */ #define ISDIO_MRITE 57 /* Masked write data to SD iSDIO register */ -/* ATA/CF specific ioctl command */ +/* ATA/CF specific ioctl command (Not used by FatFs) */ #define ATA_GET_REV 20 /* Get F/W revision */ #define ATA_GET_MODEL 21 /* Get model name */ #define ATA_GET_SN 22 /* Get serial number */ diff --git a/components/dfs/dfs_v1/filesystems/elmfat/ff.c b/components/dfs/dfs_v1/filesystems/elmfat/ff.c index 80e194d6e9a..c4df9864346 100644 --- a/components/dfs/dfs_v1/filesystems/elmfat/ff.c +++ b/components/dfs/dfs_v1/filesystems/elmfat/ff.c @@ -1,8 +1,8 @@ /*----------------------------------------------------------------------------/ -/ FatFs - Generic FAT Filesystem Module R0.14b / +/ FatFs - Generic FAT Filesystem Module R0.16 / /-----------------------------------------------------------------------------/ / -/ Copyright (C) 2021, ChaN, all right reserved. +/ Copyright (C) 2025, 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,9 +20,8 @@ #include -#include "ff.h" /* Declarations of FatFs API */ -#include "diskio.h" /* Declarations of device I/O functions */ - +#include "ff.h" /* Basic definitions and declarations of API */ +#include "diskio.h" /* Declarations of MAI */ /*-------------------------------------------------------------------------- @@ -30,17 +29,17 @@ ---------------------------------------------------------------------------*/ -#if FF_DEFINED != 86631 /* Revision ID */ +#if FF_DEFINED != 80386 /* Revision ID */ #error Wrong include file (ff.h). #endif /* Limits and boundaries */ -#define MAX_DIR 0x200000 /* Max size of FAT directory */ -#define MAX_DIR_EX 0x10000000 /* Max size of exFAT directory */ +#define MAX_DIR 0x200000 /* Max size of FAT directory (byte) */ +#define MAX_DIR_EX 0x10000000 /* Max size of exFAT directory (byte) */ #define MAX_FAT12 0xFF5 /* Max FAT12 clusters (differs from specs, but right for real DOS/Windows behavior) */ #define MAX_FAT16 0xFFF5 /* Max FAT16 clusters (differs from specs, but right for real DOS/Windows behavior) */ -#define MAX_FAT32 0x0FFFFFF5 /* Max FAT32 clusters (not specified, practical limit) */ +#define MAX_FAT32 0x0FFFFFF5 /* Max FAT32 clusters (not defined in specs, practical limit) */ #define MAX_EXFAT 0x7FFFFFFD /* Max exFAT clusters (differs from specs, implementation limit) */ @@ -89,7 +88,7 @@ #define ET_FILENAME 0xC1 /* Name extension */ -/* FatFs refers the FAT structure as simple byte array instead of structure member +/* FatFs refers the FAT structures as simple byte array instead of structure member / because the C structure is not binary compatible between different platforms */ #define BS_JmpBoot 0 /* x86 jump instruction (3-byte) */ @@ -113,7 +112,7 @@ #define BS_VolLab 43 /* Volume label string (8-byte) */ #define BS_FilSysType 54 /* Filesystem type string (8-byte) */ #define BS_BootCode 62 /* Boot code (448-byte) */ -#define BS_55AA 510 /* Signature word (WORD) */ +#define BS_55AA 510 /* Boot signature (WORD, for VBR and MBR) */ #define BPB_FATSz32 36 /* FAT32: FAT size [sector] (DWORD) */ #define BPB_ExtFlags32 40 /* FAT32: Extended flags (WORD) */ @@ -139,18 +138,18 @@ #define BPB_RootClusEx 96 /* exFAT: Root directory start cluster (DWORD) */ #define BPB_VolIDEx 100 /* exFAT: Volume serial number (DWORD) */ #define BPB_FSVerEx 104 /* exFAT: Filesystem version (WORD) */ -#define BPB_VolFlagEx 106 /* exFAT: Volume flags (WORD) */ +#define BPB_VolFlagEx 106 /* exFAT: Volume flags (WORD, out of check sum calculation) */ #define BPB_BytsPerSecEx 108 /* exFAT: Log2 of sector size in unit of byte (BYTE) */ #define BPB_SecPerClusEx 109 /* exFAT: Log2 of cluster size in unit of sector (BYTE) */ #define BPB_NumFATsEx 110 /* exFAT: Number of FATs (BYTE) */ #define BPB_DrvNumEx 111 /* exFAT: Physical drive number for int13h (BYTE) */ -#define BPB_PercInUseEx 112 /* exFAT: Percent in use (BYTE) */ +#define BPB_PercInUseEx 112 /* exFAT: Percent in use (BYTE, out of check sum calculation) */ #define BPB_RsvdEx 113 /* exFAT: Reserved (7-byte) */ #define BS_BootCodeEx 120 /* exFAT: Boot code (390-byte) */ #define DIR_Name 0 /* Short file name (11-byte) */ #define DIR_Attr 11 /* Attribute (BYTE) */ -#define DIR_NTres 12 /* Lower case flag (BYTE) */ +#define DIR_NTres 12 /* Low case flags of SFN (BYTE) */ #define DIR_CrtTime10 13 /* Created time sub-second (BYTE) */ #define DIR_CrtTime 14 /* Created time (DWORD) */ #define DIR_LstAccDate 18 /* Last accessed date (WORD) */ @@ -194,40 +193,41 @@ #define FSI_StrucSig 484 /* FAT32 FSI: Structure signature (DWORD) */ #define FSI_Free_Count 488 /* FAT32 FSI: Number of free clusters (DWORD) */ #define FSI_Nxt_Free 492 /* FAT32 FSI: Last allocated cluster (DWORD) */ +#define FSI_TrailSig 508 /* FAT32 FSI: Trailing signature (DWORD) */ #define MBR_Table 446 /* MBR: Offset of partition table in the MBR */ #define SZ_PTE 16 /* MBR: Size of a partition table entry */ #define PTE_Boot 0 /* MBR PTE: Boot indicator */ -#define PTE_StHead 1 /* MBR PTE: Start head */ -#define PTE_StSec 2 /* MBR PTE: Start sector */ -#define PTE_StCyl 3 /* MBR PTE: Start cylinder */ +#define PTE_StHead 1 /* MBR PTE: Start head in CHS */ +#define PTE_StSec 2 /* MBR PTE: Start sector in CHS */ +#define PTE_StCyl 3 /* MBR PTE: Start cylinder in CHS */ #define PTE_System 4 /* MBR PTE: System ID */ -#define PTE_EdHead 5 /* MBR PTE: End head */ -#define PTE_EdSec 6 /* MBR PTE: End sector */ -#define PTE_EdCyl 7 /* MBR PTE: End cylinder */ +#define PTE_EdHead 5 /* MBR PTE: End head in CHS */ +#define PTE_EdSec 6 /* MBR PTE: End sector in CHS */ +#define PTE_EdCyl 7 /* MBR PTE: End cylinder in CHS */ #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 GPTH_Sign 0 /* GPT HDR: Signature (8-byte) */ +#define GPTH_Rev 8 /* GPT HDR: Revision (DWORD) */ +#define GPTH_Size 12 /* GPT HDR: Header size (DWORD) */ +#define GPTH_Bcc 16 /* GPT HDR: Header BCC (DWORD) */ +#define GPTH_CurLba 24 /* GPT HDR: This header LBA (QWORD) */ +#define GPTH_BakLba 32 /* GPT HDR: Another header LBA (QWORD) */ +#define GPTH_FstLba 40 /* GPT HDR: First LBA for partition data (QWORD) */ +#define GPTH_LstLba 48 /* GPT HDR: Last LBA for partition data (QWORD) */ +#define GPTH_DskGuid 56 /* GPT HDR: Disk GUID (16-byte) */ +#define GPTH_PtOfs 72 /* GPT HDR: Partition table LBA (QWORD) */ +#define GPTH_PtNum 80 /* GPT HDR: Number of table entries (DWORD) */ +#define GPTH_PteSize 84 /* GPT HDR: Size of table entry (DWORD) */ +#define GPTH_PtBcc 88 /* GPT HDR: Partition table BCC (DWORD) */ +#define SZ_GPTE 128 /* GPT PTE: Size of a GPT 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 */ +#define GPTE_FstLba 32 /* GPT PTE: First LBA of partition (QWORD) */ +#define GPTE_LstLba 40 /* GPT PTE: Last LBA of partition (QWORD) */ +#define GPTE_Flags 48 /* GPT PTE: Partition flags (QWORD) */ +#define GPTE_Name 56 /* GPT PTE: Partition name */ /* Post process on fatal error in the file operations */ @@ -239,16 +239,16 @@ #if FF_USE_LFN == 1 #error Static LFN work area cannot be used in thread-safe configuration #endif -#define LEAVE_FF(fs, res) { unlock_fs(fs, res); return res; } +#define LEAVE_FF(fs, res) { unlock_volume(fs, res); return res; } #else #define LEAVE_FF(fs, res) return res #endif -/* Definitions of logical drive - physical location conversion */ +/* Definitions of logical drive to 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 number (0:auto search, 1..:forced partition number) */ +#define LD2PD(vol) VolToPart[vol].pd /* Get physical drive number from the mapping table */ +#define LD2PT(vol) VolToPart[vol].pt /* Get partition number from the mapping table (0:auto search, 1-:forced partition number) */ #else #define LD2PD(vol) (BYTE)(vol) /* Each logical drive is associated with the same physical drive number */ #define LD2PT(vol) 0 /* Auto partition search */ @@ -278,15 +278,15 @@ /* File lock controls */ -#if FF_FS_LOCK != 0 +#if FF_FS_LOCK #if FF_FS_READONLY #error FF_FS_LOCK must be 0 at read-only configuration #endif -typedef struct { - FATFS *fs; /* Object ID 1, volume (NULL:blank entry) */ - DWORD clu; /* Object ID 2, containing directory (0:root) */ - DWORD ofs; /* Object ID 3, offset in the directory */ - WORD ctr; /* Object open counter, 0:none, 0x01..0xFF:read mode open count, 0x100:write mode */ +typedef struct { /* Open object identifier with status */ + FATFS* fs; /* Object ID 1, volume (NULL:blank entry) */ + DWORD clu; /* Object ID 2, containing directory (0:root) */ + DWORD ofs; /* Object ID 3, offset in the directory */ + UINT ctr; /* Object open status, 0:none, 0x01..0xFF:read mode open count, 0x100:write mode */ } FILESEM; #endif @@ -461,20 +461,24 @@ typedef struct { #if FF_VOLUMES < 1 || FF_VOLUMES > 10 #error Wrong FF_VOLUMES setting #endif -static FATFS* FatFs[FF_VOLUMES]; /* Pointer to the filesystem objects (logical drives) */ +static FATFS *FatFs[FF_VOLUMES]; /* Pointer to the filesystem objects (logical drives) */ static WORD Fsid; /* Filesystem mount ID */ -#if FF_FS_RPATH != 0 -static BYTE CurrVol; /* Current drive */ +#if FF_FS_RPATH +static BYTE CurrVol; /* Current drive number set by f_chdrive() */ #endif -#if FF_FS_LOCK != 0 +#if FF_FS_LOCK static FILESEM Files[FF_FS_LOCK]; /* Open object lock semaphores */ +#if FF_FS_REENTRANT +static volatile BYTE SysLock; /* System lock flag to protect Files[] (0:no mutex, 1:unlocked, 2:locked) */ +static volatile BYTE SysLockVolume; /* Volume id who is locking Files[] */ +#endif #endif #if FF_STR_VOLUME_ID #ifdef FF_VOLUME_STRS -static const char* const VolumeStr[FF_VOLUMES] = {FF_VOLUME_STRS}; /* Pre-defined volume ID */ +static const char *const VolumeStr[FF_VOLUMES] = {FF_VOLUME_STRS}; /* Pre-defined volume ID */ #endif #endif @@ -495,9 +499,9 @@ static const BYTE GUID_MS_Basic[16] = {0xA2,0xA0,0xD0,0xEB,0xE5,0xB9,0x33,0x44,0 #if FF_FS_EXFAT #error LFN must be enabled when enable exFAT #endif -#define DEF_NAMBUF -#define INIT_NAMBUF(fs) -#define FREE_NAMBUF() +#define DEF_NAMEBUFF +#define INIT_NAMEBUFF(fs) +#define FREE_NAMEBUFF() #define LEAVE_MKFS(res) return res #else /* LFN configurations */ @@ -518,32 +522,32 @@ static const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30}; /* FAT: Offset static BYTE DirBuf[MAXDIRB(FF_MAX_LFN)]; /* Directory entry block scratchpad buffer */ #endif static WCHAR LfnBuf[FF_MAX_LFN + 1]; /* LFN working buffer */ -#define DEF_NAMBUF -#define INIT_NAMBUF(fs) -#define FREE_NAMBUF() +#define DEF_NAMEBUFF +#define INIT_NAMEBUFF(fs) +#define FREE_NAMEBUFF() #define LEAVE_MKFS(res) return res #elif FF_USE_LFN == 2 /* LFN enabled with dynamic working buffer on the stack */ #if FF_FS_EXFAT -#define DEF_NAMBUF WCHAR lbuf[FF_MAX_LFN+1]; BYTE dbuf[MAXDIRB(FF_MAX_LFN)]; /* LFN working buffer and directory entry block scratchpad buffer */ -#define INIT_NAMBUF(fs) { (fs)->lfnbuf = lbuf; (fs)->dirbuf = dbuf; } -#define FREE_NAMBUF() +#define DEF_NAMEBUFF WCHAR lbuf[FF_MAX_LFN+1]; BYTE dbuf[MAXDIRB(FF_MAX_LFN)]; /* LFN working buffer and directory entry block scratchpad buffer */ +#define INIT_NAMEBUFF(fs) { (fs)->lfnbuf = lbuf; (fs)->dirbuf = dbuf; } +#define FREE_NAMEBUFF() #else -#define DEF_NAMBUF WCHAR lbuf[FF_MAX_LFN+1]; /* LFN working buffer */ -#define INIT_NAMBUF(fs) { (fs)->lfnbuf = lbuf; } -#define FREE_NAMBUF() +#define DEF_NAMEBUFF WCHAR lbuf[FF_MAX_LFN+1]; /* LFN working buffer */ +#define INIT_NAMEBUFF(fs) { (fs)->lfnbuf = lbuf; } +#define FREE_NAMEBUFF() #endif #define LEAVE_MKFS(res) return res #elif FF_USE_LFN == 3 /* LFN enabled with dynamic working buffer on the heap */ #if FF_FS_EXFAT -#define DEF_NAMBUF WCHAR *lfn; /* Pointer to LFN working buffer and directory entry block scratchpad buffer */ -#define INIT_NAMBUF(fs) { lfn = ff_memalloc((FF_MAX_LFN+1)*2 + MAXDIRB(FF_MAX_LFN)); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; (fs)->dirbuf = (BYTE*)(lfn+FF_MAX_LFN+1); } -#define FREE_NAMBUF() ff_memfree(lfn) +#define DEF_NAMEBUFF WCHAR *lfn; /* Pointer to LFN working buffer and directory entry block scratchpad buffer */ +#define INIT_NAMEBUFF(fs) { lfn = ff_memalloc((FF_MAX_LFN+1)*2 + MAXDIRB(FF_MAX_LFN)); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; (fs)->dirbuf = (BYTE*)(lfn+FF_MAX_LFN+1); } +#define FREE_NAMEBUFF() ff_memfree(lfn) #else -#define DEF_NAMBUF WCHAR *lfn; /* Pointer to LFN working buffer */ -#define INIT_NAMBUF(fs) { lfn = ff_memalloc((FF_MAX_LFN+1)*2); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; } -#define FREE_NAMBUF() ff_memfree(lfn) +#define DEF_NAMEBUFF WCHAR *lfn; /* Pointer to LFN working buffer */ +#define INIT_NAMEBUFF(fs) { lfn = ff_memalloc((FF_MAX_LFN+1)*2); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; } +#define FREE_NAMEBUFF() ff_memfree(lfn) #endif #define LEAVE_MKFS(res) { if (!work) ff_memfree(buf); return res; } #define MAX_MALLOC 0x8000 /* Must be >=FF_MAX_SS */ @@ -563,7 +567,8 @@ static WCHAR LfnBuf[FF_MAX_LFN + 1]; /* LFN working buffer */ #if FF_CODE_PAGE == 0 /* Run-time code page configuration */ #define CODEPAGE CodePage static WORD CodePage; /* Current code page */ -static const BYTE *ExCvt, *DbcTbl; /* Pointer to current SBCS up-case table and DBCS code range table below */ +static const BYTE* ExCvt; /* Pointer to SBCS up-case table Ct???[] (null:disabled) */ +static const BYTE* DbcTbl; /* Pointer to DBCS code range table Dc???[] (null:disabled) */ static const BYTE Ct437[] = TBL_CT437; static const BYTE Ct720[] = TBL_CT720; @@ -611,7 +616,7 @@ static const BYTE DbcTbl[] = MKCVTBL(TBL_DC, FF_CODE_PAGE); /* Load/Store multi-byte word in the FAT structure */ /*-----------------------------------------------------------------------*/ -static WORD ld_word (const BYTE* ptr) /* Load a 2-byte little-endian word */ +static WORD ld_16 (const BYTE* ptr) /* Load a 2-byte little-endian word */ { WORD rv; @@ -620,7 +625,7 @@ static WORD ld_word (const BYTE* ptr) /* Load a 2-byte little-endian word */ return rv; } -static DWORD ld_dword (const BYTE* ptr) /* Load a 4-byte little-endian word */ +static DWORD ld_32 (const BYTE* ptr) /* Load a 4-byte little-endian word */ { DWORD rv; @@ -632,7 +637,7 @@ static DWORD ld_dword (const BYTE* ptr) /* Load a 4-byte little-endian word */ } #if FF_FS_EXFAT -static QWORD ld_qword (const BYTE* ptr) /* Load an 8-byte little-endian word */ +static QWORD ld_64 (const BYTE* ptr) /* Load an 8-byte little-endian word */ { QWORD rv; @@ -649,13 +654,13 @@ static QWORD ld_qword (const BYTE* ptr) /* Load an 8-byte little-endian word */ #endif #if !FF_FS_READONLY -static void st_word (BYTE* ptr, WORD val) /* Store a 2-byte word in little-endian */ +static void st_16 (BYTE* ptr, WORD val) /* Store a 2-byte word in little-endian */ { *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; } -static void st_dword (BYTE* ptr, DWORD val) /* Store a 4-byte word in little-endian */ +static void st_32 (BYTE* ptr, DWORD val) /* Store a 4-byte word in little-endian */ { *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; val >>= 8; @@ -664,7 +669,7 @@ static void st_dword (BYTE* ptr, DWORD val) /* Store a 4-byte word in little-end } #if FF_FS_EXFAT -static void st_qword (BYTE* ptr, QWORD val) /* Store an 8-byte word in little-endian */ +static void st_64 (BYTE* ptr, QWORD val) /* Store an 8-byte word in little-endian */ { *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; val >>= 8; @@ -739,7 +744,7 @@ static DWORD tchar2uni ( /* Returns a character in UTF-16 encoding (>=0x10000 on #if FF_LFN_UNICODE == 1 /* UTF-16 input */ WCHAR wc; - uc = *p++; /* Get a unit */ + uc = *p++; /* Get an encoding unit */ if (IsSurrogate(uc)) { /* Surrogate? */ wc = *p++; /* Get low surrogate */ if (!IsSurrogateH(uc) || !IsSurrogateL(wc)) return 0xFFFFFFFF; /* Wrong surrogate? */ @@ -747,7 +752,7 @@ static DWORD tchar2uni ( /* Returns a character in UTF-16 encoding (>=0x10000 on } #elif FF_LFN_UNICODE == 2 /* UTF-8 input */ - BYTE b; + BYTE tb; int nf; uc = (BYTE)*p++; /* Get an encoding unit */ @@ -761,10 +766,10 @@ static DWORD tchar2uni ( /* Returns a character in UTF-16 encoding (>=0x10000 on } else { /* Wrong sequence */ return 0xFFFFFFFF; } - do { /* Get trailing bytes */ - b = (BYTE)*p++; - if ((b & 0xC0) != 0x80) return 0xFFFFFFFF; /* Wrong sequence? */ - uc = uc << 6 | (b & 0x3F); + do { /* Get and merge trailing bytes */ + tb = (BYTE)*p++; + if ((tb & 0xC0) != 0x80) return 0xFFFFFFFF; /* Wrong sequence? */ + uc = uc << 6 | (tb & 0x3F); } while (--nf != 0); if (uc < 0x80 || IsSurrogate(uc) || uc >= 0x110000) return 0xFFFFFFFF; /* Wrong code? */ if (uc >= 0x010000) uc = 0xD800DC00 | ((uc - 0x10000) << 6 & 0x3FF0000) | (uc & 0x3FF); /* Make a surrogate pair if needed */ @@ -776,14 +781,14 @@ static DWORD tchar2uni ( /* Returns a character in UTF-16 encoding (>=0x10000 on if (uc >= 0x010000) uc = 0xD800DC00 | ((uc - 0x10000) << 6 & 0x3FF0000) | (uc & 0x3FF); /* Make a surrogate pair if needed */ #else /* ANSI/OEM input */ - BYTE b; + BYTE sb; WCHAR wc; wc = (BYTE)*p++; /* Get a byte */ if (dbc_1st((BYTE)wc)) { /* Is it a DBC 1st byte? */ - b = (BYTE)*p++; /* Get 2nd byte */ - if (!dbc_2nd(b)) return 0xFFFFFFFF; /* Invalid code? */ - wc = (wc << 8) + b; /* Make a DBC */ + sb = (BYTE)*p++; /* Get 2nd byte */ + if (!dbc_2nd(sb)) return 0xFFFFFFFF; /* Invalid code? */ + wc = (wc << 8) + sb; /* Make a DBC */ } if (wc != 0) { wc = ff_oem2uni(wc, CODEPAGE); /* ANSI/OEM ==> Unicode */ @@ -875,7 +880,7 @@ static UINT put_utf ( /* Returns number of encoding units written (0:buffer over *buf++ = (TCHAR)wc; /* Store DBC 2nd byte */ return 2; } - if (wc == 0 || szb < 1) return 0; /* Invalid char or buffer overflow? */ + if (wc == 0 || szb < 1) return 0; /* Invalid character or buffer overflow? */ *buf++ = (TCHAR)wc; /* Store the character */ return 1; #endif @@ -887,21 +892,46 @@ static UINT put_utf ( /* Returns number of encoding units written (0:buffer over /*-----------------------------------------------------------------------*/ /* Request/Release grant to access the volume */ /*-----------------------------------------------------------------------*/ -static int lock_fs ( /* 1:Ok, 0:timeout */ - FATFS* fs /* Filesystem object */ + +static int lock_volume ( /* 1:Ok, 0:timeout */ + FATFS* fs, /* Filesystem object to lock */ + int syslock /* System lock required */ ) { - return ff_req_grant(fs->sobj); + int rv; + + +#if FF_FS_LOCK + rv = ff_mutex_take(fs->ldrv); /* Lock the volume */ + if (rv && syslock) { /* System lock reqiered? */ + rv = ff_mutex_take(FF_VOLUMES); /* Lock the system */ + if (rv) { + SysLockVolume = fs->ldrv; + SysLock = 2; /* System lock succeeded */ + } else { + ff_mutex_give(fs->ldrv); /* Failed system lock */ + } + } +#else + rv = syslock ? ff_mutex_take(fs->ldrv) : ff_mutex_take(fs->ldrv); /* Lock the volume (this is to prevent compiler warning) */ +#endif + return rv; } -static void unlock_fs ( +static void unlock_volume ( FATFS* fs, /* Filesystem object */ FRESULT res /* Result code to be returned */ ) { if (fs && res != FR_NOT_ENABLED && res != FR_INVALID_DRIVE && res != FR_TIMEOUT) { - ff_rel_grant(fs->sobj); +#if FF_FS_LOCK + if (SysLock == 2 && SysLockVolume == fs->ldrv) { /* Unlock system if it has been locked by this task */ + SysLock = 1; + ff_mutex_give(FF_VOLUMES); + } +#endif + ff_mutex_give(fs->ldrv); /* Unlock the volume */ } } @@ -909,12 +939,12 @@ static void unlock_fs ( -#if FF_FS_LOCK != 0 +#if FF_FS_LOCK /*-----------------------------------------------------------------------*/ -/* File lock control functions */ +/* File sharing control functions */ /*-----------------------------------------------------------------------*/ -static FRESULT chk_lock ( /* Check if the file can be accessed */ +static FRESULT chk_share ( /* Check if the file can be accessed */ DIR* dp, /* Directory object pointing the file to be checked */ int acc /* Desired access type (0:Read mode open, 1:Write mode open, 2:Delete or rename) */ ) @@ -941,16 +971,16 @@ static FRESULT chk_lock ( /* Check if the file can be accessed */ } -static int enq_lock (void) /* Check if an entry is available for a new object */ +static int enq_share (void) /* Check if an entry is available for a new object */ { UINT i; - for (i = 0; i < FF_FS_LOCK && Files[i].fs; i++) ; + for (i = 0; i < FF_FS_LOCK && Files[i].fs; i++) ; /* Find a free entry */ return (i == FF_FS_LOCK) ? 0 : 1; } -static UINT inc_lock ( /* Increment object open counter and returns its index (0:Internal error) */ +static UINT inc_share ( /* Increment object open counter and returns its index (0:Internal error) */ DIR* dp, /* Directory object pointing the file to register or increment */ int acc /* Desired access (0:Read, 1:Write, 2:Delete/Rename) */ ) @@ -965,7 +995,7 @@ static UINT inc_lock ( /* Increment object open counter and returns its index (0 } if (i == FF_FS_LOCK) { /* Not opened. Register it as new. */ - for (i = 0; i < FF_FS_LOCK && Files[i].fs; i++) ; + for (i = 0; i < FF_FS_LOCK && Files[i].fs; i++) ; /* Find a free entry */ if (i == FF_FS_LOCK) return 0; /* No free entry to register (int err) */ Files[i].fs = dp->obj.fs; Files[i].clu = dp->obj.sclust; @@ -981,30 +1011,32 @@ static UINT inc_lock ( /* Increment object open counter and returns its index (0 } -static FRESULT dec_lock ( /* Decrement object open counter */ +static FRESULT dec_share ( /* Decrement object open counter */ UINT i /* Semaphore index (1..) */ ) { - WORD n; + UINT n; FRESULT res; if (--i < FF_FS_LOCK) { /* Index number origin from 0 */ n = Files[i].ctr; - if (n == 0x100) n = 0; /* If write mode open, delete the entry */ + if (n == 0x100) n = 0; /* If write mode open, delete the object semaphore */ if (n > 0) n--; /* Decrement read mode open count */ Files[i].ctr = n; - if (n == 0) Files[i].fs = 0; /* Delete the entry if open count gets zero */ + if (n == 0) { /* Delete the object semaphore if open count becomes zero */ + Files[i].fs = 0; /* Free the entry << 1, there is a potential error in this process >>> */ + } res = FR_OK; } else { - res = FR_INT_ERR; /* Invalid index nunber */ + res = FR_INT_ERR; /* Invalid index number */ } return res; } -static void clear_lock ( /* Clear lock entries of the volume */ - FATFS *fs +static void clear_share ( /* Clear all lock entries of the volume */ + FATFS* fs ) { UINT i; @@ -1014,7 +1046,7 @@ static void clear_lock ( /* Clear lock entries of the volume */ } } -#endif /* FF_FS_LOCK != 0 */ +#endif /* FF_FS_LOCK */ @@ -1084,17 +1116,30 @@ static FRESULT sync_fs ( /* Returns FR_OK or FR_DISK_ERR */ res = sync_window(fs); if (res == FR_OK) { - if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) { /* FAT32: Update FSInfo sector if needed */ - /* Create FSInfo structure */ - memset(fs->win, 0, sizeof fs->win); - st_word(fs->win + BS_55AA, 0xAA55); /* Boot signature */ - st_dword(fs->win + FSI_LeadSig, 0x41615252); /* Leading signature */ - st_dword(fs->win + FSI_StrucSig, 0x61417272); /* Structure signature */ - st_dword(fs->win + FSI_Free_Count, fs->free_clst); /* Number of free clusters */ - st_dword(fs->win + FSI_Nxt_Free, fs->last_clst); /* Last allocated culuster */ - fs->winsect = fs->volbase + 1; /* Write it into the FSInfo sector (Next to VBR) */ - disk_write(fs->pdrv, fs->win, fs->winsect, 1); + if (fs->fsi_flag == 1) { /* Allocation changed? */ fs->fsi_flag = 0; + if (fs->fs_type == FS_FAT32) { /* FAT32: Update FSInfo sector */ + /* Create FSInfo structure */ + memset(fs->win, 0, sizeof fs->win); + st_32(fs->win + FSI_LeadSig, 0x41615252); /* Leading signature */ + st_32(fs->win + FSI_StrucSig, 0x61417272); /* Structure signature */ + st_32(fs->win + FSI_Free_Count, fs->free_clst); /* Number of free clusters */ + st_32(fs->win + FSI_Nxt_Free, fs->last_clst); /* Last allocated culuster */ + st_32(fs->win + FSI_TrailSig, 0xAA550000); /* Trailing signature */ + disk_write(fs->pdrv, fs->win, fs->winsect = fs->volbase + 1, 1); /* Write it into the FSInfo sector (Next to VBR) */ + } +#if FF_FS_EXFAT + else if (fs->fs_type == FS_EXFAT) { /* exFAT: Update PercInUse field in BPB */ + if (disk_read(fs->pdrv, fs->win, fs->winsect = fs->volbase, 1) == RES_OK) { /* Load VBR */ + BYTE perc_inuse = (fs->free_clst <= fs->n_fatent - 2) ? (BYTE)((QWORD)(fs->n_fatent - 2 - fs->free_clst) * 100 / (fs->n_fatent - 2)) : 0xFF; /* Precent in use 0-100 or 0xFF(unknown) */ + + if (fs->win[BPB_PercInUseEx] != perc_inuse) { /* Write it back into VBR if needed */ + fs->win[BPB_PercInUseEx] = perc_inuse; + disk_write(fs->pdrv, fs->win, fs->winsect, 1); + } + } + } +#endif } /* Make sure that no pending write process in the lower layer */ if (disk_ioctl(fs->pdrv, CTRL_SYNC, 0) != RES_OK) res = FR_DISK_ERR; @@ -1156,12 +1201,12 @@ static DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x7FFFFFF case FS_FAT16 : if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))) != FR_OK) break; - val = ld_word(fs->win + clst * 2 % SS(fs)); /* Simple WORD array */ + val = ld_16(fs->win + clst * 2 % SS(fs)); /* Simple WORD array */ break; case FS_FAT32 : if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break; - val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x0FFFFFFF; /* Simple DWORD array but mask out upper 4 bits */ + val = ld_32(fs->win + clst * 4 % SS(fs)) & 0x0FFFFFFF; /* Simple DWORD array but mask out upper 4 bits */ break; #if FF_FS_EXFAT case FS_EXFAT : @@ -1182,7 +1227,7 @@ static DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x7FFFFFF val = 0x7FFFFFFF; /* Generate EOC */ } else { if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break; - val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x7FFFFFFF; + val = ld_32(fs->win + clst * 4 % SS(fs)) & 0x7FFFFFFF; } break; } @@ -1236,7 +1281,7 @@ static FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */ case FS_FAT16: res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))); if (res != FR_OK) break; - st_word(fs->win + clst * 2 % SS(fs), (WORD)val); /* Simple WORD array */ + st_16(fs->win + clst * 2 % SS(fs), (WORD)val); /* Simple WORD array */ fs->wflag = 1; break; @@ -1247,9 +1292,9 @@ static FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */ res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))); if (res != FR_OK) break; if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { - val = (val & 0x0FFFFFFF) | (ld_dword(fs->win + clst * 4 % SS(fs)) & 0xF0000000); + val = (val & 0x0FFFFFFF) | (ld_32(fs->win + clst * 4 % SS(fs)) & 0xF0000000); } - st_dword(fs->win + clst * 4 % SS(fs), val); + st_32(fs->win + clst * 4 % SS(fs), val); fs->wflag = 1; break; } @@ -1430,7 +1475,7 @@ static FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ res = put_fat(fs, clst, 0); /* Mark the cluster 'free' on the FAT */ if (res != FR_OK) return res; } - if (fs->free_clst < fs->n_fatent - 2) { /* Update FSINFO */ + if (fs->free_clst < fs->n_fatent - 2) { /* Update allocation information if it is valid */ fs->free_clst++; fs->fsi_flag |= 1; } @@ -1453,7 +1498,7 @@ static FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ } #endif clst = nxt; /* Next cluster */ - } while (clst < fs->n_fatent); /* Repeat while not the last link */ + } while (clst < fs->n_fatent); /* Repeat until the last link */ #if FF_FS_EXFAT /* Some post processes for chain status */ @@ -1573,10 +1618,12 @@ static DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:D } } - if (res == FR_OK) { /* Update FSINFO if function succeeded. */ + if (res == FR_OK) { /* Update allocation information if the function succeeded */ fs->last_clst = ncl; - if (fs->free_clst <= fs->n_fatent - 2) fs->free_clst--; - fs->fsi_flag |= 1; + if (fs->free_clst > 0 && fs->free_clst <= fs->n_fatent - 2) { + fs->free_clst--; + fs->fsi_flag |= 1; + } } else { ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1; /* Failed. Generate error status */ } @@ -1599,7 +1646,8 @@ static DWORD clmt_clust ( /* <2:Error, >=2:Cluster number */ FSIZE_t ofs /* File offset to be converted to cluster# */ ) { - DWORD cl, ncl, *tbl; + DWORD cl, ncl; + DWORD *tbl; FATFS *fs = fp->obj.fs; @@ -1821,9 +1869,9 @@ static DWORD ld_clust ( /* Returns the top cluster value of the SFN entry */ { DWORD cl; - cl = ld_word(dir + DIR_FstClusLO); + cl = ld_16(dir + DIR_FstClusLO); if (fs->fs_type == FS_FAT32) { - cl |= (DWORD)ld_word(dir + DIR_FstClusHI) << 16; + cl |= (DWORD)ld_16(dir + DIR_FstClusHI) << 16; } return cl; @@ -1837,9 +1885,9 @@ static void st_clust ( DWORD cl /* Value to be set */ ) { - st_word(dir + DIR_FstClusLO, (WORD)cl); + st_16(dir + DIR_FstClusLO, (WORD)cl); if (fs->fs_type == FS_FAT32) { - st_word(dir + DIR_FstClusHI, (WORD)(cl >> 16)); + st_16(dir + DIR_FstClusHI, (WORD)(cl >> 16)); } } #endif @@ -1852,31 +1900,31 @@ static void st_clust ( /*--------------------------------------------------------*/ static int cmp_lfn ( /* 1:matched, 0:not matched */ - const WCHAR* lfnbuf, /* Pointer to the LFN working buffer to be compared */ - BYTE* dir /* Pointer to the directory entry containing the part of LFN */ + const WCHAR* lfnbuf, /* Pointer to the LFN to be compared */ + BYTE* dir /* Pointer to the LFN entry */ ) { - UINT i, s; - WCHAR wc, uc; + UINT ni, di; + WCHAR pchr, chr; - if (ld_word(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO */ + if (ld_16(dir + LDIR_FstClusLO) != 0) return 0; /* Check if LDIR_FstClusLO is 0 */ - i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */ + ni = (UINT)((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the name to be compared */ - for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */ - uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */ - if (wc != 0) { - if (i >= FF_MAX_LFN + 1 || ff_wtoupper(uc) != ff_wtoupper(lfnbuf[i++])) { /* Compare it */ + for (pchr = 1, di = 0; di < 13; di++) { /* Process all characters in the entry */ + chr = ld_16(dir + LfnOfs[di]); /* Pick a character from the entry */ + if (pchr != 0) { + if (ni >= FF_MAX_LFN + 1 || ff_wtoupper(chr) != ff_wtoupper(lfnbuf[ni++])) { /* Compare it with name */ return 0; /* Not matched */ } - wc = uc; + pchr = chr; } else { - if (uc != 0xFFFF) return 0; /* Check filler */ + if (chr != 0xFFFF) return 0; /* Check filler */ } } - if ((dir[LDIR_Ord] & LLEF) && wc && lfnbuf[i]) return 0; /* Last segment matched but different length */ + if ((dir[LDIR_Ord] & LLEF) && pchr && lfnbuf[ni]) return 0; /* Last name segment matched but different length */ return 1; /* The part of LFN matched */ } @@ -1888,31 +1936,31 @@ static int cmp_lfn ( /* 1:matched, 0:not matched */ /*-----------------------------------------------------*/ static int pick_lfn ( /* 1:succeeded, 0:buffer overflow or invalid LFN entry */ - WCHAR* lfnbuf, /* Pointer to the LFN working buffer */ - BYTE* dir /* Pointer to the LFN entry */ + WCHAR* lfnbuf, /* Pointer to the name buffer to be stored */ + const BYTE* dir /* Pointer to the LFN entry */ ) { - UINT i, s; - WCHAR wc, uc; + UINT ni, di; + WCHAR pchr, chr; - if (ld_word(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO is 0 */ + if (ld_16(dir + LDIR_FstClusLO) != 0) return 0; /* Check if LDIR_FstClusLO is 0 */ - i = ((dir[LDIR_Ord] & ~LLEF) - 1) * 13; /* Offset in the LFN buffer */ + ni = (UINT)((dir[LDIR_Ord] & ~LLEF) - 1) * 13; /* Offset in the name buffer */ - for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */ - uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */ - if (wc != 0) { - if (i >= FF_MAX_LFN + 1) return 0; /* Buffer overflow? */ - lfnbuf[i++] = wc = uc; /* Store it */ + for (pchr = 1, di = 0; di < 13; di++) { /* Process all characters in the entry */ + chr = ld_16(dir + LfnOfs[di]); /* Pick a character from the entry */ + if (pchr != 0) { + if (ni >= FF_MAX_LFN + 1) return 0; /* Buffer overflow? */ + lfnbuf[ni++] = pchr = chr; /* Store it */ } else { - if (uc != 0xFFFF) return 0; /* Check filler */ + if (chr != 0xFFFF) return 0; /* Check filler */ } } - if (dir[LDIR_Ord] & LLEF && wc != 0) { /* Put terminator if it is the last LFN part and not terminated */ - if (i >= FF_MAX_LFN + 1) return 0; /* Buffer overflow? */ - lfnbuf[i] = 0; + if (dir[LDIR_Ord] & LLEF && pchr != 0) { /* Put terminator if it is the last LFN part and not terminated */ + if (ni >= FF_MAX_LFN + 1) return 0; /* Buffer overflow? */ + lfnbuf[ni] = 0; } return 1; /* The part of LFN is valid */ @@ -1932,24 +1980,24 @@ static void put_lfn ( BYTE sum /* Checksum of the corresponding SFN */ ) { - UINT i, s; - WCHAR wc; + UINT ni, di; + WCHAR chr; dir[LDIR_Chksum] = sum; /* Set checksum */ - dir[LDIR_Attr] = AM_LFN; /* Set attribute. LFN entry */ + dir[LDIR_Attr] = AM_LFN; /* Set attribute */ dir[LDIR_Type] = 0; - st_word(dir + LDIR_FstClusLO, 0); - - i = (ord - 1) * 13; /* Get offset in the LFN working buffer */ - s = wc = 0; - 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 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 */ + st_16(dir + LDIR_FstClusLO, 0); + + ni = (UINT)(ord - 1) * 13; /* Offset in the name */ + di = chr = 0; + do { /* Fill the directory entry */ + if (chr != 0xFFFF) chr = lfn[ni++]; /* Get an effective character */ + st_16(dir + LfnOfs[di], chr); /* Set it */ + if (chr == 0) chr = 0xFFFF; /* Padding characters after the terminator */ + } while (++di < 13); + if (chr == 0xFFFF || !lfn[ni]) ord |= LLEF; /* Last LFN part is the start of an enrty set */ + dir[LDIR_Ord] = ord; /* Set order in the entry set */ } #endif /* !FF_FS_READONLY */ @@ -1966,31 +2014,31 @@ static void gen_numname ( BYTE* dst, /* Pointer to the buffer to store numbered SFN */ const BYTE* src, /* Pointer to SFN in directory form */ const WCHAR* lfn, /* Pointer to LFN */ - UINT seq /* Sequence number */ + WORD seq /* Sequence number */ ) { BYTE ns[8], c; UINT i, j; - WCHAR wc; - DWORD sreg; memcpy(dst, src, 11); /* Prepare the SFN to be modified */ if (seq > 5) { /* In case of many collisions, generate a hash number instead of sequential number */ - sreg = seq; - while (*lfn) { /* Create a CRC as hash value */ + WCHAR wc; + DWORD crc_sreg = seq; + + while (*lfn) { /* Create a CRC value as a hash of LFN */ wc = *lfn++; for (i = 0; i < 16; i++) { - sreg = (sreg << 1) + (wc & 1); + crc_sreg = (crc_sreg << 1) + (wc & 1); wc >>= 1; - if (sreg & 0x10000) sreg ^= 0x11021; + if (crc_sreg & 0x10000) crc_sreg ^= 0x11021; } } - seq = (UINT)sreg; + seq = (WORD)crc_sreg; } - /* Make suffix (~ + hexdecimal) */ + /* Make suffix (~ + 4-digit hexadecimal) */ i = 7; do { c = (BYTE)((seq % 16) + '0'); seq /= 16; @@ -2049,7 +2097,7 @@ static WORD xdir_sum ( /* Get checksum of the directoly entry block */ WORD sum; - szblk = (dir[XDIR_NumSec] + 1) * SZDIRE; /* Number of bytes of the entry block */ + szblk = ((UINT)dir[XDIR_NumSec] + 1) * SZDIRE; /* Number of bytes of the entry block */ for (i = sum = 0; i < szblk; i++) { if (i == XDIR_SetSum) { /* Skip 2-byte sum field */ i++; @@ -2092,26 +2140,26 @@ static DWORD xsum32 ( /* Returns 32-bit checksum */ -/*-----------------------------------*/ -/* exFAT: Get a directry entry block */ -/*-----------------------------------*/ +/*------------------------------------*/ +/* exFAT: Get a directory entry block */ +/*------------------------------------*/ static FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */ - DIR* dp /* Reading direcotry object pointing top of the entry block to load */ + DIR* dp /* Reading directory object pointing top of the entry block to load */ ) { FRESULT res; UINT i, sz_ent; - BYTE *dirb = dp->obj.fs->dirbuf; /* Pointer to the on-memory direcotry entry block 85+C0+C1s */ + BYTE *dirb = dp->obj.fs->dirbuf; /* Pointer to the on-memory directory entry block 85+C0+C1s */ - /* Load file directory entry */ + /* Load file-directory entry */ res = move_window(dp->obj.fs, dp->sect); if (res != FR_OK) return res; - if (dp->dir[XDIR_Type] != ET_FILEDIR) return FR_INT_ERR; /* Invalid order */ + if (dp->dir[XDIR_Type] != ET_FILEDIR) return FR_INT_ERR; /* Invalid order? */ memcpy(dirb + 0 * SZDIRE, dp->dir, SZDIRE); - sz_ent = (dirb[XDIR_NumSec] + 1) * SZDIRE; - if (sz_ent < 3 * SZDIRE || sz_ent > 19 * SZDIRE) return FR_INT_ERR; + sz_ent = ((UINT)dirb[XDIR_NumSec] + 1) * SZDIRE; /* Size of this entry block */ + if (sz_ent < 3 * SZDIRE || sz_ent > 19 * SZDIRE) return FR_INT_ERR; /* Invalid block size? */ /* Load stream extension entry */ res = dir_next(dp, 0); @@ -2119,9 +2167,9 @@ static FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */ if (res != FR_OK) return res; res = move_window(dp->obj.fs, dp->sect); if (res != FR_OK) return res; - if (dp->dir[XDIR_Type] != ET_STREAM) return FR_INT_ERR; /* Invalid order */ + if (dp->dir[XDIR_Type] != ET_STREAM) return FR_INT_ERR; /* Invalid order? */ memcpy(dirb + 1 * SZDIRE, dp->dir, SZDIRE); - if (MAXDIRB(dirb[XDIR_NumName]) > sz_ent) return FR_INT_ERR; + if (MAXDIRB(dirb[XDIR_NumName]) > sz_ent) return FR_INT_ERR; /* Invalid block size for the name? */ /* Load file name entries */ i = 2 * SZDIRE; /* Name offset to load */ @@ -2131,14 +2179,15 @@ static FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */ if (res != FR_OK) return res; res = move_window(dp->obj.fs, dp->sect); if (res != FR_OK) return res; - if (dp->dir[XDIR_Type] != ET_FILENAME) return FR_INT_ERR; /* Invalid order */ - if (i < MAXDIRB(FF_MAX_LFN)) memcpy(dirb + i, dp->dir, SZDIRE); + if (dp->dir[XDIR_Type] != ET_FILENAME) return FR_INT_ERR; /* Invalid order? */ + if (i < MAXDIRB(FF_MAX_LFN)) memcpy(dirb + i, dp->dir, SZDIRE); /* Load name entries only if the object is accessible */ } while ((i += SZDIRE) < sz_ent); /* Sanity check (do it for only accessible object) */ if (i <= MAXDIRB(FF_MAX_LFN)) { - if (xdir_sum(dirb) != ld_word(dirb + XDIR_SetSum)) return FR_INT_ERR; + if (xdir_sum(dirb) != ld_16(dirb + XDIR_SetSum)) return FR_INT_ERR; } + return FR_OK; } @@ -2148,25 +2197,33 @@ static FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */ /*------------------------------------------------------------------*/ static void init_alloc_info ( - FATFS* fs, /* Filesystem object */ - FFOBJID* obj /* Object allocation information to be initialized */ + FFOBJID* dobj, /* Object allocation information to be initialized */ + DIR* sdir /* Additional source about containing direcotry */ ) { - obj->sclust = ld_dword(fs->dirbuf + XDIR_FstClus); /* Start cluster */ - obj->objsize = ld_qword(fs->dirbuf + XDIR_FileSize); /* Size */ - obj->stat = fs->dirbuf[XDIR_GenFlags] & 2; /* Allocation status */ - obj->n_frag = 0; /* No last fragment info */ + FATFS *fs = dobj->fs; + + + if (sdir) { /* Initialize the containing directory. This block needs to precede the followings. */ + dobj->c_scl = sdir->obj.sclust; + dobj->c_size = ((DWORD)sdir->obj.objsize & 0xFFFFFF00) | sdir->obj.stat; + dobj->c_ofs = sdir->blk_ofs; + } + dobj->sclust = ld_32(fs->dirbuf + XDIR_FstClus); /* Start cluster */ + dobj->objsize = ld_64(fs->dirbuf + XDIR_FileSize); /* Size */ + dobj->stat = fs->dirbuf[XDIR_GenFlags] & 2; /* Allocation status */ + dobj->n_frag = 0; /* No last fragment info */ } -#if !FF_FS_READONLY || FF_FS_RPATH != 0 +#if !FF_FS_READONLY || FF_FS_RPATH /*------------------------------------------------*/ /* exFAT: Load the object's directory entry block */ /*------------------------------------------------*/ static FRESULT load_obj_xdir ( - DIR* dp, /* Blank directory object to be used to access containing direcotry */ + DIR* dp, /* Blank directory object to be used to access containing directory */ const FFOBJID* obj /* Object with its containing directory information */ ) { @@ -2195,27 +2252,29 @@ static FRESULT load_obj_xdir ( /*----------------------------------------*/ static FRESULT store_xdir ( - DIR* dp /* Pointer to the direcotry object */ + DIR* dp /* Pointer to the directory object */ ) { FRESULT res; UINT nent; - BYTE *dirb = dp->obj.fs->dirbuf; /* Pointer to the direcotry entry block 85+C0+C1s */ + BYTE *dirb = dp->obj.fs->dirbuf; /* Pointer to the entry set 85+C0+C1s */ + - /* Create set sum */ - st_word(dirb + XDIR_SetSum, xdir_sum(dirb)); - nent = dirb[XDIR_NumSec] + 1; + st_16(dirb + XDIR_SetSum, xdir_sum(dirb)); /* Create check sum */ - /* Store the direcotry entry block to the directory */ - res = dir_sdi(dp, dp->blk_ofs); + /* Store the entry set to the directory */ + nent = dirb[XDIR_NumSec] + 1; /* Number of entries */ + res = dir_sdi(dp, dp->blk_ofs); /* Top of the entry set */ while (res == FR_OK) { + /* Set an entry to the directory */ res = move_window(dp->obj.fs, dp->sect); if (res != FR_OK) break; memcpy(dp->dir, dirb, SZDIRE); dp->obj.fs->wflag = 1; - if (--nent == 0) break; + + if (--nent == 0) break; /* All done? */ dirb += SZDIRE; - res = dir_next(dp, 0); + res = dir_next(dp, 0); /* Next entry */ } return (res == FR_OK || res == FR_DISK_ERR) ? res : FR_INT_ERR; } @@ -2223,40 +2282,40 @@ static FRESULT store_xdir ( /*-------------------------------------------*/ -/* exFAT: Create a new directory enrty block */ +/* exFAT: Create a new directory entry block */ /*-------------------------------------------*/ static void create_xdir ( - BYTE* dirb, /* Pointer to the direcotry entry block buffer */ + BYTE* dirb, /* Pointer to the directory entry block buffer */ const WCHAR* lfn /* Pointer to the object name */ ) { UINT i; - BYTE nc1, nlen; - WCHAR wc; + BYTE n_c1, nlen; + WCHAR chr; - /* Create file-directory and stream-extension entry */ + /* Create file-directory and stream-extension entry (1st and 2nd entry) */ memset(dirb, 0, 2 * SZDIRE); dirb[0 * SZDIRE + XDIR_Type] = ET_FILEDIR; dirb[1 * SZDIRE + XDIR_Type] = ET_STREAM; - /* Create file-name entries */ - i = SZDIRE * 2; /* Top of file_name entries */ - nlen = nc1 = 0; wc = 1; + /* Create file name entries (3rd enrty and follows) */ + i = SZDIRE * 2; /* Top of file name entries */ + nlen = n_c1 = 0; chr = 1; do { dirb[i++] = ET_FILENAME; dirb[i++] = 0; do { /* Fill name field */ - if (wc != 0 && (wc = lfn[nlen]) != 0) nlen++; /* Get a character if exist */ - st_word(dirb + i, wc); /* Store it */ + if (chr != 0 && (chr = lfn[nlen]) != 0) nlen++; /* Get a character if exist */ + st_16(dirb + i, chr); /* Store it */ i += 2; } while (i % SZDIRE != 0); - nc1++; - } while (lfn[nlen]); /* Fill next entry if any char follows */ + n_c1++; + } while (lfn[nlen]); /* Fill next C1 entry if any char follows */ dirb[XDIR_NumName] = nlen; /* Set name length */ - dirb[XDIR_NumSec] = 1 + nc1; /* Set secondary count (C0 + C1s) */ - st_word(dirb + XDIR_NameHash, xname_sum(lfn)); /* Set name hash */ + dirb[XDIR_NumSec] = 1 + n_c1; /* Set secondary count (C0 + C1s) */ + st_16(dirb + XDIR_NameHash, xname_sum(lfn)); /* Set name hash */ } #endif /* !FF_FS_READONLY */ @@ -2279,7 +2338,7 @@ static FRESULT dir_read ( { FRESULT res = FR_NO_FILE; FATFS *fs = dp->obj.fs; - BYTE attr, b; + BYTE attr, et; #if FF_USE_LFN BYTE ord = 0xFF, sum = 0xFF; #endif @@ -2287,16 +2346,16 @@ static FRESULT dir_read ( while (dp->sect) { res = move_window(fs, dp->sect); if (res != FR_OK) break; - b = dp->dir[DIR_Name]; /* Test for the entry type */ - if (b == 0) { + et = dp->dir[DIR_Name]; /* Test for the entry type */ + if (et == 0) { res = FR_NO_FILE; break; /* Reached to end of the directory */ } #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ if (FF_USE_LABEL && vol) { - if (b == ET_VLABEL) break; /* Volume label entry? */ + if (et == ET_VLABEL) break; /* Volume label entry? */ } else { - if (b == ET_FILEDIR) { /* Start of the file entry block? */ + if (et == ET_FILEDIR) { /* Start of the file entry block? */ dp->blk_ofs = dp->dptr; /* Get location of the block */ res = load_xdir(dp); /* Load the entry block */ if (res == FR_OK) { @@ -2310,17 +2369,17 @@ static FRESULT dir_read ( { /* On the FAT/FAT32 volume */ dp->obj.attr = attr = dp->dir[DIR_Attr] & AM_MASK; /* Get attribute */ #if FF_USE_LFN /* LFN configuration */ - if (b == DDEM || b == '.' || (int)((attr & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */ + if (et == DDEM || et == '.' || (int)((attr & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */ ord = 0xFF; } else { if (attr == AM_LFN) { /* An LFN entry is found */ - if (b & LLEF) { /* Is it start of an LFN sequence? */ + if (et & LLEF) { /* Is it start of an LFN sequence? */ sum = dp->dir[LDIR_Chksum]; - b &= (BYTE)~LLEF; ord = b; + et &= (BYTE)~LLEF; ord = et; dp->blk_ofs = dp->dptr; } /* Check LFN validity and capture it */ - ord = (b == ord && sum == dp->dir[LDIR_Chksum] && pick_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF; + ord = (et == ord && sum == dp->dir[LDIR_Chksum] && pick_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF; } else { /* An SFN entry is found */ if (ord != 0 || sum != sum_sfn(dp->dir)) { /* Is there a valid LFN? */ dp->blk_ofs = 0xFFFFFFFF; /* It has no LFN. */ @@ -2329,7 +2388,7 @@ static FRESULT dir_read ( } } #else /* Non LFN configuration */ - if (b != DDEM && b != '.' && attr != AM_LFN && (int)((attr & ~AM_ARC) == AM_VOL) == vol) { /* Is it a valid entry? */ + if (et != DDEM && et != '.' && attr != AM_LFN && (int)((attr & ~AM_ARC) == AM_VOL) == vol) { /* Is it a valid entry? */ break; } #endif @@ -2356,9 +2415,9 @@ static FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ { FRESULT res; FATFS *fs = dp->obj.fs; - BYTE c; + BYTE et; #if FF_USE_LFN - BYTE a, ord, sum; + BYTE attr, ord, sum; #endif res = dir_sdi(dp, 0); /* Rewind directory object */ @@ -2373,10 +2432,10 @@ static FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ #if FF_MAX_LFN < 255 if (fs->dirbuf[XDIR_NumName] > FF_MAX_LFN) continue; /* Skip comparison if inaccessible object name */ #endif - if (ld_word(fs->dirbuf + XDIR_NameHash) != hash) continue; /* Skip comparison if hash mismatched */ + if (ld_16(fs->dirbuf + XDIR_NameHash) != hash) continue; /* Skip comparison if hash mismatched */ for (nc = fs->dirbuf[XDIR_NumName], di = SZDIRE * 2, ni = 0; nc; nc--, di += 2, ni++) { /* Compare the name */ if ((di % SZDIRE) == 0) di += 2; - if (ff_wtoupper(ld_word(fs->dirbuf + di)) != ff_wtoupper(fs->lfnbuf[ni])) break; + if (ff_wtoupper(ld_16(fs->dirbuf + di)) != ff_wtoupper(fs->lfnbuf[ni])) break; } if (nc == 0 && !fs->lfnbuf[ni]) break; /* Name matched? */ } @@ -2390,27 +2449,28 @@ static FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ do { res = move_window(fs, dp->sect); if (res != FR_OK) break; - c = dp->dir[DIR_Name]; - if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */ + et = dp->dir[DIR_Name]; /* Entry type */ + if (et == 0) { res = FR_NO_FILE; break; } /* Reached end of directory table */ #if FF_USE_LFN /* LFN configuration */ - dp->obj.attr = a = dp->dir[DIR_Attr] & AM_MASK; - if (c == DDEM || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */ + dp->obj.attr = attr = dp->dir[DIR_Attr] & AM_MASK; + if (et == DDEM || ((attr & AM_VOL) && attr != AM_LFN)) { /* An entry without valid data */ ord = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ } else { - if (a == AM_LFN) { /* An LFN entry is found */ + if (attr == AM_LFN) { /* Is it an LFN entry? */ if (!(dp->fn[NSFLAG] & NS_NOLFN)) { - if (c & LLEF) { /* Is it start of LFN sequence? */ - sum = dp->dir[LDIR_Chksum]; - c &= (BYTE)~LLEF; ord = c; /* LFN start order */ - dp->blk_ofs = dp->dptr; /* Start offset of LFN */ + if (et & LLEF) { /* Is it start of an entry set? */ + et &= (BYTE)~LLEF; + ord = et; /* Number of LFN entries */ + dp->blk_ofs = dp->dptr; /* Start offset of LFN */ + sum = dp->dir[LDIR_Chksum]; /* Sum of the SFN */ } /* Check validity of the LFN entry and compare it with given name */ - ord = (c == ord && sum == dp->dir[LDIR_Chksum] && cmp_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF; + ord = (et == ord && sum == dp->dir[LDIR_Chksum] && cmp_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF; } - } else { /* An SFN entry is found */ + } else { /* SFN entry */ if (ord == 0 && sum == sum_sfn(dp->dir)) break; /* LFN matched? */ if (!(dp->fn[NSFLAG] & NS_LOSS) && !memcmp(dp->dir, dp->fn, 11)) break; /* SFN matched? */ - ord = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ + ord = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Not matched, reset LFN sequence */ } } #else /* Non LFN configuration */ @@ -2439,7 +2499,7 @@ static FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too FATFS *fs = dp->obj.fs; #if FF_USE_LFN /* LFN configuration */ UINT n, len, n_ent; - BYTE sn[12], sum; + BYTE sn[12]; if (dp->fn[NSFLAG] & (NS_DOT | NS_NONAME)) return FR_INVALID_NAME; /* Check name validity */ @@ -2464,11 +2524,17 @@ 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); - st_qword(fs->dirbuf + XDIR_ValidFileSize, dp->obj.objsize); - fs->dirbuf[XDIR_GenFlags] = dp->obj.stat | 1; /* Update the allocation status */ + st_64(fs->dirbuf + XDIR_FileSize, dp->obj.objsize); + st_64(fs->dirbuf + XDIR_ValidFileSize, dp->obj.objsize); + 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; +#if FF_FS_RPATH /* Refrect changes to the current dir chain if the stretched dir is in it */ + for (n = 1; n <= fs->xcwds.depth && dp->obj.sclust != fs->xcwds.tbl[n].d_scl; n++) ; /* Check if the dir is in the current dir path */ + if (n <= fs->xcwds.depth) { /* If exist, update it */ + fs->xcwds.tbl[n].d_size = (DWORD)dp->obj.objsize | dp->obj.stat; + } +#endif } } @@ -2481,7 +2547,7 @@ static FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too if (sn[NSFLAG] & NS_LOSS) { /* When LFN is out of 8.3 format, generate a numbered name */ dp->fn[NSFLAG] = NS_NOLFN; /* Find only SFN */ for (n = 1; n < 100; n++) { - gen_numname(dp->fn, sn, fs->lfnbuf, n); /* Generate a numbered name */ + gen_numname(dp->fn, sn, fs->lfnbuf, (WORD)n); /* Generate a numbered name */ res = dir_find(dp); /* Check if the name collides with existing SFN */ if (res != FR_OK) break; } @@ -2496,7 +2562,8 @@ static FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too if (res == FR_OK && --n_ent) { /* Set LFN entry if needed */ res = dir_sdi(dp, dp->dptr - n_ent * SZDIRE); if (res == FR_OK) { - sum = sum_sfn(dp->fn); /* Checksum value of the SFN tied to the LFN */ + BYTE sum = sum_sfn(dp->fn); /* Checksum value of the SFN tied to the LFN */ + do { /* Store LFN entries in bottom first */ res = move_window(fs, dp->sect); if (res != FR_OK) break; @@ -2519,7 +2586,7 @@ static FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too memset(dp->dir, 0, SZDIRE); /* Clean the entry */ memcpy(dp->dir + DIR_Name, dp->fn, 11); /* Put SFN */ #if FF_USE_LFN - dp->dir[DIR_NTres] = dp->fn[NSFLAG] & (NS_BODY | NS_EXT); /* Put NT flag */ + dp->dir[DIR_NTres] = dp->fn[NSFLAG] & (NS_BODY | NS_EXT); /* Put low-case flags */ #endif fs->wflag = 1; } @@ -2590,7 +2657,6 @@ static void get_fileinfo ( { UINT si, di; #if FF_USE_LFN - BYTE lcf; WCHAR wc, hs; FATFS *fs = dp->obj.fs; UINT nw; @@ -2599,7 +2665,7 @@ static void get_fileinfo ( #endif - fno->fname[0] = 0; /* Invaidate file info */ + fno->fname[0] = 0; if (dp->sect == 0) return; /* Exit if read pointer has reached end of directory */ #if FF_USE_LFN /* LFN configuration */ @@ -2610,26 +2676,34 @@ static void get_fileinfo ( si = SZDIRE * 2; di = 0; /* 1st C1 entry in the entry block */ hs = 0; while (nc < fs->dirbuf[XDIR_NumName]) { - if (si >= MAXDIRB(FF_MAX_LFN)) { di = 0; break; } /* Truncated directory block? */ - if ((si % SZDIRE) == 0) si += 2; /* Skip entry type field */ - wc = ld_word(fs->dirbuf + si); si += 2; nc++; /* Get a character */ - if (hs == 0 && IsSurrogate(wc)) { /* Is it a surrogate? */ - hs = wc; continue; /* Get low surrogate */ + if (si >= MAXDIRB(FF_MAX_LFN)) { /* Truncated directory block? */ + di = 0; break; + } + if ((si % SZDIRE) == 0) si += 2; /* Skip entry type field */ + wc = ld_16(fs->dirbuf + si); si += 2; nc++; /* Get a character */ + if (hs == 0 && IsSurrogate(wc)) { /* Is it a surrogate? */ + hs = wc; continue; /* Get low surrogate */ } nw = put_utf((DWORD)hs << 16 | wc, &fno->fname[di], FF_LFN_BUF - di); /* Store it in API encoding */ - if (nw == 0) { di = 0; break; } /* Buffer overflow or wrong char? */ + if (nw == 0) { /* Buffer overflow or wrong char? */ + di = 0; break; + } di += nw; hs = 0; } if (hs != 0) di = 0; /* Broken surrogate pair? */ - if (di == 0) fno->fname[di++] = '?'; /* Inaccessible object name? */ + if (di == 0) fno->fname[di++] = '\?'; /* Inaccessible object name? */ fno->fname[di] = 0; /* Terminate the name */ fno->altname[0] = 0; /* exFAT does not support SFN */ - fno->fattrib = fs->dirbuf[XDIR_Attr] & AM_MASKX; /* Attribute */ - fno->fsize = (fno->fattrib & AM_DIR) ? 0 : ld_qword(fs->dirbuf + XDIR_FileSize); /* Size */ - fno->ftime = ld_word(fs->dirbuf + XDIR_ModTime + 0); /* Time */ - fno->fdate = ld_word(fs->dirbuf + XDIR_ModTime + 2); /* Date */ + fno->fattrib = fs->dirbuf[XDIR_Attr] & AM_MASKX; /* Attribute */ + fno->fsize = (fno->fattrib & AM_DIR) ? 0 : ld_64(fs->dirbuf + XDIR_FileSize); /* Size */ + fno->ftime = ld_16(fs->dirbuf + XDIR_ModTime + 0); /* Last modified time */ + fno->fdate = ld_16(fs->dirbuf + XDIR_ModTime + 2); /* Last modified date */ +#if FF_FS_CRTIME + fno->crtime = ld_16(fs->dirbuf + XDIR_CrtTime + 0); /* Created time */ + fno->crdate = ld_16(fs->dirbuf + XDIR_CrtTime + 2); /* Created date */ +#endif return; } else #endif @@ -2643,7 +2717,9 @@ static void get_fileinfo ( hs = wc; continue; /* Get low surrogate */ } nw = put_utf((DWORD)hs << 16 | wc, &fno->fname[di], FF_LFN_BUF - di); /* Store it in API encoding */ - if (nw == 0) { di = 0; break; } /* Buffer overflow or wrong char? */ + if (nw == 0) { /* Buffer overflow or wrong char? */ + di = 0; break; + } di += nw; hs = 0; } @@ -2663,9 +2739,13 @@ static void get_fileinfo ( wc = wc << 8 | dp->dir[si++]; } wc = ff_oem2uni(wc, CODEPAGE); /* ANSI/OEM -> Unicode */ - if (wc == 0) { di = 0; break; } /* Wrong char in the current code page? */ + if (wc == 0) { /* Wrong char in the current code page? */ + di = 0; break; + } nw = put_utf(wc, &fno->altname[di], FF_SFN_BUF - di); /* Store it in API encoding */ - if (nw == 0) { di = 0; break; } /* Buffer overflow? */ + if (nw == 0) { /* Buffer overflow? */ + di = 0; break; + } di += nw; #else /* ANSI/OEM output */ fno->altname[di++] = (TCHAR)wc; /* Store it without any conversion */ @@ -2673,14 +2753,16 @@ static void get_fileinfo ( } fno->altname[di] = 0; /* Terminate the SFN (null string means SFN is invalid) */ - if (fno->fname[0] == 0) { /* If LFN is invalid, altname[] needs to be copied to fname[] */ - if (di == 0) { /* If LFN and SFN both are invalid, this object is inaccesible */ - fno->fname[di++] = '?'; + if (!fno->fname[0]) { /* If LFN is invalid, altname[] needs to be copied to fname[] */ + if (di == 0) { /* If LFN and SFN both are invalid, */ + fno->fname[di++] = '\?'; /* This object is inaccessible due to wrong buffer or locale settings */ } else { - for (si = di = 0, lcf = NS_BODY; fno->altname[si]; si++, di++) { /* Copy altname[] to fname[] with case information */ + BYTE lcflg = NS_BODY; + + for (si = di = 0; fno->altname[si]; si++, di++) { /* Copy altname[] to fname[] with case information */ wc = (WCHAR)fno->altname[si]; - if (wc == '.') lcf = NS_EXT; - if (IsUpper(wc) && (dp->dir[DIR_NTres] & lcf)) wc += 0x20; + if (wc == '.') lcflg = NS_EXT; + if (IsUpper(wc) && (dp->dir[DIR_NTres] & lcflg)) wc += 0x20; fno->fname[di] = (TCHAR)wc; } } @@ -2700,10 +2782,14 @@ static void get_fileinfo ( fno->fname[di] = 0; /* Terminate the SFN */ #endif - fno->fattrib = dp->dir[DIR_Attr] & AM_MASK; /* Attribute */ - fno->fsize = ld_dword(dp->dir + DIR_FileSize); /* Size */ - fno->ftime = ld_word(dp->dir + DIR_ModTime + 0); /* Time */ - fno->fdate = ld_word(dp->dir + DIR_ModTime + 2); /* Date */ + fno->fattrib = dp->dir[DIR_Attr] & AM_MASK; /* Attribute */ + fno->fsize = ld_32(dp->dir + DIR_FileSize); /* Size */ + fno->ftime = ld_16(dp->dir + DIR_ModTime + 0); /* Last modified time */ + fno->fdate = ld_16(dp->dir + DIR_ModTime + 2); /* Last Modified date */ +#if FF_FS_CRTIME + fno->crtime = ld_16(dp->dir + DIR_CrtTime + 0); /* Created time */ + fno->crdate = ld_16(dp->dir + DIR_CrtTime + 2); /* Created date */ +#endif } #endif /* FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 */ @@ -2734,9 +2820,9 @@ static DWORD get_achar ( /* Get a character and advance ptr */ chr = (BYTE)*(*ptr)++; /* Get a byte */ if (IsLower(chr)) chr -= 0x20; /* To upper ASCII char */ #if FF_CODE_PAGE == 0 - if (ExCvt && chr >= 0x80) chr = ExCvt[chr - 0x80]; /* To upper SBCS extended char */ + if (ExCvt && chr >= 0x80) chr = ExCvt[chr - 0x80]; /* To upper (SBCS extended char) */ #elif FF_CODE_PAGE < 900 - if (chr >= 0x80) chr = ExCvt[chr - 0x80]; /* To upper SBCS extended char */ + if (chr >= 0x80) chr = ExCvt[chr - 0x80]; /* To upper (SBCS extended char) */ #endif #if FF_CODE_PAGE == 0 || FF_CODE_PAGE >= 900 if (dbc_1st((BYTE)chr)) { /* Get DBC 2nd byte if needed */ @@ -2756,7 +2842,8 @@ static int pattern_match ( /* 0:mismatched, 1:matched */ UINT recur /* Recursion count */ ) { - const TCHAR *pptr, *nptr; + const TCHAR *pptr; + const TCHAR *nptr; DWORD pchr, nchr; UINT sk; @@ -2770,12 +2857,16 @@ static int pattern_match ( /* 0:mismatched, 1:matched */ do { pptr = pat; nptr = nam; /* Top of pattern and name to match */ for (;;) { - if (*pptr == '?' || *pptr == '*') { /* Wildcard term? */ + if (*pptr == '\?' || *pptr == '*') { /* Wildcard term? */ if (recur == 0) return 0; /* Too many wildcard terms? */ sk = 0; do { /* Analyze the wildcard term */ - if (*pptr++ == '?') sk++; else sk |= 0x100; - } while (*pptr == '?' || *pptr == '*'); + if (*pptr++ == '\?') { + sk++; + } else { + sk |= 0x100; + } + } while (*pptr == '\?' || *pptr == '*'); if (pattern_match(pptr, nptr, sk, recur - 1)) return 1; /* Test new branch (recursive call) */ nchr = *nptr; break; /* Branch mismatched */ } @@ -2805,13 +2896,14 @@ static FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not cr { #if FF_USE_LFN /* LFN configuration */ BYTE b, cf; - WCHAR wc, *lfn; + WCHAR wc; + WCHAR *lfn; + const TCHAR* p; DWORD uc; UINT i, ni, si, di; - const TCHAR *p; - /* Create LFN into LFN working buffer */ + /* Create an LFN into LFN working buffer */ p = *path; lfn = dp->obj.fs->lfnbuf; di = 0; for (;;) { uc = tchar2uni(&p); /* Get a character */ @@ -2832,7 +2924,7 @@ static FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not cr } *path = p; /* Return pointer to the next segment */ -#if FF_FS_RPATH != 0 +#if FF_FS_RPATH if ((di == 1 && lfn[di - 1] == '.') || (di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) { /* Is this segment a dot name? */ lfn[di] = 0; @@ -2930,7 +3022,8 @@ static FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not cr #else /* FF_USE_LFN : Non-LFN configuration */ - BYTE c, d, *sfn; + BYTE c, d; + BYTE *sfn; UINT ni, si, i; const char *p; @@ -2938,14 +3031,19 @@ static FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not cr p = *path; sfn = dp->fn; memset(sfn, ' ', 11); si = i = 0; ni = 8; -#if FF_FS_RPATH != 0 +#if FF_FS_RPATH if (p[si] == '.') { /* Is this a dot entry? */ - for (;;) { + for (;;) { /* Copy one or two dots */ c = (BYTE)p[si++]; if (c != '.' || si >= 3) break; sfn[i++] = c; } - if (!IsSeparator(c) && c > ' ') return FR_INVALID_NAME; + if (IsSeparator(c)) { + while (IsSeparator(p[si])) si++; /* Skip duplicated separators */ + if ((BYTE)p[si] <= ' ') c = 0; /* Terminate if no segment follows */ + } else if (c > ' ') { /* Not in dot name */ + return FR_INVALID_NAME; + } *path = p + si; /* Return pointer to the next segment */ sfn[NSFLAG] = (c <= ' ') ? NS_LAST | NS_DOT : NS_DOT; /* Set last segment flag if end of the path */ return FR_OK; @@ -2955,7 +3053,7 @@ static FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not cr c = (BYTE)p[si++]; /* Get a byte */ if (c <= ' ') break; /* Break if end of the path name */ if (IsSeparator(c)) { /* Break if a separator is found */ - while (IsSeparator(p[si])) si++; /* Skip duplicated separator if exist */ + while (IsSeparator(p[si])) si++; /* Skip duplicated separators */ break; } if (c == '.' || i >= ni) { /* End of body or field overflow? */ @@ -3010,28 +3108,33 @@ static FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ FATFS *fs = dp->obj.fs; -#if FF_FS_RPATH != 0 + /* Determins the start directory (current directory or forced root directory) */ +#if FF_FS_RPATH if (!IsSeparator(*path) && (FF_STR_VOLUME_ID != 2 || !IsTerminator(*path))) { /* Without heading separator */ dp->obj.sclust = fs->cdir; /* Start at the current directory */ } else #endif { /* With heading separator */ - while (IsSeparator(*path)) path++; /* Strip separators */ - dp->obj.sclust = 0; /* Start from the root directory */ + while (IsSeparator(*path)) path++; /* Strip heading separators */ + dp->obj.sclust = 0; /* Start at the root directory */ } + #if FF_FS_EXFAT dp->obj.n_frag = 0; /* Invalidate last fragment counter of the object */ -#if FF_FS_RPATH != 0 - if (fs->fs_type == FS_EXFAT && dp->obj.sclust) { /* exFAT: Retrieve the sub-directory's status */ - DIR dj; - - dp->obj.c_scl = fs->cdc_scl; - dp->obj.c_size = fs->cdc_size; - dp->obj.c_ofs = fs->cdc_ofs; - res = load_obj_xdir(&dj, &dp->obj); - if (res != FR_OK) return res; - dp->obj.objsize = ld_dword(fs->dirbuf + XDIR_FileSize); - dp->obj.stat = fs->dirbuf[XDIR_GenFlags] & 2; +#if FF_FS_RPATH + if (fs->fs_type == FS_EXFAT) { /* exFAT: Retrieve the start-directory's status */ + if (dp->obj.sclust) { /* Start directory is a sub-directory */ + /* Load the current directory chain into working buffer and initialize directory object as current dir */ + memcpy(&fs->xcwds2, &fs->xcwds, sizeof fs->xcwds2); + dp->obj.stat = (BYTE)fs->xcwds2.tbl[fs->xcwds2.depth].d_size; + dp->obj.objsize = fs->xcwds2.tbl[fs->xcwds2.depth].d_size & 0xFFFFFF00; + dp->obj.c_scl = fs->xcwds2.tbl[fs->xcwds2.depth - 1].d_scl; + dp->obj.c_size = fs->xcwds2.tbl[fs->xcwds2.depth - 1].d_size & 0xFFFFFF00; + dp->obj.c_ofs = fs->xcwds2.tbl[fs->xcwds2.depth - 1].nxt_ofs; + } else { /* Start directory is the root directory */ + /* Clear the directory path working buffer as root directory */ + memset(&fs->xcwds2, 0, sizeof fs->xcwds2); + } } #endif #endif @@ -3044,11 +3147,31 @@ static FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ for (;;) { res = create_name(dp, &path); /* Get a segment name of the path */ if (res != FR_OK) break; - res = dir_find(dp); /* Find an object with the segment name */ ns = dp->fn[NSFLAG]; +#if FF_FS_EXFAT && FF_FS_RPATH + if (fs->fs_type == FS_EXFAT && (ns & NS_DOT)) { /* Is it a dot name? */ + /* There is no dot entry in exFAT volume, so it needs to follow the parent directory with recorded path */ + if (fs->lfnbuf[1] == '.' && fs->xcwds2.depth) { /* ".." in the sub-dir? */ + fs->xcwds2.depth--; /* Get into the parent directory and load the directory info */ + dp->obj.sclust = fs->xcwds2.tbl[fs->xcwds2.depth].d_scl; + dp->obj.stat = (BYTE)fs->xcwds2.tbl[fs->xcwds2.depth].d_size; + dp->obj.objsize = fs->xcwds2.tbl[fs->xcwds2.depth].d_size & 0xFFFFFF00; + if (fs->xcwds2.depth) { /* Load containing dir info if needed */ + dp->obj.c_scl = fs->xcwds2.tbl[fs->xcwds2.depth - 1].d_scl; + dp->obj.c_size = fs->xcwds2.tbl[fs->xcwds2.depth - 1].d_size; + dp->obj.c_ofs = fs->xcwds2.tbl[fs->xcwds2.depth - 1].nxt_ofs; + } + } + dp->obj.attr |= AM_DIR; /* This is a directory */ + dp->fn[NSFLAG] |= NS_NONAME; /* but dot names in exFAT volume are not directory entry */ + if (ns & NS_LAST) break; /* Last segment? */ + continue; /* Follow next segment */ + } +#endif + res = dir_find(dp); /* Find an object with the segment name */ if (res != FR_OK) { /* Failed to find the object */ if (res == FR_NO_FILE) { /* Object is not found */ - if (FF_FS_RPATH && (ns & NS_DOT)) { /* If dot entry is not exist, stay there */ + if (FF_FS_RPATH && (ns & NS_DOT)) { /* If dot entry is not exist, stay there (may be root dir in FAT volume) */ if (!(ns & NS_LAST)) continue; /* Continue to follow if not last segment */ dp->fn[NSFLAG] = NS_NONAME; res = FR_OK; @@ -3058,17 +3181,24 @@ static FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ } break; } - if (ns & NS_LAST) break; /* Last segment matched. Function completed. */ +#if FF_FS_EXFAT && FF_FS_RPATH + if (fs->fs_type == FS_EXFAT && (dp->obj.attr & AM_DIR)) { /* Record the path if it is a sub-directory */ + fs->xcwds2.tbl[fs->xcwds2.depth].nxt_ofs = dp->blk_ofs; + if (++fs->xcwds2.depth >= sizeof fs->xcwds2.tbl / sizeof fs->xcwds2.tbl[0]) { /* Is it too deep path? */ + res = FR_NOT_ENOUGH_CORE; break; + } + fs->xcwds2.tbl[fs->xcwds2.depth].d_scl = ld_32(fs->dirbuf + XDIR_FstClus); + fs->xcwds2.tbl[fs->xcwds2.depth].d_size = ld_32(fs->dirbuf + XDIR_FileSize) | (fs->dirbuf[XDIR_GenFlags] & 2); + } +#endif + if (ns & NS_LAST) break; /* If last segment matched, the function completed */ /* Get into the sub-directory */ - if (!(dp->obj.attr & AM_DIR)) { /* It is not a sub-directory and cannot follow */ - res = FR_NO_PATH; break; + if (!(dp->obj.attr & AM_DIR)) { + res = FR_NO_PATH; break; /* It is not a sub-directory and cannot follow the path */ } #if FF_FS_EXFAT - if (fs->fs_type == FS_EXFAT) { /* Save containing directory information for next dir */ - dp->obj.c_scl = dp->obj.sclust; - dp->obj.c_size = ((DWORD)dp->obj.objsize & 0xFFFFFF00) | dp->obj.stat; - dp->obj.c_ofs = dp->blk_ofs; - init_alloc_info(fs, &dp->obj); /* Open next directory */ + if (fs->fs_type == FS_EXFAT) { + init_alloc_info(&dp->obj, dp); /* Open next directory */ } else #endif { @@ -3091,69 +3221,66 @@ static int get_ldnumber ( /* Returns logical drive number (-1:invalid drive numb const TCHAR** path /* Pointer to pointer to the path name */ ) { - const TCHAR *tp, *tt; - TCHAR tc; + const TCHAR *tp; + const TCHAR *tt; + TCHAR chr; int i; - int vol = -1; #if FF_STR_VOLUME_ID /* Find string volume ID */ - const char *sp; - char c; + const char *vsp; + char vchr; #endif tt = tp = *path; - if (!tp) return vol; /* Invalid path name? */ - do tc = *tt++; while (!IsTerminator(tc) && tc != ':'); /* Find a colon in the path */ + if (!tp) return -1; /* Invalid path name? */ + do { /* Find a colon in the path */ + chr = *tt++; + } while (!IsTerminator(chr) && chr != ':'); - if (tc == ':') { /* DOS/Windows style volume ID? */ + if (chr == ':') { /* Is there a DOS/Windows style volume ID? */ i = FF_VOLUMES; - if (IsDigit(*tp) && tp + 2 == tt) { /* Is there a numeric volume ID + colon? */ - i = (int)*tp - '0'; /* Get the LD number */ + if (IsDigit(*tp) && tp + 2 == tt) { /* Is it a numeric volume ID + colon? */ + i = (int)*tp - '0'; /* Get the logical drive number */ } -#if FF_STR_VOLUME_ID == 1 /* Arbitrary string is enabled */ +#if FF_STR_VOLUME_ID == 1 /* Arbitrary string volume ID is enabled */ else { - i = 0; + i = 0; /* Find volume ID string in the preconfigured table */ do { - sp = VolumeStr[i]; tp = *path; /* This string volume ID and path name */ - do { /* Compare the volume ID with path name */ - c = *sp++; tc = *tp++; - if (IsLower(c)) c -= 0x20; - if (IsLower(tc)) tc -= 0x20; - } while (c && (TCHAR)c == tc); - } while ((c || tp != tt) && ++i < FF_VOLUMES); /* Repeat for each id until pattern match */ + vsp = VolumeStr[i]; tp = *path; /* Preconfigured string and path name to test */ + do { /* Compare the volume ID with path name in case-insensitive */ + vchr = *vsp++; chr = *tp++; + if (IsLower(vchr)) vchr -= 0x20; + if (IsLower(chr)) chr -= 0x20; + } while (vchr && (TCHAR)vchr == chr); + } while ((vchr || tp != tt) && ++i < FF_VOLUMES); /* Repeat for each id until pattern match */ } #endif - if (i < FF_VOLUMES) { /* If a volume ID is found, get the drive number and strip it */ - vol = i; /* Drive number */ - *path = tt; /* Snip the drive prefix off */ - } - return vol; + if (i >= FF_VOLUMES) return -1; /* Not found or invalid volume ID */ + *path = tt; /* Snip the drive prefix off */ + return i; /* Return the found drive number */ } #if FF_STR_VOLUME_ID == 2 /* Unix style volume ID is enabled */ if (*tp == '/') { /* Is there a volume ID? */ while (*(tp + 1) == '/') tp++; /* Skip duplicated separator */ i = 0; do { - tt = tp; sp = VolumeStr[i]; /* Path name and this string volume ID */ - do { /* Compare the volume ID with path name */ - c = *sp++; tc = *(++tt); - if (IsLower(c)) c -= 0x20; - if (IsLower(tc)) tc -= 0x20; - } while (c && (TCHAR)c == tc); - } while ((c || (tc != '/' && !IsTerminator(tc))) && ++i < FF_VOLUMES); /* Repeat for each ID until pattern match */ - if (i < FF_VOLUMES) { /* If a volume ID is found, get the drive number and strip it */ - vol = i; /* Drive number */ - *path = tt; /* Snip the drive prefix off */ - } - return vol; - } -#endif - /* No drive prefix is found */ -#if FF_FS_RPATH != 0 - vol = CurrVol; /* Default drive is current drive */ + vsp = VolumeStr[i]; tt = tp; /* Preconfigured string and path name to test */ + do { /* Compare the volume ID with path name in case-insensitive */ + vchr = *vsp++; chr = *(++tt); + if (IsLower(vchr)) vchr -= 0x20; + if (IsLower(chr)) chr -= 0x20; + } while (vchr && (TCHAR)vchr == chr); + } while ((vchr || (chr != '/' && !IsTerminator(chr))) && ++i < FF_VOLUMES); /* Repeat for each ID until pattern match */ + if (i >= FF_VOLUMES) return -1; /* Not found (invalid volume ID) */ + *path = tt; /* Snip the node name off */ + return i; /* Return the found drive number */ + } +#endif + /* No drive prefix */ +#if FF_FS_RPATH + return (int)CurrVol; /* Default drive is current drive */ #else - vol = 0; /* Default drive is 0 */ + return 0; /* Default drive is 0 */ #endif - return vol; /* Return the default drive */ } @@ -3190,27 +3317,29 @@ static int test_gpt_header ( /* 0:Invalid, 1:Valid */ ) { UINT i; - DWORD bcc; + DWORD bcc, hlen; - if (memcmp(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 */ + if (memcmp(gpth + GPTH_Sign, "EFI PART" "\0\0\1", 12)) return 0; /* Check signature and version (1.0) */ + hlen = ld_32(gpth + GPTH_Size); /* Check header size */ + if (hlen < 92 || hlen > FF_MIN_SS) return 0; + for (i = 0, bcc = 0xFFFFFFFF; i < hlen; 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) */ + if (~bcc != ld_32(gpth + GPTH_Bcc)) return 0; + if (ld_32(gpth + GPTH_PteSize) != SZ_GPTE) return 0; /* Table entry size (must be SZ_GPTE bytes) */ + if (ld_32(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 */ +/* Generate a random value */ +static DWORD make_rand ( /* Returns a seed value for next */ + DWORD seed, /* Seed value */ + BYTE *buff, /* Output buffer */ + UINT n /* Data length */ ) { UINT r; @@ -3246,7 +3375,7 @@ static UINT check_fs ( /* 0:FAT/FAT32 VBR, 1:exFAT VBR, 2:Not FAT and valid BS, fs->wflag = 0; fs->winsect = (LBA_t)0 - 1; /* Invaidate window */ if (move_window(fs, sect) != FR_OK) return 4; /* Load the boot sector */ - sign = ld_word(fs->win + BS_55AA); + sign = ld_16(fs->win + BS_55AA); #if FF_FS_EXFAT if (sign == 0xAA55 && !memcmp(fs->win + BS_JmpBoot, "\xEB\x76\x90" "EXFAT ", 11)) return 1; /* It is an exFAT VBR */ #endif @@ -3255,20 +3384,20 @@ static UINT check_fs ( /* 0:FAT/FAT32 VBR, 1:exFAT VBR, 2:Not FAT and valid BS, if (sign == 0xAA55 && !memcmp(fs->win + BS_FilSysType32, "FAT32 ", 8)) { return 0; /* It is an FAT32 VBR */ } - /* FAT volumes formatted with early MS-DOS lack BS_55AA and BS_FilSysType, so FAT VBR needs to be identified without them. */ - w = ld_word(fs->win + BPB_BytsPerSec); + /* FAT volumes created in the early MS-DOS era lack BS_55AA and BS_FilSysType, so FAT VBR needs to be identified without them. */ + w = ld_16(fs->win + BPB_BytsPerSec); b = fs->win[BPB_SecPerClus]; if ((w & (w - 1)) == 0 && w >= FF_MIN_SS && w <= FF_MAX_SS /* Properness of sector size (512-4096 and 2^n) */ && b != 0 && (b & (b - 1)) == 0 /* Properness of cluster size (2^n) */ - && ld_word(fs->win + BPB_RsvdSecCnt) != 0 /* Properness of reserved sectors (MNBZ) */ - && (UINT)fs->win[BPB_NumFATs] - 1 <= 1 /* Properness of FATs (1 or 2) */ - && ld_word(fs->win + BPB_RootEntCnt) != 0 /* Properness of root dir entries (MNBZ) */ - && (ld_word(fs->win + BPB_TotSec16) >= 128 || ld_dword(fs->win + BPB_TotSec32) >= 0x10000) /* Properness of volume sectors (>=128) */ - && ld_word(fs->win + BPB_FATSz16) != 0) { /* Properness of FAT size (MNBZ) */ + && ld_16(fs->win + BPB_RsvdSecCnt) != 0 /* Properness of number of reserved sectors (MNBZ) */ + && (UINT)fs->win[BPB_NumFATs] - 1 <= 1 /* Properness of number of FATs (1 or 2) */ + && ld_16(fs->win + BPB_RootEntCnt) != 0 /* Properness of root dir size (MNBZ) */ + && (ld_16(fs->win + BPB_TotSec16) >= 128 || ld_32(fs->win + BPB_TotSec32) >= 0x10000) /* Properness of volume size (>=128) */ + && ld_16(fs->win + BPB_FATSz16) != 0) { /* Properness of FAT size (MNBZ) */ return 0; /* It can be presumed an FAT VBR */ } } - return sign == 0xAA55 ? 2 : 3; /* Not an FAT VBR (valid or invalid BS) */ + return sign == 0xAA55 ? 2 : 3; /* Not an FAT VBR (with valid or invalid BS) */ } @@ -3277,7 +3406,7 @@ static UINT check_fs ( /* 0:FAT/FAT32 VBR, 1:exFAT VBR, 2:Not FAT and valid BS, 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 part /* Partition to fined = 0:find as SFD and partitions, >0:forced partition number */ ) { UINT fmt, i; @@ -3287,7 +3416,7 @@ static UINT find_volume ( /* Returns BS status found in the hosting drive */ fmt = check_fs(fs, 0); /* Load sector 0 and check if it is an FAT VBR as SFD format */ if (fmt != 2 && (fmt >= 3 || part == 0)) return fmt; /* Returns if it is an 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 */ + /* Sector 0 is not an FAT VBR or forced partition number wants a partitioned drive */ #if FF_LBA64 if (fs->win[MBR_Table + PTE_System] == 0xEE) { /* GPT protective MBR? */ @@ -3296,14 +3425,14 @@ static UINT find_volume ( /* Returns BS status found in the hosting drive */ 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 */ + n_ent = ld_32(fs->win + GPTH_PtNum); /* Number of entries */ + pt_lba = ld_64(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 (!memcmp(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 */ + v_ent++; /* Order of MS BDP */ + fmt = check_fs(fs, ld_64(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) */ } @@ -3311,9 +3440,9 @@ static UINT find_volume ( /* Returns BS status found in the hosting drive */ return 3; /* Not found */ } #endif - if (FF_MULTI_PARTITION && part > 4) return 3; /* MBR has 4 partitions max */ + if (FF_MULTI_PARTITION && part > 4) return 3; /* MBR has four primary partitions max (FatFs does not support logical partition) */ 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); + mbr_pt[i] = ld_32(fs->win + MBR_Table + i * SZ_PTE + PTE_StLba); } i = part ? part - 1 : 0; /* Table index to find first */ do { /* Find an FAT volume */ @@ -3332,15 +3461,13 @@ static UINT find_volume ( /* Returns BS status found in the hosting drive */ 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 mode /* Desiered access mode to check write protection */ ) { int vol; + FATFS *fs; DSTATUS stat; LBA_t bsect; - DWORD tsect, sysect, fasize, nclst, szbfat; - WORD nrsv; - FATFS *fs; UINT fmt; @@ -3353,7 +3480,7 @@ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ fs = FatFs[vol]; /* Get pointer to the filesystem object */ if (!fs) return FR_NOT_ENABLED; /* Is the filesystem object available? */ #if FF_FS_REENTRANT - if (!lock_fs(fs)) return FR_TIMEOUT; /* Lock the volume */ + if (!lock_volume(fs, 1)) return FR_TIMEOUT; /* Lock the volume, and system if needed */ #endif *rfs = fs; /* Return pointer to the filesystem object */ @@ -3371,9 +3498,8 @@ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ /* The filesystem object is not valid. */ /* Following code attempts to mount the volume. (find an FAT volume, analyze the BPB and initialize the filesystem object) */ - fs->fs_type = 0; /* Clear the filesystem object */ - fs->pdrv = LD2PD(vol); /* Volume hosting physical drive */ - stat = disk_initialize(fs->pdrv); /* Initialize the physical drive */ + fs->fs_type = 0; /* Invalidate the filesystem object */ + stat = disk_initialize(fs->pdrv); /* Initialize the volume hosting 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 */ } @@ -3385,32 +3511,32 @@ static FRESULT mount_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 volume on the drive */ + /* Find an FAT volume on the hosting 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 == 4) return FR_DISK_ERR; /* An error occurred in the disk I/O layer */ if (fmt >= 2) return FR_NO_FILESYSTEM; /* No FAT volume is found */ - bsect = fs->winsect; /* Volume offset */ + bsect = fs->winsect; /* Volume offset in the hosting physical drive */ /* 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, i; + DWORD so, cv, bcl, ncl, 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; - if (ld_word(fs->win + BPB_FSVerEx) != 0x100) return FR_NO_FILESYSTEM; /* Check exFAT version (must be version 1.0) */ + if (ld_16(fs->win + BPB_FSVerEx) != 0x100) return FR_NO_FILESYSTEM; /* Check exFAT version (must be version 1.0) */ if (1 << fs->win[BPB_BytsPerSecEx] != SS(fs)) { /* (BPB_BytsPerSecEx must be equal to the physical sector size) */ return FR_NO_FILESYSTEM; } - maxlba = ld_qword(fs->win + BPB_TotSecEx) + bsect; /* Last LBA of the volume + 1 */ + maxlba = ld_64(fs->win + BPB_TotSecEx) + bsect; /* Last LBA of the volume + 1 */ if (!FF_LBA64 && maxlba >= 0x100000000) return FR_NO_FILESYSTEM; /* (It cannot be accessed in 32-bit LBA) */ - fs->fsize = ld_dword(fs->win + BPB_FatSzEx); /* Number of sectors per FAT */ + fs->fsize = ld_32(fs->win + BPB_FatSzEx); /* Number of sectors per FAT */ fs->n_fats = fs->win[BPB_NumFATsEx]; /* Number of FATs */ if (fs->n_fats != 1) return FR_NO_FILESYSTEM; /* (Supports only 1 FAT) */ @@ -3418,16 +3544,16 @@ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ fs->csize = 1 << fs->win[BPB_SecPerClusEx]; /* Cluster size */ if (fs->csize == 0) return FR_NO_FILESYSTEM; /* (Must be 1..32768 sectors) */ - nclst = ld_dword(fs->win + BPB_NumClusEx); /* Number of clusters */ - if (nclst > MAX_EXFAT) return FR_NO_FILESYSTEM; /* (Too many clusters) */ - fs->n_fatent = nclst + 2; + ncl = ld_32(fs->win + BPB_NumClusEx); /* Number of clusters */ + if (ncl > MAX_EXFAT) return FR_NO_FILESYSTEM; /* (Too many clusters) */ + fs->n_fatent = ncl + 2; /* Boundaries and Limits */ fs->volbase = bsect; - fs->database = bsect + ld_dword(fs->win + BPB_DataOfsEx); - fs->fatbase = bsect + ld_dword(fs->win + BPB_FatOfsEx); - if (maxlba < (QWORD)fs->database + nclst * fs->csize) return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size requiered) */ - fs->dirbase = ld_dword(fs->win + BPB_RootClusEx); + fs->database = bsect + ld_32(fs->win + BPB_DataOfsEx); + fs->fatbase = bsect + ld_32(fs->win + BPB_FatOfsEx); + if (maxlba < (QWORD)fs->database + ncl * fs->csize) return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size required) */ + fs->dirbase = ld_32(fs->win + BPB_RootClusEx); /* Get bitmap location and check if it is contiguous (implementation assumption) */ so = i = 0; @@ -3437,30 +3563,33 @@ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ 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? */ + if (fs->win[i] == ET_BITMAP) break; /* Is it a bitmap entry? */ i = (i + SZDIRE) % SS(fs); /* Next entry */ } - bcl = ld_dword(fs->win + i + 20); /* Bitmap cluster */ + bcl = ld_32(fs->win + i + 20); /* Bitmap cluster */ if (bcl < 2 || bcl >= fs->n_fatent) return FR_NO_FILESYSTEM; /* (Wrong cluster#) */ fs->bitbase = fs->database + fs->csize * (bcl - 2); /* Bitmap sector */ for (;;) { /* Check if bitmap is contiguous */ if (move_window(fs, fs->fatbase + bcl / (SS(fs) / 4)) != FR_OK) return FR_DISK_ERR; - cv = ld_dword(fs->win + bcl % (SS(fs) / 4) * 4); + cv = ld_32(fs->win + bcl % (SS(fs) / 4) * 4); if (cv == 0xFFFFFFFF) break; /* Last link? */ - if (cv != ++bcl) return FR_NO_FILESYSTEM; /* Fragmented? */ + if (cv != ++bcl) return FR_NO_FILESYSTEM; /* Fragmented bitmap? */ } - #if !FF_FS_READONLY - fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */ + fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Invalidate cluster allocation information */ + fs->fsi_flag = 0; /* Enable to sync PercInUse value in VBR */ #endif fmt = FS_EXFAT; /* FAT sub-type */ } else #endif /* FF_FS_EXFAT */ { - if (ld_word(fs->win + BPB_BytsPerSec) != SS(fs)) return FR_NO_FILESYSTEM; /* (BPB_BytsPerSec must be equal to the physical sector size) */ + DWORD tsect, sysect, fasize, nclst, szbfat; + WORD nrsv; + + if (ld_16(fs->win + BPB_BytsPerSec) != SS(fs)) return FR_NO_FILESYSTEM; /* (BPB_BytsPerSec must be equal to the physical sector size) */ - fasize = ld_word(fs->win + BPB_FATSz16); /* Number of sectors per FAT */ - if (fasize == 0) fasize = ld_dword(fs->win + BPB_FATSz32); + fasize = ld_16(fs->win + BPB_FATSz16); /* Number of sectors per FAT */ + if (fasize == 0) fasize = ld_32(fs->win + BPB_FATSz32); fs->fsize = fasize; fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FATs */ @@ -3470,13 +3599,13 @@ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ fs->csize = fs->win[BPB_SecPerClus]; /* Cluster size */ if (fs->csize == 0 || (fs->csize & (fs->csize - 1))) return FR_NO_FILESYSTEM; /* (Must be power of 2) */ - fs->n_rootdir = ld_word(fs->win + BPB_RootEntCnt); /* Number of root directory entries */ + fs->n_rootdir = ld_16(fs->win + BPB_RootEntCnt); /* Number of root directory entries */ if (fs->n_rootdir % (SS(fs) / SZDIRE)) return FR_NO_FILESYSTEM; /* (Must be sector aligned) */ - tsect = ld_word(fs->win + BPB_TotSec16); /* Number of sectors on the volume */ - if (tsect == 0) tsect = ld_dword(fs->win + BPB_TotSec32); + tsect = ld_16(fs->win + BPB_TotSec16); /* Number of sectors on the volume */ + if (tsect == 0) tsect = ld_32(fs->win + BPB_TotSec32); - nrsv = ld_word(fs->win + BPB_RsvdSecCnt); /* Number of reserved sectors */ + nrsv = ld_16(fs->win + BPB_RsvdSecCnt); /* Number of reserved sectors */ if (nrsv == 0) return FR_NO_FILESYSTEM; /* (Must not be 0) */ /* Determine the FAT sub type */ @@ -3496,9 +3625,9 @@ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ fs->fatbase = bsect + nrsv; /* FAT start sector */ fs->database = bsect + sysect; /* Data start sector */ if (fmt == FS_FAT32) { - if (ld_word(fs->win + BPB_FSVer32) != 0) return FR_NO_FILESYSTEM; /* (Must be FAT32 revision 0.0) */ + if (ld_16(fs->win + BPB_FSVer32) != 0) return FR_NO_FILESYSTEM; /* (Must be FAT32 revision 0.0) */ if (fs->n_rootdir != 0) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */ - fs->dirbase = ld_dword(fs->win + BPB_RootClus32); /* Root directory start cluster */ + fs->dirbase = ld_32(fs->win + BPB_RootClus32); /* Root directory start cluster */ szbfat = fs->n_fatent * 4; /* (Needed FAT size) */ } else { if (fs->n_rootdir == 0) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must not be 0) */ @@ -3510,44 +3639,49 @@ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ #if !FF_FS_READONLY /* Get FSInfo if available */ - fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */ - fs->fsi_flag = 0x80; -#if (FF_FS_NOFSINFO & 3) != 3 - if (fmt == FS_FAT32 /* Allow to update FSInfo only if BPB_FSInfo32 == 1 */ - && ld_word(fs->win + BPB_FSInfo32) == 1 + fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Invalidate cluster allocation information */ + fs->fsi_flag = 0x80; /* Disable FSInfo by default */ + if (fmt == FS_FAT32 + && ld_16(fs->win + BPB_FSInfo32) == 1 /* FAT32: Enable FSInfo feature only if FSInfo sector is next to VBR */ && move_window(fs, bsect + 1) == FR_OK) { fs->fsi_flag = 0; - if (ld_word(fs->win + BS_55AA) == 0xAA55 /* Load FSInfo data if available */ - && ld_dword(fs->win + FSI_LeadSig) == 0x41615252 - && ld_dword(fs->win + FSI_StrucSig) == 0x61417272) + if ( ld_32(fs->win + FSI_LeadSig) == 0x41615252 /* Load FSInfo data if available */ + && ld_32(fs->win + FSI_StrucSig) == 0x61417272 + && ld_32(fs->win + FSI_TrailSig) == 0xAA550000) { -#if (FF_FS_NOFSINFO & 1) == 0 - fs->free_clst = ld_dword(fs->win + FSI_Free_Count); +#if (FF_FS_NOFSINFO & 1) == 0 /* Get free cluster count if trust it */ + fs->free_clst = ld_32(fs->win + FSI_Free_Count); #endif -#if (FF_FS_NOFSINFO & 2) == 0 - fs->last_clst = ld_dword(fs->win + FSI_Nxt_Free); +#if (FF_FS_NOFSINFO & 2) == 0 /* Get next free cluster if rtust it */ + fs->last_clst = ld_32(fs->win + FSI_Nxt_Free); #endif } } -#endif /* (FF_FS_NOFSINFO & 3) != 3 */ #endif /* !FF_FS_READONLY */ } - fs->fs_type = (BYTE)fmt;/* FAT sub-type */ + fs->fs_type = (BYTE)fmt;/* FAT sub-type (the filesystem object gets valid) */ fs->id = ++Fsid; /* Volume mount ID */ -#if FF_USE_LFN == 1 - fs->lfnbuf = LfnBuf; /* Static LFN working buffer */ + +#if FF_USE_LFN == 1 /* Initilize pointers to the static working buffers */ + fs->lfnbuf = LfnBuf; /* LFN working buffer */ #if FF_FS_EXFAT - fs->dirbuf = DirBuf; /* Static directory block scratchpad buuffer */ + fs->dirbuf = DirBuf; /* Directory block scratchpad buuffer */ #endif #endif -#if FF_FS_RPATH != 0 - fs->cdir = 0; /* Initialize current directory */ + +#if FF_FS_RPATH /* Set the current directory top layer (root) */ + fs->cdir = 0; +#if FF_FS_EXFAT + memset(&fs->xcwds, 0, sizeof fs->xcwds); #endif -#if FF_FS_LOCK != 0 /* Clear file lock semaphores */ - clear_lock(fs); #endif + +#if FF_FS_LOCK /* Clear file lock semaphores */ + clear_share(fs); +#endif + return FR_OK; } @@ -3559,7 +3693,7 @@ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ /*-----------------------------------------------------------------------*/ static FRESULT validate ( /* Returns FR_OK or FR_INVALID_OBJECT */ - FFOBJID* obj, /* Pointer to the FFOBJID, the 1st member in the FIL/DIR object, to check validity */ + FFOBJID* obj, /* Pointer to the FFOBJID, the 1st member in the FIL/DIR structure, to check validity */ FATFS** rfs /* Pointer to pointer to the owner filesystem object to return */ ) { @@ -3568,22 +3702,22 @@ static FRESULT validate ( /* Returns FR_OK or FR_INVALID_OBJECT */ if (obj && obj->fs && obj->fs->fs_type && obj->id == obj->fs->id) { /* Test if the object is valid */ #if FF_FS_REENTRANT - if (lock_fs(obj->fs)) { /* Obtain the filesystem object */ - if (!(disk_status(obj->fs->pdrv) & STA_NOINIT)) { /* Test if the phsical drive is kept initialized */ + if (lock_volume(obj->fs, 0)) { /* Take a grant to access the volume */ + if (!(disk_status(obj->fs->pdrv) & STA_NOINIT)) { /* Test if the hosting physical drive is kept initialized */ res = FR_OK; } else { - unlock_fs(obj->fs, FR_OK); + unlock_volume(obj->fs, FR_OK); /* Invalidated volume, abort to access */ } - } else { + } else { /* Could not take */ res = FR_TIMEOUT; } #else - if (!(disk_status(obj->fs->pdrv) & STA_NOINIT)) { /* Test if the phsical drive is kept initialized */ + if (!(disk_status(obj->fs->pdrv) & STA_NOINIT)) { /* Test if the hosting physical drive is kept initialized */ res = FR_OK; } #endif } - *rfs = (res == FR_OK) ? obj->fs : 0; /* Corresponding filesystem object */ + *rfs = (res == FR_OK) ? obj->fs : 0; /* Return corresponding filesystem object if it is valid */ return res; } @@ -3599,7 +3733,7 @@ static FRESULT validate ( /* Returns FR_OK or FR_INVALID_OBJECT */ /*-----------------------------------------------------------------------*/ -/* Mount/Unmount a Logical Drive */ +/* API: Mount/Unmount a Logical Drive */ /*-----------------------------------------------------------------------*/ FRESULT f_mount ( @@ -3614,32 +3748,44 @@ FRESULT f_mount ( const TCHAR *rp = path; - /* Get logical drive number */ + /* Get volume ID (logical drive number) */ vol = get_ldnumber(&rp); if (vol < 0) return FR_INVALID_DRIVE; - cfs = FatFs[vol]; /* Pointer to fs object */ - if (cfs) { -#if FF_FS_LOCK != 0 - clear_lock(cfs); + cfs = FatFs[vol]; /* Pointer to the filesystem object of the volume */ + if (cfs) { /* Unregister current filesystem object */ + FatFs[vol] = 0; +#if FF_FS_LOCK /* Clear file lock semaphores correspond to this volume */ + clear_share(cfs); #endif -#if FF_FS_REENTRANT /* Discard sync object of the current volume */ - if (!ff_del_syncobj(cfs->sobj)) return FR_INT_ERR; +#if FF_FS_REENTRANT /* Discard mutex of the current volume */ + ff_mutex_delete(vol); #endif - cfs->fs_type = 0; /* Clear old fs object */ + cfs->fs_type = 0; /* Invalidate the filesystem object to be unregistered */ } - if (fs) { - fs->fs_type = 0; /* Clear new fs object */ -#if FF_FS_REENTRANT /* Create sync object for the new volume */ - if (!ff_cre_syncobj((BYTE)vol, &fs->sobj)) return FR_INT_ERR; + if (fs) { /* Register new filesystem object */ + fs->pdrv = LD2PD(vol); /* Volume hosting physical drive */ +#if FF_FS_REENTRANT /* Create a volume mutex */ + fs->ldrv = (BYTE)vol; /* Owner volume ID */ + if (!ff_mutex_create(vol)) return FR_INT_ERR; +#if FF_FS_LOCK + if (SysLock == 0) { /* Create a system mutex if needed */ + if (!ff_mutex_create(FF_VOLUMES)) { + ff_mutex_delete(vol); + return FR_INT_ERR; + } + SysLock = 1; /* System mutex is ready */ + } #endif +#endif + fs->fs_type = 0; /* Invalidate the new filesystem object */ + FatFs[vol] = fs; /* Register it */ } - FatFs[vol] = fs; /* Register new fs object */ - if (opt == 0) return FR_OK; /* Do not mount now, it will be mounted later */ + if (opt == 0) return FR_OK; /* Do not mount now, it will be mounted in subsequent file functions */ - res = mount_volume(&path, &fs, 0); /* Force mounted the volume */ + res = mount_volume(&path, &fs, 0); /* Force mounted the volume in this function */ LEAVE_FF(fs, res); } @@ -3647,7 +3793,7 @@ FRESULT f_mount ( /*-----------------------------------------------------------------------*/ -/* Open or Create a File */ +/* API: Open or Create a File */ /*-----------------------------------------------------------------------*/ FRESULT f_open ( @@ -3659,31 +3805,28 @@ FRESULT f_open ( FRESULT res; DIR dj; FATFS *fs; -#if !FF_FS_READONLY - DWORD cl, bcs, clst, tm; - LBA_t sc; - FSIZE_t ofs; -#endif - DEF_NAMBUF + DEF_NAMEBUFF - if (!fp) return FR_INVALID_OBJECT; + if (!fp) return FR_INVALID_OBJECT; /* Reject null pointer */ - /* Get logical drive number */ + /* Get logical drive number and mount the volume if needed */ mode &= FF_FS_READONLY ? FA_READ : FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_CREATE_NEW | FA_OPEN_ALWAYS | FA_OPEN_APPEND; res = mount_volume(&path, &fs, mode); + if (res == FR_OK) { + fp->obj.fs = fs; dj.obj.fs = fs; - INIT_NAMBUF(fs); + INIT_NAMEBUFF(fs); res = follow_path(&dj, path); /* Follow the file path */ #if !FF_FS_READONLY /* Read/Write configuration */ if (res == FR_OK) { if (dj.fn[NSFLAG] & NS_NONAME) { /* Origin directory itself? */ res = FR_INVALID_NAME; } -#if FF_FS_LOCK != 0 +#if FF_FS_LOCK else { - res = chk_lock(&dj, (mode & ~FA_READ) ? 1 : 0); /* Check if the file can be used */ + res = chk_share(&dj, (mode & ~FA_READ) ? 1 : 0); /* Check if the file can be used */ } #endif } @@ -3691,32 +3834,33 @@ FRESULT f_open ( if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) { if (res != FR_OK) { /* No file, create new */ if (res == FR_NO_FILE) { /* There is no file to open, create a new entry */ -#if FF_FS_LOCK != 0 - res = enq_lock() ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES; +#if FF_FS_LOCK + res = enq_share() ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES; #else res = dir_register(&dj); #endif } mode |= FA_CREATE_ALWAYS; /* File is created */ } - else { /* Any object with the same name is already existing */ - if (dj.obj.attr & (AM_RDO | AM_DIR)) { /* Cannot overwrite it (R/O or DIR) */ - res = FR_DENIED; + else { /* An object with the same name is already existing */ + if (mode & FA_CREATE_NEW) { + res = FR_EXIST; /* Cannot create as new file */ } else { - if (mode & FA_CREATE_NEW) res = FR_EXIST; /* Cannot create as new file */ + if (dj.obj.attr & (AM_RDO | AM_DIR)) res = FR_DENIED; /* Cannot overwrite it (R/O or DIR) */ } } if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) { /* Truncate the file if overwrite mode */ + DWORD tm = GET_FATTIME(); #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* Get current allocation info */ - fp->obj.fs = fs; - init_alloc_info(fs, &fp->obj); - /* Set directory entry block initial state */ + init_alloc_info(&fp->obj, 0); + /* Set exFAT directory entry block initial state */ memset(fs->dirbuf + 2, 0, 30); /* Clear 85 entry except for NumSec */ memset(fs->dirbuf + 38, 0, 26); /* Clear C0 entry except for NumName and NameHash */ fs->dirbuf[XDIR_Attr] = AM_ARC; - st_dword(fs->dirbuf + XDIR_CrtTime, GET_FATTIME()); + st_32(fs->dirbuf + XDIR_CrtTime, tm); /* Set created time */ + st_32(fs->dirbuf + XDIR_ModTime, tm); /* Set modified time (tmp setting) */ fs->dirbuf[XDIR_GenFlags] = 1; res = store_xdir(&dj); if (res == FR_OK && fp->obj.sclust != 0) { /* Remove the cluster chain if exist */ @@ -3726,17 +3870,18 @@ FRESULT f_open ( } else #endif { - /* Set directory entry initial state */ - tm = GET_FATTIME(); /* Set created time */ - st_dword(dj.dir + DIR_CrtTime, tm); - st_dword(dj.dir + DIR_ModTime, tm); + DWORD cl; + /* Set FAT directory entry initial state */ + st_32(dj.dir + DIR_CrtTime, tm); /* Set created time */ + st_32(dj.dir + DIR_ModTime, tm); /* Set modified time (tmp setting) */ cl = ld_clust(fs, dj.dir); /* Get current cluster chain */ dj.dir[DIR_Attr] = AM_ARC; /* Reset attribute */ st_clust(fs, dj.dir, 0); /* Reset file allocation info */ - st_dword(dj.dir + DIR_FileSize, 0); + st_32(dj.dir + DIR_FileSize, 0); fs->wflag = 1; if (cl != 0) { /* Remove the cluster chain if exist */ - sc = fs->winsect; + LBA_t sc = fs->winsect; + res = remove_chain(&dj.obj, cl, 0); if (res == FR_OK) { res = move_window(fs, sc); @@ -3761,12 +3906,13 @@ FRESULT f_open ( if (mode & FA_CREATE_ALWAYS) mode |= FA_MODIFIED; /* Set file change flag if created or overwritten */ fp->dir_sect = fs->winsect; /* Pointer to the directory entry */ fp->dir_ptr = dj.dir; -#if FF_FS_LOCK != 0 - fp->obj.lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0); /* Lock the file for this session */ +#if FF_FS_LOCK + fp->obj.lockid = inc_share(&dj, (mode & ~FA_READ) ? 1 : 0); /* Lock the file for this session */ if (fp->obj.lockid == 0) res = FR_INT_ERR; #endif } -#else /* R/O configuration */ + +#else /* R/O configuration */ if (res == FR_OK) { if (dj.fn[NSFLAG] & NS_NONAME) { /* Is it origin directory itself? */ res = FR_INVALID_NAME; @@ -3781,21 +3927,17 @@ FRESULT f_open ( if (res == FR_OK) { #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { - fp->obj.c_scl = dj.obj.sclust; /* Get containing directory info */ - fp->obj.c_size = ((DWORD)dj.obj.objsize & 0xFFFFFF00) | dj.obj.stat; - fp->obj.c_ofs = dj.blk_ofs; - init_alloc_info(fs, &fp->obj); + init_alloc_info(&fp->obj, &dj); } else #endif { fp->obj.sclust = ld_clust(fs, dj.dir); /* Get object allocation info */ - fp->obj.objsize = ld_dword(dj.dir + DIR_FileSize); + fp->obj.objsize = ld_32(dj.dir + DIR_FileSize); } #if FF_USE_FASTSEEK fp->cltbl = 0; /* Disable fast seek mode */ #endif - fp->obj.fs = fs; /* Validate the file object */ - fp->obj.id = fs->id; + fp->obj.id = fs->id; /* Set current volume mount ID */ fp->flag = mode; /* Set file access mode */ fp->err = 0; /* Clear error flag */ fp->sect = 0; /* Invalidate current data sector */ @@ -3805,6 +3947,9 @@ FRESULT f_open ( memset(fp->buf, 0, sizeof fp->buf); /* Clear sector buffer */ #endif if ((mode & FA_SEEKEND) && fp->obj.objsize > 0) { /* Seek to end of file if FA_OPEN_APPEND is specified */ + DWORD bcs, clst; + FSIZE_t ofs; + fp->fptr = fp->obj.objsize; /* Offset to seek */ bcs = (DWORD)fs->csize * SS(fs); /* Cluster size in byte */ clst = fp->obj.sclust; /* Follow the cluster chain */ @@ -3815,24 +3960,25 @@ FRESULT f_open ( } fp->clust = clst; if (res == FR_OK && ofs % SS(fs)) { /* Fill sector buffer if not on the sector boundary */ - sc = clst2sect(fs, clst); - if (sc == 0) { + LBA_t sec = clst2sect(fs, clst); + + if (sec == 0) { res = FR_INT_ERR; } else { - fp->sect = sc + (DWORD)(ofs / SS(fs)); + fp->sect = sec + (DWORD)(ofs / SS(fs)); #if !FF_FS_TINY if (disk_read(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) res = FR_DISK_ERR; #endif } } -#if FF_FS_LOCK != 0 - if (res != FR_OK) dec_lock(fp->obj.lockid); /* Decrement file open counter if seek failed */ +#if FF_FS_LOCK + if (res != FR_OK) dec_share(fp->obj.lockid); /* Decrement file open counter if seek failed */ #endif } #endif } - FREE_NAMBUF(); + FREE_NAMEBUFF(); } if (res != FR_OK) fp->obj.fs = 0; /* Invalidate file object on error */ @@ -3844,7 +3990,7 @@ FRESULT f_open ( /*-----------------------------------------------------------------------*/ -/* Read File */ +/* API: Read File */ /*-----------------------------------------------------------------------*/ FRESULT f_read ( @@ -3856,7 +4002,6 @@ FRESULT f_read ( { FRESULT res; FATFS *fs; - DWORD clst; LBA_t sect; FSIZE_t remain; UINT rcnt, cc, csect; @@ -3874,6 +4019,8 @@ FRESULT f_read ( if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */ csect = (UINT)(fp->fptr / SS(fs) & (fs->csize - 1)); /* Sector offset in the cluster */ if (csect == 0) { /* On the cluster boundary? */ + DWORD clst; + if (fp->fptr == 0) { /* On the top of the file? */ clst = fp->obj.sclust; /* Follow cluster chain from the origin */ } else { /* Middle or end of the file */ @@ -3921,7 +4068,7 @@ FRESULT f_read ( fp->flag &= (BYTE)~FA_DIRTY; } #endif - if (disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */ + if (disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */ } #endif fp->sect = sect; @@ -3944,7 +4091,7 @@ FRESULT f_read ( #if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ -/* Write File */ +/* API: Write File */ /*-----------------------------------------------------------------------*/ FRESULT f_write ( @@ -4065,7 +4212,7 @@ FRESULT f_write ( /*-----------------------------------------------------------------------*/ -/* Synchronize the File */ +/* API: Synchronize the File */ /*-----------------------------------------------------------------------*/ FRESULT f_sync ( @@ -4074,8 +4221,6 @@ FRESULT f_sync ( { FRESULT res; FATFS *fs; - DWORD tm; - BYTE *dir; res = validate(&fp->obj, &fs); /* Check validity of the file object */ @@ -4088,7 +4233,6 @@ FRESULT f_sync ( } #endif /* Update the directory entry */ - tm = GET_FATTIME(); /* Modified time */ #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { res = fill_first_frag(&fp->obj); /* Fill first fragment on the FAT if needed */ @@ -4097,40 +4241,43 @@ FRESULT f_sync ( } if (res == FR_OK) { DIR dj; - DEF_NAMBUF + DEF_NAMEBUFF - INIT_NAMBUF(fs); + INIT_NAMEBUFF(fs); res = load_obj_xdir(&dj, &fp->obj); /* Load directory entry block */ 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); /* 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_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_32(fs->dirbuf + XDIR_FstClus, fp->obj.sclust); /* Update start cluster */ + st_64(fs->dirbuf + XDIR_FileSize, fp->obj.objsize); /* Update file size */ + st_64(fs->dirbuf + XDIR_ValidFileSize, fp->obj.objsize); /* (FatFs does not support Valid File Size feature) */ + st_32(fs->dirbuf + XDIR_ModTime, GET_FATTIME()); /* Update modified time */ fs->dirbuf[XDIR_ModTime10] = 0; - st_dword(fs->dirbuf + XDIR_AccTime, 0); - res = store_xdir(&dj); /* Restore it to the directory */ + fs->dirbuf[XDIR_ModTZ] = 0; + st_32(fs->dirbuf + XDIR_AccTime, 0); /* Invalidate last access time */ + fs->dirbuf[XDIR_AccTZ] = 0; + res = store_xdir(&dj); /* Restore it to the directory */ if (res == FR_OK) { res = sync_fs(fs); fp->flag &= (BYTE)~FA_MODIFIED; } } - FREE_NAMBUF(); + FREE_NAMEBUFF(); } } else #endif { res = move_window(fs, fp->dir_sect); if (res == FR_OK) { - dir = fp->dir_ptr; - dir[DIR_Attr] |= AM_ARC; /* Set archive attribute to indicate that the file has been changed */ - st_clust(fp->obj.fs, dir, fp->obj.sclust); /* Update file allocation information */ - st_dword(dir + DIR_FileSize, (DWORD)fp->obj.objsize); /* Update file size */ - st_dword(dir + DIR_ModTime, tm); /* Update modified time */ - st_word(dir + DIR_LstAccDate, 0); + BYTE *dir = fp->dir_ptr; + + dir[DIR_Attr] |= AM_ARC; /* Set archive attribute to indicate that the file has been changed */ + st_clust(fp->obj.fs, dir, fp->obj.sclust); /* Update file allocation information */ + st_32(dir + DIR_FileSize, (DWORD)fp->obj.objsize); /* Update file size */ + st_32(dir + DIR_ModTime, GET_FATTIME()); /* Update modified time */ + st_16(dir + DIR_LstAccDate, 0); /* Invalidate last access date */ fs->wflag = 1; - res = sync_fs(fs); /* Restore it to the directory */ + res = sync_fs(fs); /* Restore it to the directory */ fp->flag &= (BYTE)~FA_MODIFIED; } } @@ -4146,7 +4293,7 @@ FRESULT f_sync ( /*-----------------------------------------------------------------------*/ -/* Close File */ +/* API: Close File */ /*-----------------------------------------------------------------------*/ FRESULT f_close ( @@ -4163,14 +4310,14 @@ FRESULT f_close ( { res = validate(&fp->obj, &fs); /* Lock volume */ if (res == FR_OK) { -#if FF_FS_LOCK != 0 - res = dec_lock(fp->obj.lockid); /* Decrement file open counter */ +#if FF_FS_LOCK + res = dec_share(fp->obj.lockid); /* Decrement file open counter */ if (res == FR_OK) fp->obj.fs = 0; /* Invalidate file object */ #else fp->obj.fs = 0; /* Invalidate file object */ #endif #if FF_FS_REENTRANT - unlock_fs(fs, FR_OK); /* Unlock volume */ + unlock_volume(fs, FR_OK); /* Unlock volume */ #endif } } @@ -4182,7 +4329,7 @@ FRESULT f_close ( #if FF_FS_RPATH >= 1 /*-----------------------------------------------------------------------*/ -/* Change Current Directory or Current Drive, Get Current Directory */ +/* API: Change Current Drive */ /*-----------------------------------------------------------------------*/ FRESULT f_chdrive ( @@ -4202,57 +4349,56 @@ FRESULT f_chdrive ( + +/*-----------------------------------------------------------------------*/ +/* API: Change Current Directory */ +/*-----------------------------------------------------------------------*/ + FRESULT f_chdir ( const TCHAR* path /* Pointer to the directory path */ ) { -#if FF_STR_VOLUME_ID == 2 - UINT i; -#endif FRESULT res; DIR dj; FATFS *fs; - DEF_NAMBUF + DEF_NAMEBUFF - /* Get logical drive */ - res = mount_volume(&path, &fs, 0); + res = mount_volume(&path, &fs, 0); /* Get logical drive and mount the volume if needed */ if (res == FR_OK) { dj.obj.fs = fs; - INIT_NAMBUF(fs); + INIT_NAMEBUFF(fs); res = follow_path(&dj, path); /* Follow the path */ if (res == FR_OK) { /* Follow completed */ if (dj.fn[NSFLAG] & NS_NONAME) { /* Is it the start directory itself? */ - fs->cdir = dj.obj.sclust; #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { - fs->cdc_scl = dj.obj.c_scl; - fs->cdc_size = dj.obj.c_size; - fs->cdc_ofs = dj.obj.c_ofs; + memcpy(&fs->xcwds, &fs->xcwds2, sizeof fs->xcwds); } #endif + fs->cdir = dj.obj.sclust; } else { if (dj.obj.attr & AM_DIR) { /* It is a sub-directory */ #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { - fs->cdir = ld_dword(fs->dirbuf + XDIR_FstClus); /* Sub-directory cluster */ - fs->cdc_scl = dj.obj.sclust; /* Save containing directory information */ - fs->cdc_size = ((DWORD)dj.obj.objsize & 0xFFFFFF00) | dj.obj.stat; - fs->cdc_ofs = dj.blk_ofs; + memcpy(&fs->xcwds, &fs->xcwds2, sizeof fs->xcwds); + fs->cdir = fs->xcwds.tbl[fs->xcwds.depth].d_scl; /* Sub-directory cluster */ } else #endif { - fs->cdir = ld_clust(fs, dj.dir); /* Sub-directory cluster */ + fs->cdir = ld_clust(fs, dj.dir); /* Sub-directory cluster */ } } else { res = FR_NO_PATH; /* Reached but a file */ } } } - FREE_NAMBUF(); + FREE_NAMEBUFF(); if (res == FR_NO_FILE) res = FR_NO_PATH; #if FF_STR_VOLUME_ID == 2 /* Also current drive is changed if in Unix style volume ID */ if (res == FR_OK) { + UINT i; + for (i = FF_VOLUMES - 1; i && fs != FatFs[i]; i--) ; /* Set current drive */ CurrVol = (BYTE)i; } @@ -4263,94 +4409,136 @@ FRESULT f_chdir ( } + + #if FF_FS_RPATH >= 2 +/*-----------------------------------------------------------------------*/ +/* API: Get Curent Directory */ +/*-----------------------------------------------------------------------*/ + FRESULT f_getcwd ( - TCHAR* buff, /* Pointer to the directory path */ + TCHAR* buff, /* Pointer to the buffer to store the current direcotry path */ UINT len /* Size of buff in unit of TCHAR */ ) { FRESULT res; DIR dj; FATFS *fs; - UINT i, n; - DWORD ccl; - TCHAR *tp = buff; #if FF_VOLUMES >= 2 UINT vl; #if FF_STR_VOLUME_ID - const char *vp; + const char *vid; #endif #endif FILINFO fno; - DEF_NAMBUF + DEF_NAMEBUFF - /* Get logical drive */ - buff[0] = 0; /* Set null string to get current volume */ - res = mount_volume((const TCHAR**)&buff, &fs, 0); /* Get current volume */ + buff[0] = 0; /* A null str to get current drive */ + res = mount_volume((const TCHAR**)&buff, &fs, 0); if (res == FR_OK) { dj.obj.fs = fs; - INIT_NAMBUF(fs); + INIT_NAMEBUFF(fs); +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ + UINT wi = 0; + UINT di, ni; + +#if FF_VOLUMES >= 2 /* Add drive prefix if needed */ +#if FF_STR_VOLUME_ID == 0 /* Numeric volume ID */ + if (wi < len) buff[wi++] = '0' + CurrVol; +#else /* String volume ID */ + if (FF_STR_VOLUME_ID == 2 && wi < len) buff[wi++] = '/'; + for (vid = (const char*)VolumeStr[CurrVol]; *vid && wi < len; buff[wi++] = *vid++) ; +#endif + if (FF_STR_VOLUME_ID <= 1 && wi < len) buff[wi++] = ':'; +#endif + if (wi < len) buff[wi++] = '/'; + for (di = 0; wi < len && di < fs->xcwds.depth; di++) { /* Follow current directory path with cwd structure */ + dj.obj.sclust = fs->xcwds.tbl[di].d_scl; /* Open this directory */ + dj.obj.stat = (BYTE)fs->xcwds.tbl[di].d_size; + dj.obj.objsize = fs->xcwds.tbl[di].d_size & 0xFFFFFF00; + res = dir_sdi(&dj, fs->xcwds.tbl[di].nxt_ofs); /* Find next directory */ + if (res != FR_OK) break; + res = DIR_READ_FILE(&dj); /* Get the directory name */ + if (res != FR_OK) break; + get_fileinfo(&dj, &fno); + if (di > 0 && wi < len) buff[wi++] = '/'; /* Add the directory name with a directory separator */ + for (ni = 0; fno.fname[ni] && wi < len; buff[wi++] = fno.fname[ni++]) ; + } + if (wi == len) { /* Buffer overflow? */ + res = FR_NOT_ENOUGH_CORE; + } else { + buff[wi] = 0; /* Terminate the string */ + } + } + else +#endif + { /* On the FAT/FAT32 volume */ + TCHAR *tp = buff; + UINT i, nl; + DWORD ccl; - /* Follow parent directories and create the path */ - i = len; /* Bottom of buffer (directory stack base) */ - if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { /* (Cannot do getcwd on exFAT and returns root path) */ + /* Follow parent directories toward the root directory and create the cwd path */ + i = len; /* Bottom of buffer (directory stack base) */ dj.obj.sclust = fs->cdir; /* Start to follow upper directory from current directory */ while ((ccl = dj.obj.sclust) != 0) { /* Repeat while current directory is a sub-directory */ - res = dir_sdi(&dj, 1 * SZDIRE); /* Get parent directory */ + res = dir_sdi(&dj, 1 * SZDIRE); /* Get parent directory */ if (res != FR_OK) break; res = move_window(fs, dj.sect); if (res != FR_OK) break; - dj.obj.sclust = ld_clust(fs, dj.dir); /* Goto parent directory */ + dj.obj.sclust = ld_clust(fs, dj.dir); /* Go to parent directory */ res = dir_sdi(&dj, 0); if (res != FR_OK) break; - do { /* Find the entry links to the child directory */ + do { /* Find the entry links to this sub-directory */ res = DIR_READ_FILE(&dj); if (res != FR_OK) break; if (ccl == ld_clust(fs, dj.dir)) break; /* Found the entry */ res = dir_next(&dj, 0); } while (res == FR_OK); - if (res == FR_NO_FILE) res = FR_INT_ERR;/* It cannot be 'not found'. */ + if (res == FR_NO_FILE) res = FR_INT_ERR; /* It cannot be 'not found'. */ if (res != FR_OK) break; - get_fileinfo(&dj, &fno); /* Get the directory name and push it to the buffer */ - for (n = 0; fno.fname[n]; n++) ; /* Name length */ - if (i < n + 1) { /* Insufficient space to store the path name? */ + get_fileinfo(&dj, &fno); /* Get the directory name and push it to the buffer */ + for (nl = 0; fno.fname[nl]; nl++) ; /* Name length */ + if (i < nl + 1) { /* Insufficient space to store the path name? */ res = FR_NOT_ENOUGH_CORE; break; } - while (n) buff[--i] = fno.fname[--n]; /* Stack the name */ + while (nl) buff[--i] = fno.fname[--nl]; /* Stack the name */ buff[--i] = '/'; } - } - if (res == FR_OK) { - if (i == len) buff[--i] = '/'; /* Is it the root-directory? */ + if (res == FR_OK) { + if (i == len) buff[--i] = '/'; /* Is it the root-directory? */ #if FF_VOLUMES >= 2 /* Put drive prefix */ - vl = 0; + vl = 0; #if FF_STR_VOLUME_ID >= 1 /* String volume ID */ - for (n = 0, vp = (const char*)VolumeStr[CurrVol]; vp[n]; n++) ; - if (i >= n + 2) { - if (FF_STR_VOLUME_ID == 2) *tp++ = (TCHAR)'/'; - for (vl = 0; vl < n; *tp++ = (TCHAR)vp[vl], vl++) ; - if (FF_STR_VOLUME_ID == 1) *tp++ = (TCHAR)':'; - vl++; - } + for (nl = 0, vid = (const char*)VolumeStr[CurrVol]; vid[nl]; nl++) ; /* Volume ID length */ + if (i >= nl + 2) { + if (FF_STR_VOLUME_ID == 2) *tp++ = '/'; /* Unix style */ + for (vl = 0; vl < nl; *tp++ = vid[vl], vl++) ; + if (FF_STR_VOLUME_ID == 1) *tp++ = ':'; /* DOS/Windows style */ + vl++; + } #else /* Numeric volume ID */ - if (i >= 3) { - *tp++ = (TCHAR)'0' + CurrVol; - *tp++ = (TCHAR)':'; - vl = 2; - } + if (i >= 3) { + *tp++ = '0' + CurrVol; + *tp++ = ':'; + vl = 2; + } #endif - if (vl == 0) res = FR_NOT_ENOUGH_CORE; + if (vl == 0) res = FR_NOT_ENOUGH_CORE; #endif - /* Add current directory path */ - if (res == FR_OK) { - do *tp++ = buff[i++]; while (i < len); /* Copy stacked path string */ + /* Add current directory path */ + if (res == FR_OK) { + do { /* Copy stacked path string */ + *tp++ = buff[i++]; + } while (i < len); + } } + *tp = 0; } - FREE_NAMBUF(); + FREE_NAMEBUFF(); } - *tp = 0; LEAVE_FF(fs, res); } @@ -4361,7 +4549,7 @@ FRESULT f_getcwd ( #if FF_FS_MINIMIZE <= 2 /*-----------------------------------------------------------------------*/ -/* Seek File Read/Write Pointer */ +/* API: Seek File Read/Write Pointer */ /*-----------------------------------------------------------------------*/ FRESULT f_lseek ( @@ -4374,11 +4562,7 @@ FRESULT f_lseek ( DWORD clst, bcs; LBA_t nsect; FSIZE_t ifptr; -#if FF_USE_FASTSEEK - DWORD cl, pcl, ncl, tcl, tlen, ulen; - DWORD *tbl; - LBA_t dsc; -#endif + res = validate(&fp->obj, &fs); /* Check validity of the file object */ if (res == FR_OK) res = (FRESULT)fp->err; @@ -4391,6 +4575,10 @@ FRESULT f_lseek ( #if FF_USE_FASTSEEK if (fp->cltbl) { /* Fast seek */ + DWORD cl, pcl, ncl, tcl, tlen, ulen; + DWORD *tbl; + LBA_t dsc; + if (ofs == CREATE_LINKMAP) { /* Create CLMT */ tbl = fp->cltbl; tlen = *tbl++; ulen = 2; /* Given table size and required table size */ @@ -4525,7 +4713,7 @@ FRESULT f_lseek ( #if FF_FS_MINIMIZE <= 1 /*-----------------------------------------------------------------------*/ -/* Create a Directory Object */ +/* API: Create a Directory Object */ /*-----------------------------------------------------------------------*/ FRESULT f_opendir ( @@ -4535,26 +4723,22 @@ FRESULT f_opendir ( { FRESULT res; FATFS *fs; - DEF_NAMBUF + DEF_NAMEBUFF - if (!dp) return FR_INVALID_OBJECT; + if (!dp) return FR_INVALID_OBJECT; /* Reject null pointer */ - /* Get logical drive */ - res = mount_volume(&path, &fs, 0); + res = mount_volume(&path, &fs, 0); /* Get logical drive and mount the volume if needed */ if (res == FR_OK) { dp->obj.fs = fs; - INIT_NAMBUF(fs); + INIT_NAMEBUFF(fs); res = follow_path(dp, path); /* Follow the path to the directory */ if (res == FR_OK) { /* Follow completed */ - if (!(dp->fn[NSFLAG] & NS_NONAME)) { /* It is not the origin directory itself */ + if (!(dp->fn[NSFLAG] & NS_NONAME)) { /* It is neither the origin directory itself nor dot name in exFAT */ if (dp->obj.attr & AM_DIR) { /* This object is a sub-directory */ #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { - dp->obj.c_scl = dp->obj.sclust; /* Get containing directory inforamation */ - dp->obj.c_size = ((DWORD)dp->obj.objsize & 0xFFFFFF00) | dp->obj.stat; - dp->obj.c_ofs = dp->blk_ofs; - init_alloc_info(fs, &dp->obj); /* Get object allocation info */ + init_alloc_info(&dp->obj, dp); /* Get object allocation info */ } else #endif { @@ -4565,24 +4749,24 @@ FRESULT f_opendir ( } } if (res == FR_OK) { - dp->obj.id = fs->id; - res = dir_sdi(dp, 0); /* Rewind directory */ -#if FF_FS_LOCK != 0 + dp->obj.id = fs->id; /* Set current volume mount ID */ + res = dir_sdi(dp, 0); /* Rewind directory */ +#if FF_FS_LOCK if (res == FR_OK) { - if (dp->obj.sclust != 0) { - dp->obj.lockid = inc_lock(dp, 0); /* Lock the sub directory */ + if (dp->obj.sclust) { /* Is this a sub-directory? */ + dp->obj.lockid = inc_share(dp, 0); /* Lock the sub-directory */ if (!dp->obj.lockid) res = FR_TOO_MANY_OPEN_FILES; } else { - dp->obj.lockid = 0; /* Root directory need not to be locked */ + dp->obj.lockid = 0; /* Root directory does not need to be locked */ } } #endif } } - FREE_NAMBUF(); + FREE_NAMEBUFF(); if (res == FR_NO_FILE) res = FR_NO_PATH; } - if (res != FR_OK) dp->obj.fs = 0; /* Invalidate the directory object if function faild */ + if (res != FR_OK) dp->obj.fs = 0; /* Invalidate the directory object if function failed */ LEAVE_FF(fs, res); } @@ -4591,7 +4775,7 @@ FRESULT f_opendir ( /*-----------------------------------------------------------------------*/ -/* Close Directory */ +/* API: Close Directory */ /*-----------------------------------------------------------------------*/ FRESULT f_closedir ( @@ -4604,14 +4788,14 @@ FRESULT f_closedir ( res = validate(&dp->obj, &fs); /* Check validity of the file object */ if (res == FR_OK) { -#if FF_FS_LOCK != 0 - if (dp->obj.lockid) res = dec_lock(dp->obj.lockid); /* Decrement sub-directory open counter */ +#if FF_FS_LOCK + if (dp->obj.lockid) res = dec_share(dp->obj.lockid); /* Decrement sub-directory open counter */ if (res == FR_OK) dp->obj.fs = 0; /* Invalidate directory object */ #else dp->obj.fs = 0; /* Invalidate directory object */ #endif #if FF_FS_REENTRANT - unlock_fs(fs, FR_OK); /* Unlock volume */ + unlock_volume(fs, FR_OK); /* Unlock volume */ #endif } return res; @@ -4621,7 +4805,7 @@ FRESULT f_closedir ( /*-----------------------------------------------------------------------*/ -/* Read Directory Entries in Sequence */ +/* API: Read Directory Entries in Sequence */ /*-----------------------------------------------------------------------*/ FRESULT f_readdir ( @@ -4631,15 +4815,16 @@ FRESULT f_readdir ( { FRESULT res; FATFS *fs; - DEF_NAMBUF + DEF_NAMEBUFF res = validate(&dp->obj, &fs); /* Check validity of the directory object */ if (res == FR_OK) { if (!fno) { - res = dir_sdi(dp, 0); /* Rewind the directory object */ + res = dir_sdi(dp, 0); /* Rewind the directory object */ } else { - INIT_NAMBUF(fs); + INIT_NAMEBUFF(fs); + fno->fname[0] = 0; /* Clear file information */ res = DIR_READ_FILE(dp); /* Read an item */ if (res == FR_NO_FILE) res = FR_OK; /* Ignore end of directory */ if (res == FR_OK) { /* A valid entry is found */ @@ -4647,9 +4832,11 @@ FRESULT f_readdir ( res = dir_next(dp, 0); /* Increment index for next */ if (res == FR_NO_FILE) res = FR_OK; /* Ignore end of directory now */ } - FREE_NAMBUF(); + FREE_NAMEBUFF(); } } + + if (fno && res != FR_OK) fno->fname[0] = 0; /* Clear the file information if any error occured */ LEAVE_FF(fs, res); } @@ -4674,7 +4861,7 @@ FRESULT f_seekdir( #if FF_USE_FIND /*-----------------------------------------------------------------------*/ -/* Find Next File */ +/* API: Find Next File */ /*-----------------------------------------------------------------------*/ FRESULT f_findnext ( @@ -4699,7 +4886,7 @@ FRESULT f_findnext ( /*-----------------------------------------------------------------------*/ -/* Find First File */ +/* API: Find First File */ /*-----------------------------------------------------------------------*/ FRESULT f_findfirst ( @@ -4726,7 +4913,7 @@ FRESULT f_findfirst ( #if FF_FS_MINIMIZE == 0 /*-----------------------------------------------------------------------*/ -/* Get File Status */ +/* API: Get File Status */ /*-----------------------------------------------------------------------*/ FRESULT f_stat ( @@ -4736,13 +4923,14 @@ FRESULT f_stat ( { FRESULT res; DIR dj; - DEF_NAMBUF + DEF_NAMEBUFF - /* Get logical drive */ + /* Get logical drive and mount the volume if needed */ res = mount_volume(&path, &dj.obj.fs, 0); + if (res == FR_OK) { - INIT_NAMBUF(dj.obj.fs); + INIT_NAMEBUFF(dj.obj.fs); res = follow_path(&dj, path); /* Follow the file path */ if (res == FR_OK) { /* Follow completed */ if (dj.fn[NSFLAG] & NS_NONAME) { /* It is origin directory */ @@ -4751,9 +4939,10 @@ FRESULT f_stat ( if (fno) get_fileinfo(&dj, fno); } } - FREE_NAMBUF(); + FREE_NAMEBUFF(); } + if (fno && res != FR_OK) fno->fname[0] = 0; /* Invalidate the file information if an error occured */ LEAVE_FF(dj.obj.fs, res); } @@ -4761,13 +4950,13 @@ FRESULT f_stat ( #if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ -/* Get Number of Free Clusters */ +/* API: Get Number of Free Clusters */ /*-----------------------------------------------------------------------*/ FRESULT f_getfree ( const TCHAR* path, /* Logical drive number */ DWORD* nclst, /* Pointer to a variable to return number of free clusters */ - FATFS** fatfs /* Pointer to return pointer to corresponding filesystem object */ + FATFS** fatfs /* Pointer to a pointer to return corresponding filesystem object */ ) { FRESULT res; @@ -4778,22 +4967,27 @@ FRESULT f_getfree ( FFOBJID obj; - /* Get logical drive */ + /* Get logical drive and mount the volume if needed */ 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 */ if (fs->free_clst <= fs->n_fatent - 2) { *nclst = fs->free_clst; } else { - /* Scan FAT to obtain number of free clusters */ + /* Scan FAT to obtain the correct free cluster count */ nfree = 0; if (fs->fs_type == FS_FAT12) { /* FAT12: Scan bit field FAT entries */ clst = 2; obj.fs = fs; do { stat = get_fat(&obj, clst); - if (stat == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } - if (stat == 1) { res = FR_INT_ERR; break; } + if (stat == 0xFFFFFFFF) { + res = FR_DISK_ERR; break; + } + if (stat == 1) { + res = FR_INT_ERR; break; + } if (stat == 0) nfree++; } while (++clst < fs->n_fatent); } else { @@ -4805,16 +4999,16 @@ FRESULT f_getfree ( clst = fs->n_fatent - 2; /* Number of clusters */ sect = fs->bitbase; /* Bitmap sector */ i = 0; /* Offset in the sector */ - do { /* Counts numbuer of bits with zero in the bitmap */ - if (i == 0) { + do { /* Counts numbuer of clear bits (free clusters) in the bitmap */ + if (i == 0) { /* New sector? */ res = move_window(fs, sect++); if (res != FR_OK) break; } - for (b = 8, bm = fs->win[i]; b && clst; b--, clst--) { - if (!(bm & 1)) nfree++; + for (b = 8, bm = ~fs->win[i]; b && clst; b--, clst--) { /* Count clear bits in a byte */ + nfree += bm & 1; bm >>= 1; } - i = (i + 1) % SS(fs); + i = (i + 1) % SS(fs); /* Next byte */ } while (clst); } else #endif @@ -4823,16 +5017,16 @@ FRESULT f_getfree ( sect = fs->fatbase; /* Top of the FAT */ i = 0; /* Offset in the sector */ do { /* Counts numbuer of entries with zero in the FAT */ - if (i == 0) { + if (i == 0) { /* New sector? */ res = move_window(fs, sect++); if (res != FR_OK) break; } if (fs->fs_type == FS_FAT16) { - if (ld_word(fs->win + i) == 0) nfree++; - i += 2; + if (ld_16(fs->win + i) == 0) nfree++; /* FAT16: Is this cluster free? */ + i += 2; /* Next entry */ } else { - if ((ld_dword(fs->win + i) & 0x0FFFFFFF) == 0) nfree++; - i += 4; + if ((ld_32(fs->win + i) & 0x0FFFFFFF) == 0) nfree++; /* FAT32: Is this cluster free? */ + i += 4; /* Next entry */ } i %= SS(fs); } while (--clst); @@ -4840,8 +5034,8 @@ FRESULT f_getfree ( } if (res == FR_OK) { /* Update parameters if succeeded */ *nclst = nfree; /* Return the free clusters */ - fs->free_clst = nfree; /* Now free_clst is valid */ - fs->fsi_flag |= 1; /* FAT32: FSInfo is to be updated */ + fs->free_clst = nfree; /* Now free cluster count is valid */ + fs->fsi_flag |= 1; /* FAT32/exfAT : Allocation information is to be updated */ } } } @@ -4853,7 +5047,7 @@ FRESULT f_getfree ( /*-----------------------------------------------------------------------*/ -/* Truncate File */ +/* API: Truncate File */ /*-----------------------------------------------------------------------*/ FRESULT f_truncate ( @@ -4865,7 +5059,8 @@ FRESULT f_truncate ( DWORD ncl; - res = validate(&fp->obj, &fs); /* Check validity of the file object */ + /* Check validity of the file object */ + res = validate(&fp->obj, &fs); if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ @@ -4903,7 +5098,7 @@ FRESULT f_truncate ( /*-----------------------------------------------------------------------*/ -/* Delete a File/Directory */ +/* API: Delete a File/Directory */ /*-----------------------------------------------------------------------*/ FRESULT f_unlink ( @@ -4911,83 +5106,78 @@ FRESULT f_unlink ( ) { FRESULT res; + FATFS *fs; DIR dj, sdj; DWORD dclst = 0; - FATFS *fs; #if FF_FS_EXFAT FFOBJID obj; #endif - DEF_NAMBUF - + DEF_NAMEBUFF - /* Get logical drive */ + /* Get logical drive and mount the volume if needed */ res = mount_volume(&path, &fs, FA_WRITE); if (res == FR_OK) { dj.obj.fs = fs; - INIT_NAMBUF(fs); - res = follow_path(&dj, path); /* Follow the file path */ - if (FF_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) { - res = FR_INVALID_NAME; /* Cannot remove dot entry */ - } -#if FF_FS_LOCK != 0 - if (res == FR_OK) res = chk_lock(&dj, 2); /* Check if it is an open object */ -#endif - if (res == FR_OK) { /* The object is accessible */ - if (dj.fn[NSFLAG] & NS_NONAME) { - res = FR_INVALID_NAME; /* Cannot remove the origin directory */ + INIT_NAMEBUFF(fs); + res = follow_path(&dj, path); /* Follow the path to the object */ + if (res == FR_OK) { + if (dj.fn[NSFLAG] & (NS_DOT | NS_NONAME)) { + res = FR_INVALID_NAME; /* It must be a real object */ + } else if (dj.obj.attr & AM_RDO) { + res = FR_DENIED; /* The object must not be read-only */ +#if FF_FS_LOCK } else { - if (dj.obj.attr & AM_RDO) { - res = FR_DENIED; /* Cannot remove R/O object */ - } + res = chk_share(&dj, 2); /* Check if the object is in use */ +#endif } - if (res == FR_OK) { + } + if (res == FR_OK) { /* The object is accessible */ #if FF_FS_EXFAT - obj.fs = fs; - if (fs->fs_type == FS_EXFAT) { - init_alloc_info(fs, &obj); - dclst = obj.sclust; + obj.fs = fs; + if (fs->fs_type == FS_EXFAT) { + init_alloc_info(&obj, 0); + dclst = obj.sclust; + } else +#endif + { + dclst = ld_clust(fs, dj.dir); + } + if (dj.obj.attr & AM_DIR) { /* Is the object a sub-directory? */ +#if FF_FS_RPATH + if (dclst == fs->cdir) { + res = FR_DENIED; /* Current directory cannot be removed */ } else #endif { - dclst = ld_clust(fs, dj.dir); - } - if (dj.obj.attr & AM_DIR) { /* Is it a sub-directory? */ -#if FF_FS_RPATH != 0 - if (dclst == fs->cdir) { /* Is it the current directory? */ - res = FR_DENIED; - } else -#endif - { - sdj.obj.fs = fs; /* Open the sub-directory */ - sdj.obj.sclust = dclst; + sdj.obj.fs = fs; /* Open the sub-directory */ + sdj.obj.sclust = dclst; #if FF_FS_EXFAT - if (fs->fs_type == FS_EXFAT) { - sdj.obj.objsize = obj.objsize; - sdj.obj.stat = obj.stat; - } + if (fs->fs_type == FS_EXFAT) { + sdj.obj.objsize = obj.objsize; + sdj.obj.stat = obj.stat; + } #endif - res = dir_sdi(&sdj, 0); - if (res == FR_OK) { - res = DIR_READ_FILE(&sdj); /* Test if the directory is empty */ - if (res == FR_OK) res = FR_DENIED; /* Not empty? */ - if (res == FR_NO_FILE) res = FR_OK; /* Empty? */ - } + res = dir_sdi(&sdj, 0); + if (res == FR_OK) { + res = DIR_READ_FILE(&sdj); /* Check if the sub-directory is empty */ + if (res == FR_OK) res = FR_DENIED; /* Not empty? */ + if (res == FR_NO_FILE) res = FR_OK; /* Empty? */ } } } - if (res == FR_OK) { - res = dir_remove(&dj); /* Remove the directory entry */ - if (res == FR_OK && dclst != 0) { /* Remove the cluster chain if exist */ + } + if (res == FR_OK) { /* It is ready to remove the object */ + res = dir_remove(&dj); /* Remove the directory entry */ + if (res == FR_OK && dclst != 0) { /* Remove the cluster chain if exist */ #if FF_FS_EXFAT - res = remove_chain(&obj, dclst, 0); + res = remove_chain(&obj, dclst, 0); #else - res = remove_chain(&dj.obj, dclst, 0); + res = remove_chain(&dj.obj, dclst, 0); #endif - } - if (res == FR_OK) res = sync_fs(fs); } + if (res == FR_OK) res = sync_fs(fs); } - FREE_NAMBUF(); + FREE_NAMEBUFF(); } LEAVE_FF(fs, res); @@ -4997,7 +5187,7 @@ FRESULT f_unlink ( /*-----------------------------------------------------------------------*/ -/* Create a Directory */ +/* API: Create a Directory */ /*-----------------------------------------------------------------------*/ FRESULT f_mkdir ( @@ -5005,24 +5195,23 @@ FRESULT f_mkdir ( ) { FRESULT res; + FATFS *fs; DIR dj; FFOBJID sobj; - FATFS *fs; DWORD dcl, pcl, tm; - DEF_NAMBUF + DEF_NAMEBUFF - res = mount_volume(&path, &fs, FA_WRITE); /* Get logical drive */ + res = mount_volume(&path, &fs, FA_WRITE); /* Get logical drive and mount the volume if needed */ if (res == FR_OK) { dj.obj.fs = fs; - INIT_NAMBUF(fs); + INIT_NAMEBUFF(fs); res = follow_path(&dj, path); /* Follow the file path */ - if (res == FR_OK) res = FR_EXIST; /* Name collision? */ - if (FF_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) { /* Invalid name? */ - res = FR_INVALID_NAME; + if (res == FR_OK) { /* Invalid name or name collision */ + res = (dj.fn[NSFLAG] & (NS_DOT | NS_NONAME)) ? FR_INVALID_NAME : FR_EXIST; } if (res == FR_NO_FILE) { /* It is clear to create a new directory */ - sobj.fs = fs; /* New object id to create a new chain */ + sobj.fs = fs; /* New object ID to create a new chain */ dcl = create_chain(&sobj, 0); /* Allocate a cluster for the new directory */ res = FR_OK; if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster? */ @@ -5030,36 +5219,38 @@ FRESULT f_mkdir ( if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR; /* Disk error? */ tm = GET_FATTIME(); if (res == FR_OK) { - res = dir_clear(fs, dcl); /* Clean up the new table */ + res = dir_clear(fs, dcl); /* Clear the allocated cluster as new direcotry table */ if (res == FR_OK) { if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { /* Create dot entries (FAT only) */ memset(fs->win + DIR_Name, ' ', 11); /* Create "." entry */ fs->win[DIR_Name] = '.'; fs->win[DIR_Attr] = AM_DIR; - st_dword(fs->win + DIR_ModTime, tm); + st_32(fs->win + DIR_ModTime, tm); st_clust(fs, fs->win, dcl); memcpy(fs->win + SZDIRE, fs->win, SZDIRE); /* Create ".." entry */ fs->win[SZDIRE + 1] = '.'; pcl = dj.obj.sclust; st_clust(fs, fs->win + SZDIRE, pcl); fs->wflag = 1; } - res = dir_register(&dj); /* Register the object to the parent directoy */ + res = dir_register(&dj); /* Register the object to the parent directory */ } } if (res == FR_OK) { #if FF_FS_EXFAT 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)); /* 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 */ + st_32(fs->dirbuf + XDIR_CrtTime, tm); /* Created time */ + st_32(fs->dirbuf + XDIR_ModTime, tm); + st_32(fs->dirbuf + XDIR_FstClus, dcl); /* Table start cluster */ + st_32(fs->dirbuf + XDIR_FileSize, (DWORD)fs->csize * SS(fs)); /* Directory size needs to be valid */ + st_32(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 */ res = store_xdir(&dj); } else #endif { - st_dword(dj.dir + DIR_ModTime, tm); /* Created time */ + st_32(dj.dir + DIR_CrtTime, tm); /* Created time */ + st_32(dj.dir + DIR_ModTime, tm); st_clust(fs, dj.dir, dcl); /* Table start cluster */ dj.dir[DIR_Attr] = AM_DIR; /* Attribute */ fs->wflag = 1; @@ -5071,7 +5262,7 @@ FRESULT f_mkdir ( remove_chain(&sobj, dcl, 0); /* Could not register, remove the allocated cluster */ } } - FREE_NAMBUF(); + FREE_NAMEBUFF(); } LEAVE_FF(fs, res); @@ -5081,7 +5272,7 @@ FRESULT f_mkdir ( /*-----------------------------------------------------------------------*/ -/* Rename a File/Directory */ +/* API: Rename a File/Directory */ /*-----------------------------------------------------------------------*/ FRESULT f_rename ( @@ -5090,45 +5281,58 @@ FRESULT f_rename ( ) { FRESULT res; - DIR djo, djn; FATFS *fs; + DIR djo, djn; BYTE buf[FF_FS_EXFAT ? SZDIRE * 2 : SZDIRE], *dir; - LBA_t sect; - DEF_NAMBUF + DEF_NAMEBUFF - get_ldnumber(&path_new); /* Snip the drive number of new name off */ + get_ldnumber(&path_new); /* Snip the drive number of new name off */ 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); - res = follow_path(&djo, path_old); /* Check old object */ - if (res == FR_OK && (djo.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check validity of name */ -#if FF_FS_LOCK != 0 + INIT_NAMEBUFF(fs); + res = follow_path(&djo, path_old); /* Check old object */ if (res == FR_OK) { - res = chk_lock(&djo, 2); - } + if (djo.fn[NSFLAG] & (NS_DOT | NS_NONAME)) { + res = FR_INVALID_NAME; /* Object must not be a dot name or blank name */ +#if FF_FS_LOCK + } else { + res = chk_share(&djo, 2); /* Check if the object is in use */ #endif - if (res == FR_OK) { /* Object to be renamed is found */ + } + } + if (res == FR_OK) { /* It is ready to rename the object */ #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* At exFAT volume */ - BYTE nf, nn; - WORD nh; +#if FF_FS_RPATH + UINT i; + DWORD dscl = ld_32(fs->dirbuf + XDIR_FstClus); - memcpy(buf, fs->dirbuf, SZDIRE * 2); /* Save 85+C0 entry of old object */ - memcpy(&djn, &djo, sizeof djo); - res = follow_path(&djn, path_new); /* Make sure if new object name is not in use */ - if (res == FR_OK) { /* Is new name already in use by any other object? */ + for (i = 1; i <= fs->xcwds.depth && dscl != fs->xcwds.tbl[i].d_scl; i++) ; /* Check if the object is a sub-dir in the current dir path */ + if (i <= fs->xcwds.depth) { + res = FR_DENIED; /* Reject to rename a sub-dir in the current dir path */ + } else +#endif + { + memcpy(buf, fs->dirbuf, SZDIRE * 2); /* Save 85+C0 entry of old object */ + memcpy(&djn, &djo, sizeof djn); + res = follow_path(&djn, path_new); /* Check if new object name collides with an existing one */ + } + if (res == FR_OK) { /* Is new name already in use by another object? */ res = (djn.obj.sclust == djo.obj.sclust && djn.dptr == djo.dptr) ? FR_NO_FILE : FR_EXIST; } - if (res == FR_NO_FILE) { /* It is a valid path and no name collision */ - res = dir_register(&djn); /* Register the new entry */ + if (res == FR_NO_FILE) { /* It is a valid path and no name collision */ + res = dir_register(&djn); /* Register the new entry */ if (res == FR_OK) { - nf = fs->dirbuf[XDIR_NumSec]; nn = fs->dirbuf[XDIR_NumName]; - nh = ld_word(fs->dirbuf + XDIR_NameHash); + BYTE nf, nn; + WORD nh; + + nf = fs->dirbuf[XDIR_NumSec]; nn = fs->dirbuf[XDIR_NumName]; /* Save name length and hash */ + nh = ld_16(fs->dirbuf + XDIR_NameHash); memcpy(fs->dirbuf, buf, SZDIRE * 2); /* Restore 85+C0 entry */ - fs->dirbuf[XDIR_NumSec] = nf; fs->dirbuf[XDIR_NumName] = nn; - st_word(fs->dirbuf + XDIR_NameHash, nh); + fs->dirbuf[XDIR_NumSec] = nf; fs->dirbuf[XDIR_NumName] = nn; /* Restore name length and hash */ + st_16(fs->dirbuf + XDIR_NameHash, nh); if (!(fs->dirbuf[XDIR_Attr] & AM_DIR)) fs->dirbuf[XDIR_Attr] |= AM_ARC; /* Set archive attribute if it is a file */ /* Start of critical section where an interruption can cause a cross-link */ res = store_xdir(&djn); @@ -5138,9 +5342,9 @@ FRESULT f_rename ( #endif { /* At FAT/FAT32 volume */ memcpy(buf, djo.dir, SZDIRE); /* Save directory entry of the object */ - memcpy(&djn, &djo, sizeof (DIR)); /* Duplicate the directory object */ + memcpy(&djn, &djo, sizeof djn); /* Duplicate the directory object */ res = follow_path(&djn, path_new); /* Make sure if new object name is not in use */ - if (res == FR_OK) { /* Is new name already in use by any other object? */ + if (res == FR_OK) { /* Is new name already in use by another object? */ res = (djn.obj.sclust == djo.obj.sclust && djn.dptr == djo.dptr) ? FR_NO_FILE : FR_EXIST; } if (res == FR_NO_FILE) { /* It is a valid path and no name collision */ @@ -5151,14 +5355,15 @@ FRESULT f_rename ( dir[DIR_Attr] = buf[DIR_Attr]; 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 */ - sect = clst2sect(fs, ld_clust(fs, dir)); + if ((dir[DIR_Attr] & AM_DIR) && djo.obj.sclust != djn.obj.sclust) { /* Update .. entry in the sub-directory being moved if needed */ + LBA_t 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, sect); - dir = fs->win + SZDIRE * 1; /* Ptr to .. entry */ + dir = fs->win + SZDIRE * 1; /* Pointer to .. entry */ if (res == FR_OK && dir[1] == '.') { st_clust(fs, dir, djn.obj.sclust); fs->wflag = 1; @@ -5168,15 +5373,15 @@ FRESULT f_rename ( } } } - if (res == FR_OK) { - res = dir_remove(&djo); /* Remove old entry */ + if (res == FR_OK) { /* New entry has been created */ + res = dir_remove(&djo); /* Remove old entry */ if (res == FR_OK) { res = sync_fs(fs); } } /* End of the critical section */ } - FREE_NAMBUF(); + FREE_NAMEBUFF(); } LEAVE_FF(fs, res); @@ -5191,25 +5396,27 @@ FRESULT f_rename ( #if FF_USE_CHMOD && !FF_FS_READONLY /*-----------------------------------------------------------------------*/ -/* Change Attribute */ +/* API: Change Attribute */ /*-----------------------------------------------------------------------*/ FRESULT f_chmod ( const TCHAR* path, /* Pointer to the file path */ - BYTE attr, /* Attribute bits */ + BYTE attr, /* Attribute bits to set/clear */ BYTE mask /* Attribute mask to change */ ) { FRESULT res; - DIR dj; FATFS *fs; - DEF_NAMBUF + DIR dj; + DEF_NAMEBUFF - res = mount_volume(&path, &fs, FA_WRITE); /* Get logical drive */ + /* Get logical drive and mount the volume if needed */ + res = mount_volume(&path, &fs, FA_WRITE); + if (res == FR_OK) { dj.obj.fs = fs; - INIT_NAMBUF(fs); + INIT_NAMEBUFF(fs); res = follow_path(&dj, path); /* Follow the file path */ if (res == FR_OK && (dj.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check object validity */ if (res == FR_OK) { @@ -5228,7 +5435,7 @@ FRESULT f_chmod ( res = sync_fs(fs); } } - FREE_NAMBUF(); + FREE_NAMEBUFF(); } LEAVE_FF(fs, res); @@ -5238,42 +5445,63 @@ FRESULT f_chmod ( /*-----------------------------------------------------------------------*/ -/* Change Timestamp */ +/* API: Change Timestamp */ /*-----------------------------------------------------------------------*/ FRESULT f_utime ( const TCHAR* path, /* Pointer to the file/directory name */ - const FILINFO* fno /* Pointer to the timestamp to be set */ + const FILINFO* fno /* Timestamp to be set */ ) { FRESULT res; - DIR dj; FATFS *fs; - DEF_NAMBUF + DIR dj; + DEF_NAMEBUFF - res = mount_volume(&path, &fs, FA_WRITE); /* Get logical drive */ + /* Get logical drive and mount the volume if needed */ + res = mount_volume(&path, &fs, FA_WRITE); + if (res == FR_OK) { dj.obj.fs = fs; - INIT_NAMBUF(fs); + INIT_NAMEBUFF(fs); res = follow_path(&dj, path); /* Follow the file path */ if (res == FR_OK && (dj.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check object validity */ if (res == FR_OK) { #if FF_FS_EXFAT - if (fs->fs_type == FS_EXFAT) { - st_dword(fs->dirbuf + XDIR_ModTime, (DWORD)fno->fdate << 16 | fno->ftime); + if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ + if (fno->fdate) { /* Change last modified time if needed */ + st_32(fs->dirbuf + XDIR_ModTime, (DWORD)fno->fdate << 16 | fno->ftime); + fs->dirbuf[XDIR_ModTime10] = 0; + fs->dirbuf[XDIR_ModTZ] = 0; + } +#if FF_FS_CRTIME + if (fno->crdate) { /* Change created time if needed */ + st_32(fs->dirbuf + XDIR_CrtTime, (DWORD)fno->crdate << 16 | fno->crtime); + fs->dirbuf[XDIR_CrtTime10] = 0; + fs->dirbuf[XDIR_CrtTZ] = 0; + } +#endif res = store_xdir(&dj); } else #endif - { - st_dword(dj.dir + DIR_ModTime, (DWORD)fno->fdate << 16 | fno->ftime); + { /* On the FAT volume */ + if (fno->fdate) { /* Change last modified time if needed */ + st_32(dj.dir + DIR_ModTime, (DWORD)fno->fdate << 16 | fno->ftime); + } +#if FF_FS_CRTIME + if (fno->crdate) { /* Change created time if needed */ + st_32(dj.dir + DIR_CrtTime, (DWORD)fno->crdate << 16 | fno->crtime); + dj.dir[DIR_CrtTime10] = 0; + } +#endif fs->wflag = 1; } if (res == FR_OK) { res = sync_fs(fs); } } - FREE_NAMBUF(); + FREE_NAMEBUFF(); } LEAVE_FF(fs, res); @@ -5285,7 +5513,7 @@ FRESULT f_utime ( #if FF_USE_LABEL /*-----------------------------------------------------------------------*/ -/* Get Volume Label */ +/* API: Get Volume Label */ /*-----------------------------------------------------------------------*/ FRESULT f_getlabel ( @@ -5295,13 +5523,13 @@ FRESULT f_getlabel ( ) { FRESULT res; - DIR dj; FATFS *fs; + DIR dj; UINT si, di; WCHAR wc; - /* Get logical drive */ - res = mount_volume(&path, &fs, 0); + + res = mount_volume(&path, &fs, 0); /* Get logical drive and mount the volume if needed */ /* Get volume label */ if (res == FR_OK && label) { @@ -5316,12 +5544,14 @@ FRESULT f_getlabel ( UINT nw; for (si = di = hs = 0; si < dj.dir[XDIR_NumLabel]; si++) { /* Extract volume label from 83 entry */ - wc = ld_word(dj.dir + XDIR_Label + si * 2); + wc = ld_16(dj.dir + XDIR_Label + si * 2); if (hs == 0 && IsSurrogate(wc)) { /* Is the code a surrogate? */ hs = wc; continue; } nw = put_utf((DWORD)hs << 16 | wc, &label[di], 4); /* Store it in API encoding */ - if (nw == 0) { di = 0; break; } /* Encode error? */ + if (nw == 0) { /* Encode error? */ + di = 0; break; + } di += nw; hs = 0; } @@ -5336,7 +5566,9 @@ FRESULT f_getlabel ( #if FF_USE_LFN && FF_LFN_UNICODE >= 1 /* Unicode output */ if (dbc_1st((BYTE)wc) && si < 11) wc = wc << 8 | dj.dir[si++]; /* Is it a DBC? */ wc = ff_oem2uni(wc, CODEPAGE); /* Convert it into Unicode */ - if (wc == 0) { di = 0; break; } /* Invalid char in current code page? */ + if (wc == 0) { /* Invalid char in current code page? */ + di = 0; break; + } di += put_utf(wc, &label[di], 4); /* Store it in Unicode */ #else /* ANSI/OEM output */ label[di++] = (TCHAR)wc; @@ -5357,7 +5589,7 @@ FRESULT f_getlabel ( /* Get volume serial number */ if (res == FR_OK && vsn) { - res = move_window(fs, fs->volbase); + res = move_window(fs, fs->volbase); /* Load VBR */ if (res == FR_OK) { switch (fs->fs_type) { case FS_EXFAT: @@ -5368,10 +5600,10 @@ FRESULT f_getlabel ( di = BS_VolID32; break; - default: - di = BS_VolID; + default: /* FAT12/16 */ + di = fs->win[BS_BootSig] == 0x29 ? BS_VolID : 0; } - *vsn = ld_dword(fs->win + di); + *vsn = di ? ld_32(fs->win + di) : 0; /* Get VSN in the VBR */ } } @@ -5382,7 +5614,7 @@ FRESULT f_getlabel ( #if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ -/* Set Volume Label */ +/* API: Set Volume Label */ /*-----------------------------------------------------------------------*/ FRESULT f_setlabel ( @@ -5390,8 +5622,8 @@ FRESULT f_setlabel ( ) { FRESULT res; - DIR dj; FATFS *fs; + DIR dj; BYTE dirvn[22]; UINT di; WCHAR wc; @@ -5400,9 +5632,12 @@ FRESULT f_setlabel ( DWORD dc; #endif - /* Get logical drive */ + /* Get logical drive and mount the volume if needed */ res = mount_volume(&label, &fs, FA_WRITE); if (res != FR_OK) LEAVE_FF(fs, res); +#if FF_STR_VOLUME_ID == 2 + for ( ; *label == '/'; label++) ; /* Snip the separators off */ +#endif #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ @@ -5414,13 +5649,13 @@ FRESULT f_setlabel ( if (dc == 0xFFFFFFFF || di >= 10) { /* Wrong surrogate or buffer overflow */ dc = 0; } else { - st_word(dirvn + di * 2, (WCHAR)(dc >> 16)); di++; + st_16(dirvn + di * 2, (WCHAR)(dc >> 16)); di++; } } if (dc == 0 || strchr(&badchr[7], (int)dc) || di >= 11) { /* Check validity of the volume label */ LEAVE_FF(fs, FR_INVALID_NAME); } - st_word(dirvn + di * 2, (WCHAR)dc); di++; + st_16(dirvn + di * 2, (WCHAR)dc); di++; } } else #endif @@ -5502,7 +5737,7 @@ FRESULT f_setlabel ( #if FF_USE_EXPAND && !FF_FS_READONLY /*-----------------------------------------------------------------------*/ -/* Allocate a Contiguous Blocks to the File */ +/* API: Allocate a Contiguous Blocks to the File */ /*-----------------------------------------------------------------------*/ FRESULT f_expand ( @@ -5547,14 +5782,20 @@ FRESULT f_expand ( for (;;) { /* Find a contiguous cluster block */ n = get_fat(&fp->obj, clst); if (++clst >= fs->n_fatent) clst = 2; - if (n == 1) { res = FR_INT_ERR; break; } - if (n == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } + if (n == 1) { + res = FR_INT_ERR; break; + } + if (n == 0xFFFFFFFF) { + res = FR_DISK_ERR; break; + } if (n == 0) { /* Is it a free cluster? */ if (++ncl == tcl) break; /* Break if a contiguous cluster block is found */ } else { scl = clst; ncl = 0; /* Not a free cluster */ } - if (clst == stcl) { res = FR_DENIED; break; } /* No contiguous cluster? */ + if (clst == stcl) { /* No contiguous cluster? */ + res = FR_DENIED; break; + } } if (res == FR_OK) { /* A contiguous free area is found */ if (opt) { /* Allocate it now */ @@ -5592,7 +5833,7 @@ FRESULT f_expand ( #if FF_USE_FORWARD /*-----------------------------------------------------------------------*/ -/* Forward Data to the Stream Directly */ +/* API: Forward Data to the Stream Directly */ /*-----------------------------------------------------------------------*/ FRESULT f_forward ( @@ -5663,12 +5904,12 @@ FRESULT f_forward ( #if !FF_FS_READONLY && FF_USE_MKFS /*-----------------------------------------------------------------------*/ -/* Create FAT/exFAT volume (with sub-functions) */ +/* API: Create FAT/exFAT volume (with a sub-function) */ /*-----------------------------------------------------------------------*/ #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) */ +#define GPT_ITEMS 128 /* Number of GPT table items (>=128, sector aligned) */ /* Create partitions on the physical drive in format of MBR or GPT */ @@ -5676,8 +5917,8 @@ FRESULT f_forward ( static FRESULT create_partition ( BYTE drv, /* Physical drive number */ const LBA_t plst[], /* Partition list */ - BYTE sys, /* System ID (for only MBR, temp setting) */ - BYTE* buf /* Working buffer for a sector */ + BYTE sys, /* System ID for each partition (for only MBR) */ + BYTE *buf /* Working buffer for a sector */ ) { UINT i, cy; @@ -5706,19 +5947,19 @@ static FRESULT create_partition ( rnd = (DWORD)sz_drv + GET_FATTIME(); /* Random seed */ align = GPT_ALIGN / ss; /* Partition alignment for GPT [sector] */ sz_ptbl = GPT_ITEMS * SZ_GPTE / ss; /* Size of partition table [sector] */ - top_bpt = sz_drv - sz_ptbl - 1; /* Backup partiiton table start sector */ - nxt_alloc = 2 + sz_ptbl; /* First allocatable sector */ - sz_pool = top_bpt - nxt_alloc; /* Size of allocatable area */ + top_bpt = sz_drv - sz_ptbl - 1; /* Backup partition table start LBA */ + nxt_alloc = 2 + sz_ptbl; /* First allocatable LBA */ + sz_pool = top_bpt - nxt_alloc; /* Size of allocatable area [sector] */ bcc = 0xFFFFFFFF; sz_part = 1; - pi = si = 0; /* partition table index, size table index */ + pi = si = 0; /* partition table index, map index */ do { if (pi * SZ_GPTE % ss == 0) memset(buf, 0, ss); /* Clean the buffer if needed */ if (sz_part != 0) { /* Is the size table not termintated? */ - nxt_alloc = (nxt_alloc + align - 1) & ((QWORD)0 - align); /* Align partition start */ + nxt_alloc = (nxt_alloc + align - 1) & ((QWORD)0 - align); /* Align partition start LBA */ sz_part = plst[si++]; /* Get a partition size */ if (sz_part <= 100) { /* Is the size in percentage? */ - sz_part = sz_pool * sz_part / 100; - sz_part = (sz_part + align - 1) & ((QWORD)0 - align); /* Align partition end (only if in percentage) */ + sz_part = sz_pool * sz_part / 100; /* Sectors in percentage */ + sz_part = (sz_part + align - 1) & ((QWORD)0 - align); /* Align partition end LBA (only if in percentage) */ } if (nxt_alloc + sz_part > top_bpt) { /* Clip the size at end of the pool */ sz_part = (nxt_alloc < top_bpt) ? top_bpt - nxt_alloc : 0; @@ -5728,11 +5969,11 @@ static FRESULT create_partition ( ofs = pi * SZ_GPTE % ss; memcpy(buf + ofs + GPTE_PtGuid, GUID_MS_Basic, 16); /* Set partition GUID (Microsoft Basic Data) */ rnd = make_rand(rnd, buf + ofs + GPTE_UpGuid, 16); /* Set unique partition GUID */ - st_qword(buf + ofs + GPTE_FstLba, nxt_alloc); /* Set partition start sector */ - st_qword(buf + ofs + GPTE_LstLba, nxt_alloc + sz_part - 1); /* Set partition end sector */ - nxt_alloc += sz_part; /* Next allocatable sector */ + st_64(buf + ofs + GPTE_FstLba, nxt_alloc); /* Set partition start LBA */ + st_64(buf + ofs + GPTE_LstLba, nxt_alloc + sz_part - 1); /* Set partition end LBA */ + nxt_alloc += sz_part; /* Next allocatable LBA */ } - if ((pi + 1) * SZ_GPTE % ss == 0) { /* Write the buffer if it is filled up */ + if ((pi + 1) * SZ_GPTE % ss == 0) { /* Write the sector 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; /* Write to primary table */ if (disk_write(drv, buf, top_bpt + pi * SZ_GPTE / ss, 1) != RES_OK) return FR_DISK_ERR; /* Write to secondary table */ @@ -5742,32 +5983,32 @@ static FRESULT create_partition ( /* Create primary GPT header */ memset(buf, 0, ss); memcpy(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 secondary header */ - st_qword(buf + GPTH_FstLba, 2 + sz_ptbl); /* LBA of first allocatable sector */ - st_qword(buf + GPTH_LstLba, top_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 */ + st_32(buf + GPTH_PtBcc, ~bcc); /* Table check sum */ + st_64(buf + GPTH_CurLba, 1); /* LBA of this header */ + st_64(buf + GPTH_BakLba, sz_drv - 1); /* LBA of secondary header */ + st_64(buf + GPTH_FstLba, 2 + sz_ptbl); /* LBA of first allocatable sector */ + st_64(buf + GPTH_LstLba, top_bpt - 1); /* LBA of last allocatable sector */ + st_32(buf + GPTH_PteSize, SZ_GPTE); /* Size of a table entry */ + st_32(buf + GPTH_PtNum, GPT_ITEMS); /* Number of table entries */ + st_32(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 */ + st_32(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 primary header */ - st_qword(buf + GPTH_PtOfs, top_bpt); /* LBA of this table */ - st_dword(buf + GPTH_Bcc, 0); + st_64(buf + GPTH_CurLba, sz_drv - 1); /* LBA of this header */ + st_64(buf + GPTH_BakLba, 1); /* LBA of primary header */ + st_64(buf + GPTH_PtOfs, top_bpt); /* LBA of this table */ + st_32(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 */ + st_32(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 */ memset(buf, 0, ss); - memcpy(buf + MBR_Table, gpt_mbr, 16); /* Create a GPT partition */ - st_word(buf + BS_55AA, 0xAA55); + memcpy(buf + MBR_Table, gpt_mbr, 16); /* Create a GPT partition */ + st_16(buf + BS_55AA, 0xAA55); if (disk_write(drv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; } else @@ -5786,20 +6027,20 @@ static FRESULT create_partition ( if (nxt_alloc32 + sz_part32 > sz_drv32 || nxt_alloc32 + sz_part32 < nxt_alloc32) sz_part32 = sz_drv32 - nxt_alloc32; /* Clip at drive size */ if (sz_part32 == 0) break; /* End of table or no sector to allocate? */ - st_dword(pte + PTE_StLba, nxt_alloc32); /* Start LBA */ - st_dword(pte + PTE_SizLba, sz_part32); /* Number of sectors */ + st_32(pte + PTE_StLba, nxt_alloc32); /* Partition start LBA sector */ + st_32(pte + PTE_SizLba, sz_part32); /* Size of partition [sector] */ pte[PTE_System] = sys; /* System type */ - cy = (UINT)(nxt_alloc32 / n_sc / n_hd); /* Start cylinder */ - hd = (BYTE)(nxt_alloc32 / n_sc % n_hd); /* Start head */ - sc = (BYTE)(nxt_alloc32 % n_sc + 1); /* Start sector */ + cy = (UINT)(nxt_alloc32 / n_sc / n_hd); /* Partitio start CHS cylinder */ + hd = (BYTE)(nxt_alloc32 / n_sc % n_hd); /* Partition start CHS head */ + sc = (BYTE)(nxt_alloc32 % n_sc + 1); /* Partition start CHS sector */ pte[PTE_StHead] = hd; pte[PTE_StSec] = (BYTE)((cy >> 2 & 0xC0) | sc); pte[PTE_StCyl] = (BYTE)cy; - cy = (UINT)((nxt_alloc32 + sz_part32 - 1) / n_sc / n_hd); /* End cylinder */ - hd = (BYTE)((nxt_alloc32 + sz_part32 - 1) / n_sc % n_hd); /* End head */ - sc = (BYTE)((nxt_alloc32 + sz_part32 - 1) % n_sc + 1); /* End sector */ + cy = (UINT)((nxt_alloc32 + sz_part32 - 1) / n_sc / n_hd); /* Partition end CHS cylinder */ + hd = (BYTE)((nxt_alloc32 + sz_part32 - 1) / n_sc % n_hd); /* Partition end CHS head */ + sc = (BYTE)((nxt_alloc32 + sz_part32 - 1) % n_sc + 1); /* Partition end CHS sector */ pte[PTE_EdHead] = hd; pte[PTE_EdSec] = (BYTE)((cy >> 2 & 0xC0) | sc); pte[PTE_EdCyl] = (BYTE)cy; @@ -5807,7 +6048,7 @@ static FRESULT create_partition ( pte += SZ_PTE; /* Next entry */ } - st_word(buf + BS_55AA, 0xAA55); /* MBR signature */ + st_16(buf + BS_55AA, 0xAA55); /* MBR signature */ if (disk_write(drv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; /* Write it to the MBR */ } @@ -5819,46 +6060,51 @@ static FRESULT create_partition ( 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) */ + void* work, /* Pointer to working buffer (null: use len bytes of heap memory) */ UINT len /* Size of working buffer [byte] */ ) { - 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) */ + static const WORD cst[] = {1, 4, 16, 64, 256, 512, 0}; /* Cluster size boundary for FAT volume (4K sector unit) */ + static const WORD cst32[] = {1, 2, 4, 8, 16, 32, 0}; /* Cluster size boundary for FAT32 volume (128K sector unit) */ static const MKFS_PARM defopt = {FM_ANY, 0, 0, 0, 0}; /* Default parameter */ - BYTE fsopt, fsty, sys, *buf, *pte, pdrv, ipart; + BYTE fsopt, fsty, sys, pdrv, ipart; + BYTE *buf; + BYTE *pte; WORD ss; /* Sector size */ DWORD sz_buf, sz_blk, n_clst, pau, nsect, n, vsn; - LBA_t sz_vol, b_vol, b_fat, b_data; /* Size of volume, Base LBA of volume, fat, data */ + LBA_t sz_vol, b_vol, b_fat, b_data; /* Volume size, base LBA of volume, base LBA of FAT and base LBA of 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 */ + DWORD sz_rsv, sz_fat, sz_dir, sz_au; /* Size of reserved area, FAT area, directry area, data area and cluster */ + UINT n_fat, n_root, i; /* Number of FATs, number of roor directory entries and some index */ int vol; DSTATUS ds; - FRESULT fr; + FRESULT res; /* Check mounted drive and clear work area */ - vol = get_ldnumber(&path); /* Get target logical drive */ + vol = get_ldnumber(&path); /* Get logical drive number to be formatted */ if (vol < 0) return FR_INVALID_DRIVE; 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 */ + pdrv = LD2PD(vol); /* Hosting physical drive */ + ipart = LD2PT(vol); /* Hosting partition (0:create as new, 1..:existing partition) */ - /* Get physical drive status (sz_drv, sz_blk, ss) */ + /* Initialize the hosting physical drive */ ds = disk_initialize(pdrv); if (ds & STA_NOINIT) return FR_NOT_READY; if (ds & STA_PROTECT) return FR_WRITE_PROTECTED; + + /* Get physical drive parameters (sz_drv, sz_blk and ss) */ + if (!opt) opt = &defopt; /* Use default parameter if it is not given */ 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 (sz_blk == 0) disk_ioctl(pdrv, GET_BLOCK_SIZE, &sz_blk); /* Block size from the parameter or lower layer */ + if (sz_blk == 0 || sz_blk > 0x8000 || (sz_blk & (sz_blk - 1))) sz_blk = 1; /* Use default if the block size is invalid */ #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 + /* 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; @@ -5880,7 +6126,7 @@ FRESULT f_mkfs ( 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 */ + if (ld_16(buf + BS_55AA) != 0xAA55) LEAVE_MKFS(FR_MKFS_ABORTED); /* Check if MBR is valid */ #if FF_LBA64 if (buf[MBR_Table + PTE_System] == 0xEE) { /* GPT protective MBR? */ DWORD n_ent, ofs; @@ -5889,14 +6135,14 @@ FRESULT f_mkfs ( /* 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 */ + n_ent = ld_32(buf + GPTH_PtNum); /* Number of entries */ + pt_lba = ld_64(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 (!memcmp(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; + b_vol = ld_64(buf + ofs + GPTE_FstLba); + sz_vol = ld_64(buf + ofs + GPTE_LstLba) - b_vol + 1; break; } n_ent--; ofs = (ofs + SZ_GPTE) % ss; /* Next entry */ @@ -5908,8 +6154,8 @@ FRESULT f_mkfs ( { /* 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 */ + b_vol = ld_32(pte + PTE_StLba); /* Get volume start sector */ + sz_vol = ld_32(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); @@ -5928,13 +6174,13 @@ FRESULT f_mkfs ( } } } - if (sz_vol < 128) LEAVE_MKFS(FR_MKFS_ABORTED); /* Check if volume size is >=128s */ + if (sz_vol < 128) LEAVE_MKFS(FR_MKFS_ABORTED); /* Check if volume size is >=128 sectors */ /* Now start to create an 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 ? */ + if ((fsopt & FM_ANY) == FM_EXFAT || sz_vol >= 0x4000000 || sz_au > 128) { /* exFAT only, vol >= 64M sectors or sz_au > 128 sectors? */ fsty = FS_EXFAT; break; } } @@ -5951,7 +6197,7 @@ FRESULT f_mkfs ( fsty = FS_FAT16; } while (0); - vsn = (DWORD)sz_vol + GET_FATTIME(); /* VSN generated from current time and partitiion size */ + vsn = (DWORD)sz_vol + GET_FATTIME(); /* VSN generated from current time and partition size */ #if FF_FS_EXFAT if (fsty == FS_EXFAT) { /* Create an exFAT volume */ @@ -5974,7 +6220,7 @@ FRESULT f_mkfs ( 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 = (DWORD)(sz_vol - (b_data - b_vol)) / sz_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? */ @@ -6017,7 +6263,7 @@ FRESULT f_mkfs ( } } while (si); clen[1] = (szb_case + sz_au * ss - 1) / (sz_au * ss); /* Number of up-case table clusters */ - clen[2] = 1; /* Number of root dir clusters */ + clen[2] = 1; /* Number of root directory clusters */ /* Initialize the allocation bitmap */ sect = b_data; nsect = (szb_bit + ss - 1) / ss; /* Start of bitmap and number of bitmap sectors */ @@ -6036,12 +6282,13 @@ FRESULT f_mkfs ( do { memset(buf, 0, sz_buf * ss); i = 0; /* Clear work area and reset write offset */ if (clu == 0) { /* Initialize FAT [0] and FAT[1] */ - st_dword(buf + i, 0xFFFFFFF8); i += 4; clu++; - st_dword(buf + i, 0xFFFFFFFF); i += 4; clu++; + st_32(buf + i, 0xFFFFFFF8); i += 4; clu++; + st_32(buf + i, 0xFFFFFFFF); i += 4; clu++; } - do { /* Create chains of bitmap, up-case and root dir */ + + do { /* Create chains of bitmap, up-case and root directory */ while (nbit != 0 && i < sz_buf * ss) { /* Create a chain */ - st_dword(buf + i, (nbit > 1) ? clu + 1 : 0xFFFFFFFF); + st_32(buf + i, (nbit > 1) ? clu + 1 : 0xFFFFFFFF); i += 4; clu++; nbit--; } if (nbit == 0 && j < 3) nbit = clen[j++]; /* Get next chain length */ @@ -6053,14 +6300,14 @@ FRESULT f_mkfs ( /* Initialize the root directory */ memset(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 + clen[0]); /* cluster */ - st_dword(buf + SZDIRE * 2 + 24, szb_case); /* size */ + buf[SZDIRE * 0 + 0] = ET_VLABEL; /* Volume label entry (no label) */ + buf[SZDIRE * 1 + 0] = ET_BITMAP; /* Bitmap entry */ + st_32(buf + SZDIRE * 1 + 20, 2); /* cluster */ + st_32(buf + SZDIRE * 1 + 24, szb_bit); /* size */ + buf[SZDIRE * 2 + 0] = ET_UPCASE; /* Up-case table entry */ + st_32(buf + SZDIRE * 2 + 4, sum); /* sum */ + st_32(buf + SZDIRE * 2 + 20, 2 + clen[0]); /* cluster */ + st_32(buf + SZDIRE * 2 + 24, szb_case); /* size */ sect = b_data + sz_au * (clen[0] + clen[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; @@ -6075,28 +6322,28 @@ FRESULT f_mkfs ( /* Main record (+0) */ memset(buf, 0, ss); memcpy(buf + BS_JmpBoot, "\xEB\x76\x90" "EXFAT ", 11); /* Boot jump code (x86), OEM name */ - 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, (DWORD)(b_data - b_vol)); /* Data offset [sector] */ - st_dword(buf + BPB_NumClusEx, n_clst); /* Number of clusters */ - st_dword(buf + BPB_RootClusEx, 2 + clen[0] + clen[1]); /* Root dir cluster # */ - st_dword(buf + BPB_VolIDEx, vsn); /* 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] */ + st_64(buf + BPB_VolOfsEx, b_vol); /* Volume offset in the physical drive [sector] */ + st_64(buf + BPB_TotSecEx, sz_vol); /* Volume size [sector] */ + st_32(buf + BPB_FatOfsEx, (DWORD)(b_fat - b_vol)); /* FAT offset [sector] */ + st_32(buf + BPB_FatSzEx, sz_fat); /* FAT size [sector] */ + st_32(buf + BPB_DataOfsEx, (DWORD)(b_data - b_vol)); /* Data offset [sector] */ + st_32(buf + BPB_NumClusEx, n_clst); /* Number of clusters */ + st_32(buf + BPB_RootClusEx, 2 + clen[0] + clen[1]); /* Root directory cluster number */ + st_32(buf + BPB_VolIDEx, vsn); /* VSN */ + st_16(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 = 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) */ - st_word(buf + BS_55AA, 0xAA55); /* Signature (placed here regardless of sector size) */ + st_16(buf + BS_BootCodeEx, 0xFEEB); /* Boot code (x86) */ + st_16(buf + BS_55AA, 0xAA55); /* Signature (placed here regardless of sector size) */ for (i = sum = 0; i < ss; i++) { /* VBR checksum */ if (i != BPB_VolFlagEx && i != BPB_VolFlagEx + 1 && i != BPB_PercInUseEx) sum = xsum32(buf[i], sum); } if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Extended bootstrap record (+1..+8) */ memset(buf, 0, ss); - st_word(buf + ss - 2, 0xAA55); /* Signature (placed at end of sector) */ + st_16(buf + ss - 2, 0xAA55); /* Signature (placed at end of sector) */ for (j = 1; j < 9; j++) { for (i = 0; i < ss; sum = xsum32(buf[i++], sum)) ; /* VBR checksum */ if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); @@ -6108,7 +6355,7 @@ FRESULT f_mkfs ( if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); } /* Sum record (+11) */ - for (i = 0; i < ss; i += 4) st_dword(buf + i, sum); /* Fill with checksum value */ + for (i = 0; i < ss; i += 4) st_32(buf + i, sum); /* Fill with checksum value */ if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); } @@ -6142,7 +6389,7 @@ FRESULT f_mkfs ( } sz_fat = (n + ss - 1) / ss; /* FAT size [sector] */ sz_rsv = 1; /* Number of reserved sectors */ - sz_dir = (DWORD)n_root * SZDIRE / ss; /* Root dir size [sector] */ + sz_dir = (DWORD)n_root * SZDIRE / ss; /* Root directory size [sector] */ } b_fat = b_vol + sz_rsv; /* FAT base */ b_data = b_fat + sz_fat * n_fat + sz_dir; /* Data base */ @@ -6196,48 +6443,48 @@ FRESULT f_mkfs ( /* Create FAT VBR */ memset(buf, 0, ss); memcpy(buf + BS_JmpBoot, "\xEB\xFE\x90" "MSDOS5.0", 11); /* Boot jump code (x86), OEM name */ - st_word(buf + BPB_BytsPerSec, ss); /* Sector size [byte] */ + st_16(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 */ + st_16(buf + BPB_RsvdSecCnt, (WORD)sz_rsv); /* Size of reserved area */ 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 */ + st_16(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 */ + st_16(buf + BPB_TotSec16, (WORD)sz_vol); /* Volume size in 16-bit LBA */ } else { - st_dword(buf + BPB_TotSec32, (DWORD)sz_vol); /* Volume size in 32-bit LBA */ + st_32(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, (DWORD)b_vol); /* Volume offset in the physical drive [sector] */ + st_16(buf + BPB_SecPerTrk, 63); /* Number of sectors per track (for int13) */ + st_16(buf + BPB_NumHeads, 255); /* Number of heads (for int13) */ + st_32(buf + BPB_HiddSec, (DWORD)b_vol); /* Volume offset in the physical drive [sector] */ if (fsty == FS_FAT32) { - st_dword(buf + BS_VolID32, vsn); /* VSN */ - st_dword(buf + BPB_FATSz32, sz_fat); /* FAT size [sector] */ - st_dword(buf + BPB_RootClus32, 2); /* Root directory cluster # (2) */ - st_word(buf + BPB_FSInfo32, 1); /* Offset of FSINFO sector (VBR + 1) */ - st_word(buf + BPB_BkBootSec32, 6); /* Offset of backup VBR (VBR + 6) */ + st_32(buf + BS_VolID32, vsn); /* VSN */ + st_32(buf + BPB_FATSz32, sz_fat); /* FAT size [sector] */ + st_32(buf + BPB_RootClus32, 2); /* Root directory cluster # (2) */ + st_16(buf + BPB_FSInfo32, 1); /* Offset of FSINFO sector (VBR + 1) */ + st_16(buf + BPB_BkBootSec32, 6); /* Offset of backup VBR (VBR + 6) */ buf[BS_DrvNum32] = 0x80; /* Drive number (for int13) */ buf[BS_BootSig32] = 0x29; /* Extended boot signature */ memcpy(buf + BS_VolLab32, "NO NAME " "FAT32 ", 19); /* Volume label, FAT signature */ } else { - st_dword(buf + BS_VolID, vsn); /* VSN */ - st_word(buf + BPB_FATSz16, (WORD)sz_fat); /* FAT size [sector] */ + st_32(buf + BS_VolID, vsn); /* VSN */ + st_16(buf + BPB_FATSz16, (WORD)sz_fat); /* FAT size [sector] */ buf[BS_DrvNum] = 0x80; /* Drive number (for int13) */ buf[BS_BootSig] = 0x29; /* Extended boot signature */ memcpy(buf + BS_VolLab, "NO NAME " "FAT ", 19); /* Volume label, FAT signature */ } - st_word(buf + BS_55AA, 0xAA55); /* Signature (offset is fixed here regardless of sector size) */ + st_16(buf + BS_55AA, 0xAA55); /* Signature (offset is fixed here regardless of sector size) */ 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 (fsty == FS_FAT32) { disk_write(pdrv, buf, b_vol + 6, 1); /* Write backup VBR (VBR + 6) */ memset(buf, 0, ss); - st_dword(buf + FSI_LeadSig, 0x41615252); - st_dword(buf + FSI_StrucSig, 0x61417272); - st_dword(buf + FSI_Free_Count, n_clst - 1); /* Number of free clusters */ - st_dword(buf + FSI_Nxt_Free, 2); /* Last allocated cluster# */ - st_word(buf + BS_55AA, 0xAA55); + st_32(buf + FSI_LeadSig, 0x41615252); + st_32(buf + FSI_StrucSig, 0x61417272); + st_32(buf + FSI_Free_Count, n_clst - 1); /* Number of free clusters */ + st_32(buf + FSI_Nxt_Free, 2); /* Last allocated cluster# */ + st_16(buf + BS_55AA, 0xAA55); disk_write(pdrv, buf, b_vol + 7, 1); /* Write backup FSINFO (VBR + 7) */ disk_write(pdrv, buf, b_vol + 1, 1); /* Write original FSINFO (VBR + 1) */ } @@ -6247,17 +6494,17 @@ FRESULT f_mkfs ( sect = b_fat; /* FAT start sector */ 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) */ + st_32(buf + 0, 0xFFFFFFF8); /* FAT[0] */ + st_32(buf + 4, 0xFFFFFFFF); /* FAT[1] */ + st_32(buf + 8, 0x0FFFFFFF); /* FAT[2] (root directory at cluster# 2) */ } else { - st_dword(buf + 0, (fsty == FS_FAT12) ? 0xFFFFF8 : 0xFFFFFFF8); /* FAT[0] and FAT[1] */ + st_32(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); - memset(buf, 0, ss); /* Rest of FAT all are cleared */ + memset(buf, 0, ss); /* Rest of FAT area is initially zero */ sect += n; nsect -= n; } while (nsect); } @@ -6275,32 +6522,30 @@ FRESULT f_mkfs ( /* Determine system ID in the MBR partition table */ if (FF_FS_EXFAT && fsty == FS_EXFAT) { - sys = 0x07; /* exFAT */ + sys = 0x07; /* exFAT */ + } else if (fsty == FS_FAT32) { + sys = 0x0C; /* FAT32X */ + } else if (sz_vol >= 0x10000) { + sys = 0x06; /* FAT12/16 (large) */ + } else if (fsty == FS_FAT16) { + sys = 0x04; /* FAT16 */ } else { - if (fsty == FS_FAT32) { - sys = 0x0C; /* FAT32X */ - } else { - if (sz_vol >= 0x10000) { - sys = 0x06; /* FAT12/16 (large) */ - } else { - sys = (fsty == FS_FAT16) ? 0x04 : 0x01; /* FAT16 : FAT12 */ - } - } + sys = 0x01; /* FAT12 */ } /* Update partition information */ if (FF_MULTI_PARTITION && ipart != 0) { /* Volume is in the existing partition */ - if (!FF_LBA64 || !(fsopt & 0x80)) { + if (!FF_LBA64 || !(fsopt & 0x80)) { /* Is the partition in MBR? */ /* 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 */ + if (!(fsopt & FM_SFD)) { /* Create partition table if not in SFD format */ lba[0] = sz_vol; lba[1] = 0; - fr = create_partition(pdrv, lba, sys, buf); - if (fr != FR_OK) LEAVE_MKFS(fr); + res = create_partition(pdrv, lba, sys, buf); + if (res != FR_OK) LEAVE_MKFS(res); } } @@ -6314,7 +6559,7 @@ FRESULT f_mkfs ( #if FF_MULTI_PARTITION /*-----------------------------------------------------------------------*/ -/* Create Partition Table on the Physical Drive */ +/* API: Create Partition Table on the Physical Drive */ /*-----------------------------------------------------------------------*/ FRESULT f_fdisk ( @@ -6325,17 +6570,22 @@ FRESULT f_fdisk ( { BYTE *buf = (BYTE*)work; DSTATUS stat; + FRESULT res; + /* Initialize the physical drive */ stat = disk_initialize(pdrv); if (stat & STA_NOINIT) return FR_NOT_READY; if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; + #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; - LEAVE_MKFS(create_partition(pdrv, ptbl, 0x07, buf)); + res = create_partition(pdrv, ptbl, 0x07, buf); /* Create partitions (system ID is temporary setting and determined by f_mkfs) */ + + LEAVE_MKFS(res); } #endif /* FF_MULTI_PARTITION */ @@ -6349,7 +6599,7 @@ FRESULT f_fdisk ( #error Wrong FF_STRF_ENCODE setting #endif /*-----------------------------------------------------------------------*/ -/* Get a String from the File */ +/* API: Get a String from the File */ /*-----------------------------------------------------------------------*/ TCHAR* f_gets ( @@ -6390,12 +6640,12 @@ TCHAR* f_gets ( #elif FF_STRF_ENCODE == 1 || FF_STRF_ENCODE == 2 /* Read a character in UTF-16LE/BE */ 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]; + dc = (FF_STRF_ENCODE == 1) ? ld_16(s) : s[0] << 8 | s[1]; 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]; + wc = (FF_STRF_ENCODE == 1) ? ld_16(s) : s[0] << 8 | s[1]; if (!IsSurrogateL(wc)) continue; /* Broken surrogate pair? */ dc = ((dc & 0x3FF) + 0x40) << 10 | (wc & 0x3FF); /* Merge surrogate pair */ } @@ -6405,9 +6655,15 @@ TCHAR* f_gets ( dc = s[0]; if (dc >= 0x80) { /* Multi-byte sequence? */ ct = 0; - 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 ((dc & 0xE0) == 0xC0) { /* 2-byte sequence? */ + dc &= 0x1F; ct = 1; + } + if ((dc & 0xF0) == 0xE0) { /* 3-byte sequence? */ + dc &= 0x0F; ct = 2; + } + if ((dc & 0xF8) == 0xF0) { /* 4-byte sequence? */ + dc &= 0x07; ct = 3; + } if (ct == 0) continue; f_read(fp, s, ct, &rc); /* Get trailing bytes */ if (rc != ct) break; @@ -6419,7 +6675,7 @@ TCHAR* f_gets ( if (rc != ct || dc < 0x80 || IsSurrogate(dc) || dc >= 0x110000) continue; /* Wrong encoding? */ } #endif - /* A code point is avaialble in dc to be output */ + /* A code point is available 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 */ @@ -6434,25 +6690,21 @@ TCHAR* f_gets ( *p++ = (TCHAR)dc; nc++; if (dc == '\n') break; /* End of line? */ - } else { - 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 sequence? */ - *p++ = (TCHAR)(0xE0 | (dc >> 12 & 0x0F)); - *p++ = (TCHAR)(0x80 | (dc >> 6 & 0x3F)); - *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); - nc += 3; - } else { /* 4-byte sequence? */ - *p++ = (TCHAR)(0xF0 | (dc >> 18 & 0x07)); - *p++ = (TCHAR)(0x80 | (dc >> 12 & 0x3F)); - *p++ = (TCHAR)(0x80 | (dc >> 6 & 0x3F)); - *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); - nc += 4; - } - } + } else 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 sequence? */ + *p++ = (TCHAR)(0xE0 | (dc >> 12 & 0x0F)); + *p++ = (TCHAR)(0x80 | (dc >> 6 & 0x3F)); + *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); + nc += 3; + } else { /* 4-byte sequence */ + *p++ = (TCHAR)(0xF0 | (dc >> 18 & 0x07)); + *p++ = (TCHAR)(0x80 | (dc >> 12 & 0x3F)); + *p++ = (TCHAR)(0x80 | (dc >> 6 & 0x3F)); + *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); + nc += 4; } #endif } @@ -6482,14 +6734,14 @@ TCHAR* f_gets ( #define SZ_NUM_BUF 32 /*-----------------------------------------------------------------------*/ -/* Put a Character to the File (with sub-functions) */ +/* API: Put a Character to the File (with sub-functions) */ /*-----------------------------------------------------------------------*/ /* 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 */ + FIL *fp; /* Pointer to the writing file */ + int idx, nchr; /* Write index of buf[] (-1:error), number of written encoding units */ #if FF_USE_LFN && FF_LFN_UNICODE == 1 WCHAR hs; #elif FF_USE_LFN && FF_LFN_UNICODE == 2 @@ -6510,7 +6762,7 @@ static void putc_bfd (putbuff* pb, TCHAR c) WCHAR hs, wc; #if FF_LFN_UNICODE == 2 DWORD dc; - const TCHAR *tp; + const TCHAR* tp; #endif #endif @@ -6524,39 +6776,39 @@ static void putc_bfd (putbuff* pb, TCHAR c) #if FF_USE_LFN && FF_LFN_UNICODE #if FF_LFN_UNICODE == 1 /* UTF-16 input */ - if (IsSurrogateH(c)) { /* High surrogate? */ + if (IsSurrogateH(c)) { /* Is this a high-surrogate? */ pb->hs = c; return; /* Save it for next */ } hs = pb->hs; pb->hs = 0; - if (hs != 0) { /* There is a leading high surrogate */ - if (!IsSurrogateL(c)) hs = 0; /* Discard high surrogate if not a surrogate pair */ + if (hs != 0) { /* Is there a leading high-surrogate? */ + if (!IsSurrogateL(c)) hs = 0; /* Discard high-surrogate if a stray high-surrogate */ } else { - if (IsSurrogateL(c)) return; /* Discard stray low surrogate */ + 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? */ + if (pb->ct == 0) { /* Not in the multi-byte sequence? */ pb->bs[pb->wi = 0] = (BYTE)c; /* Save 1st byte */ - if ((BYTE)c < 0x80) break; /* Single byte? */ + if ((BYTE)c < 0x80) break; /* Single byte code? */ 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; + if (((BYTE)c & 0xF8) == 0xF0) pb->ct = 3; /* 4-byte sequence? */ + return; /* Invalid leading byte (discard it) */ } else { /* In the multi-byte sequence */ if (((BYTE)c & 0xC0) != 0x80) { /* Broken sequence? */ - pb->ct = 0; continue; + pb->ct = 0; continue; /* Discard the sequence */ } pb->bs[++pb->wi] = (BYTE)c; /* Save the trailing byte */ - if (--pb->ct == 0) break; /* End of multi-byte sequence? */ + if (--pb->ct == 0) break; /* End of the sequence? */ return; } } tp = (const TCHAR*)pb->bs; - dc = tchar2uni(&tp); /* UTF-8 ==> UTF-16 */ + dc = tchar2uni(&tp); /* UTF-8 ==> UTF-16 */ if (dc == 0xFFFFFFFF) return; /* Wrong code? */ - wc = (WCHAR)dc; hs = (WCHAR)(dc >> 16); + wc = (WCHAR)dc; #elif FF_LFN_UNICODE == 3 /* UTF-32 input */ if (IsSurrogate(c) || c >= 0x110000) return; /* Discard invalid code */ if (c >= 0x10000) { /* Out of BMP? */ @@ -6571,11 +6823,11 @@ static void putc_bfd (putbuff* pb, TCHAR c) #if FF_STRF_ENCODE == 1 /* Write a code point in UTF-16LE */ if (hs != 0) { /* Surrogate pair? */ - st_word(&pb->buf[i], hs); + st_16(&pb->buf[i], hs); i += 2; nc++; } - st_word(&pb->buf[i], wc); + st_16(&pb->buf[i], wc); i += 2; #elif FF_STRF_ENCODE == 2 /* Write a code point in UTF-16BE */ if (hs != 0) { /* Surrogate pair? */ @@ -6631,7 +6883,7 @@ static void putc_bfd (putbuff* pb, TCHAR c) } -/* Flush remaining characters in the buffer */ +/* Flush characters left in the buffer and return number of characters written */ static int putc_flush (putbuff* pb) { @@ -6639,7 +6891,9 @@ static int putc_flush (putbuff* pb) if ( pb->idx >= 0 /* Flush buffered characters to the file */ && f_write(pb->fp, pb->buf, (UINT)pb->idx, &nw) == FR_OK - && (UINT)pb->idx == nw) return pb->nchr; + && (UINT)pb->idx == nw) { + return pb->nchr; + } return -1; } @@ -6671,7 +6925,7 @@ int f_putc ( /*-----------------------------------------------------------------------*/ -/* Put a String to the File */ +/* API: Put a String to the File */ /*-----------------------------------------------------------------------*/ int f_puts ( @@ -6691,7 +6945,7 @@ int f_puts ( /*-----------------------------------------------------------------------*/ -/* Put a Formatted String to the File (with sub-functions) */ +/* API: Put a Formatted String to the File (with sub-functions) */ /*-----------------------------------------------------------------------*/ #if FF_PRINT_FLOAT && FF_INTDEF == 2 #include @@ -6747,8 +7001,8 @@ static void ftoa ( TCHAR fmt /* Notation */ ) { - int d; - int e = 0, m = 0; + int digit; + int exp = 0, mag = 0; char sign = 0; double w; const char *er = 0; @@ -6759,7 +7013,7 @@ static void ftoa ( er = "NaN"; } else { if (prec < 0) prec = 6; /* Default precision? (6 fractional digits) */ - if (val < 0) { /* Nagative? */ + if (val < 0) { /* Negative? */ val = 0 - val; sign = '-'; } else { sign = '+'; @@ -6769,18 +7023,18 @@ static void ftoa ( } else { if (fmt == 'f') { /* Decimal notation? */ val += i10x(0 - prec) / 2; /* Round (nearest) */ - m = ilog10(val); - if (m < 0) m = 0; - if (m + prec + 3 >= SZ_NUM_BUF) er = "OV"; /* Buffer overflow? */ + mag = ilog10(val); + if (mag < 0) mag = 0; + if (mag + prec + 3 >= SZ_NUM_BUF) er = "OV"; /* Buffer overflow? */ } else { /* E notation */ if (val != 0) { /* Not a true zero? */ val += i10x(ilog10(val) - prec) / 2; /* Round (nearest) */ - e = ilog10(val); - if (e > 99 || prec + 7 >= SZ_NUM_BUF) { /* Buffer overflow or E > +99? */ + exp = ilog10(val); + if (exp > 99 || prec + 7 >= SZ_NUM_BUF) { /* Buffer overflow or E > +99? */ er = "OV"; } else { - if (e < -99) e = -99; - val /= i10x(e); /* Normalize */ + if (exp < -99) exp = -99; + val /= i10x(exp); /* Normalize */ } } } @@ -6788,26 +7042,28 @@ static void ftoa ( if (!er) { /* Not error condition */ if (sign == '-') *buf++ = sign; /* Add a - if negative value */ do { /* Put decimal number */ - if (m == -1) *buf++ = ds; /* Insert a decimal separator when get into fractional part */ - w = i10x(m); /* Snip the highest digit d */ - d = (int)(val / w); val -= d * w; - *buf++ = (char)('0' + d); /* Put the digit */ - } while (--m >= -prec); /* Output all digits specified by prec */ + if (mag == -1) *buf++ = ds; /* Insert a decimal separator when get into fractional part */ + w = i10x(mag); /* Snip the highest digit d */ + digit = (int)(val / w); val -= digit * w; + *buf++ = (char)('0' + digit); /* Put the digit */ + } while (--mag >= -prec); /* Output all digits specified by prec */ if (fmt != 'f') { /* Put exponent if needed */ *buf++ = (char)fmt; - if (e < 0) { - e = 0 - e; *buf++ = '-'; + if (exp < 0) { + exp = 0 - exp; *buf++ = '-'; } else { *buf++ = '+'; } - *buf++ = (char)('0' + e / 10); - *buf++ = (char)('0' + e % 10); + *buf++ = (char)('0' + exp / 10); + *buf++ = (char)('0' + exp % 10); } } } if (er) { /* Error condition */ if (sign) *buf++ = sign; /* Add sign if needed */ - do *buf++ = *er++; while (*er); /* Put error symbol */ + do { /* Put error symbol */ + *buf++ = *er++; + } while (*er); } *buf = 0; /* Term */ } @@ -6823,16 +7079,17 @@ int f_printf ( { va_list arp; putbuff pb; - UINT i, j, w, f, r; + UINT i, j, width, flag, radix; int prec; #if FF_PRINT_LLI && FF_INTDEF == 2 - QWORD v; + QWORD val; #else - DWORD v; + DWORD val; #endif - TCHAR tc, pad, *tp; + TCHAR *tp; + TCHAR chr, pad; TCHAR nul = 0; - char d, str[SZ_NUM_BUF]; + char digit, str[SZ_NUM_BUF]; putc_init(&pb, fp); @@ -6840,122 +7097,132 @@ int f_printf ( va_start(arp, fmt); for (;;) { - tc = *fmt++; - if (tc == 0) break; /* End of format string */ - if (tc != '%') { /* Not an escape character (pass-through) */ - putc_bfd(&pb, tc); + chr = *fmt++; + if (chr == 0) break; /* End of format string */ + if (chr != '%') { /* Not an escape character (pass-through) */ + putc_bfd(&pb, chr); continue; } - f = w = 0; pad = ' '; prec = -1; /* Initialize parms */ - tc = *fmt++; - if (tc == '0') { /* Flag: '0' padded */ - pad = '0'; tc = *fmt++; - } else if (tc == '-') { /* Flag: Left aligned */ - f = 2; tc = *fmt++; + flag = width = 0; pad = ' '; prec = -1; /* Initialize the parameters */ + chr = *fmt++; + if (chr == '0') { /* Flag: '0' padded */ + pad = '0'; chr = *fmt++; + } else if (chr == '-') { /* Flag: Left aligned */ + flag = 2; chr = *fmt++; } - if (tc == '*') { /* Minimum width from an argument */ - w = va_arg(arp, int); - tc = *fmt++; + if (chr == '*') { /* Minimum width from an argument */ + width = (UINT)va_arg(arp, int); + chr = *fmt++; } else { - while (IsDigit(tc)) { /* Minimum width */ - w = w * 10 + tc - '0'; - tc = *fmt++; + while (IsDigit(chr)) { /* Minimum width */ + width = width * 10 + chr - '0'; + chr = *fmt++; } } - if (tc == '.') { /* Precision */ - tc = *fmt++; - if (tc == '*') { /* Precision from an argument */ + if (chr == '.') { /* Precision */ + chr = *fmt++; + if (chr == '*') { /* Precision from an argument */ prec = va_arg(arp, int); - tc = *fmt++; + chr = *fmt++; } else { prec = 0; - while (IsDigit(tc)) { /* Precision */ - prec = prec * 10 + tc - '0'; - tc = *fmt++; + while (IsDigit(chr)) { /* Precision */ + prec = prec * 10 + chr - '0'; + chr = *fmt++; } } } - if (tc == 'l') { /* Size: long int */ - f |= 4; tc = *fmt++; + if (chr == 'l') { /* Size: long int */ + flag |= 4; chr = *fmt++; #if FF_PRINT_LLI && FF_INTDEF == 2 - if (tc == 'l') { /* Size: long long int */ - f |= 8; tc = *fmt++; + if (chr == 'l') { /* Size: long long int */ + flag |= 8; chr = *fmt++; } #endif } - if (tc == 0) break; /* End of format string */ - switch (tc) { /* Atgument type is... */ + if (chr == 0) break; /* End of format string */ + switch (chr) { /* Atgument type is... */ case 'b': /* Unsigned binary */ - r = 2; break; + radix = 2; break; + case 'o': /* Unsigned octal */ - r = 8; break; + radix = 8; break; + case 'd': /* Signed decimal */ - case 'u': /* Unsigned decimal */ - r = 10; break; - case 'x': /* Unsigned hexdecimal (lower case) */ - case 'X': /* Unsigned hexdecimal (upper case) */ - r = 16; break; + case 'u': /* Unsigned decimal */ + radix = 10; break; + + case 'x': /* Unsigned hexadecimal (lower case) */ + case 'X': /* Unsigned hexadecimal (upper case) */ + radix = 16; break; + case 'c': /* Character */ putc_bfd(&pb, (TCHAR)va_arg(arp, int)); continue; + case 's': /* String */ tp = va_arg(arp, TCHAR*); /* Get a pointer argument */ - if (!tp) tp = &nul; /* Null ptr generates a null string */ + if (!tp) tp = &nul; /* Null pointer generates a null string */ for (j = 0; tp[j]; j++) ; /* j = tcslen(tp) */ - if (prec >= 0 && j > (UINT)prec) j = prec; /* Limited length of string body */ - for ( ; !(f & 2) && j < w; j++) putc_bfd(&pb, pad); /* Left pads */ - while (*tp && prec--) putc_bfd(&pb, *tp++); /* Body */ - while (j++ < w) putc_bfd(&pb, ' '); /* Right pads */ + if (prec >= 0 && j > (UINT)prec) j = (UINT)prec; /* Limited length of string body */ + for ( ; !(flag & 2) && j < width; j++) putc_bfd(&pb, pad); /* Left padding */ + while (*tp && prec--) putc_bfd(&pb, *tp++); /* Body */ + while (j++ < width) putc_bfd(&pb, ' '); /* Right padding */ continue; #if FF_PRINT_FLOAT && FF_INTDEF == 2 case 'f': /* Floating point (decimal) */ case 'e': /* Floating point (e) */ case 'E': /* Floating point (E) */ - ftoa(str, va_arg(arp, double), prec, tc); /* Make a flaoting point string */ - for (j = strlen(str); !(f & 2) && j < w; j++) putc_bfd(&pb, pad); /* Left pads */ + ftoa(str, va_arg(arp, double), prec, chr); /* Make a floating point string */ + for (j = strlen(str); !(flag & 2) && j < width; j++) putc_bfd(&pb, pad); /* Leading pads */ for (i = 0; str[i]; putc_bfd(&pb, str[i++])) ; /* Body */ - while (j++ < w) putc_bfd(&pb, ' '); /* Right pads */ + while (j++ < width) putc_bfd(&pb, ' '); /* Trailing pads */ continue; #endif default: /* Unknown type (pass-through) */ - putc_bfd(&pb, tc); continue; + putc_bfd(&pb, chr); + continue; } /* Get an integer argument and put it in numeral */ #if FF_PRINT_LLI && FF_INTDEF == 2 - if (f & 8) { /* long long argument? */ - v = (QWORD)va_arg(arp, LONGLONG); - } else { - if (f & 4) { /* long argument? */ - v = (tc == 'd') ? (QWORD)(LONGLONG)va_arg(arp, long) : (QWORD)va_arg(arp, unsigned long); - } else { /* int/short/char argument */ - v = (tc == 'd') ? (QWORD)(LONGLONG)va_arg(arp, int) : (QWORD)va_arg(arp, unsigned int); - } + if (flag & 8) { /* long long argument? */ + val = (QWORD)va_arg(arp, long long); + } else if (flag & 4) { /* long argument? */ + val = (chr == 'd') ? (QWORD)(long long)va_arg(arp, long) : (QWORD)va_arg(arp, unsigned long); + } else { /* int/short/char argument */ + val = (chr == 'd') ? (QWORD)(long long)va_arg(arp, int) : (QWORD)va_arg(arp, unsigned int); } - if (tc == 'd' && (v & 0x8000000000000000)) { /* Negative value? */ - v = 0 - v; f |= 1; + if (chr == 'd' && (val & 0x8000000000000000)) { /* Negative value? */ + val = 0 - val; flag |= 1; } #else - if (f & 4) { /* long argument? */ - v = (DWORD)va_arg(arp, long); + if (flag & 4) { /* long argument? */ + val = (DWORD)va_arg(arp, long); } else { /* int/short/char argument */ - v = (tc == 'd') ? (DWORD)(long)va_arg(arp, int) : (DWORD)va_arg(arp, unsigned int); + val = (chr == 'd') ? (DWORD)(long)va_arg(arp, int) : (DWORD)va_arg(arp, unsigned int); } - if (tc == 'd' && (v & 0x80000000)) { /* Negative value? */ - v = 0 - v; f |= 1; + if (chr == 'd' && (val & 0x80000000)) { /* Negative value? */ + val = 0 - val; flag |= 1; } #endif i = 0; do { /* Make an integer number string */ - d = (char)(v % r); v /= r; - if (d > 9) d += (tc == 'x') ? 0x27 : 0x07; - str[i++] = d + '0'; - } while (v && i < SZ_NUM_BUF); - if (f & 1) str[i++] = '-'; /* Sign */ + digit = (char)(val % radix) + '0'; val /= radix; + if (digit > '9') digit += (chr == 'x') ? 0x27 : 0x07; + str[i++] = digit; + } while (val && i < SZ_NUM_BUF); + if (flag & 1) str[i++] = '-'; /* Sign */ /* Write it */ - for (j = i; !(f & 2) && j < w; j++) putc_bfd(&pb, pad); /* Left pads */ - do putc_bfd(&pb, (TCHAR)str[--i]); while (i); /* Body */ - while (j++ < w) putc_bfd(&pb, ' '); /* Right pads */ + for (j = i; !(flag & 2) && j < width; j++) { /* Leading pads */ + putc_bfd(&pb, pad); + } + do { /* Body */ + putc_bfd(&pb, (TCHAR)str[--i]); + } while (i); + while (j++ < width) { /* Trailing pads */ + putc_bfd(&pb, ' '); + } } va_end(arp); @@ -6970,7 +7237,7 @@ int f_printf ( #if FF_CODE_PAGE == 0 /*-----------------------------------------------------------------------*/ -/* Set Active Codepage for the Path Name */ +/* API: Set Active Codepage for the Path Name */ /*-----------------------------------------------------------------------*/ FRESULT f_setcp ( @@ -6978,12 +7245,12 @@ FRESULT f_setcp ( ) { static const WORD validcp[22] = { 437, 720, 737, 771, 775, 850, 852, 855, 857, 860, 861, 862, 863, 864, 865, 866, 869, 932, 936, 949, 950, 0}; - static const BYTE* const tables[22] = {Ct437, Ct720, Ct737, Ct771, Ct775, Ct850, Ct852, Ct855, Ct857, Ct860, Ct861, Ct862, Ct863, Ct864, Ct865, Ct866, Ct869, Dc932, Dc936, Dc949, Dc950, 0}; + static const BYTE *const tables[22] = {Ct437, Ct720, Ct737, Ct771, Ct775, Ct850, Ct852, Ct855, Ct857, Ct860, Ct861, Ct862, Ct863, Ct864, Ct865, Ct866, Ct869, Dc932, Dc936, Dc949, Dc950, 0}; UINT i; for (i = 0; validcp[i] != 0 && validcp[i] != cp; i++) ; /* Find the code page */ - if (validcp[i] != cp) return FR_INVALID_PARAMETER; /* Not found? */ + if (validcp[i] != cp) return FR_INVALID_PARAMETER; /* Not found? */ CodePage = cp; if (cp >= 900) { /* DBCS */ @@ -7012,3 +7279,4 @@ int elm_get_vol(FATFS *fat) } #endif + diff --git a/components/dfs/dfs_v1/filesystems/elmfat/ff.h b/components/dfs/dfs_v1/filesystems/elmfat/ff.h index 7db1c4d4a29..fed69af5d6f 100644 --- a/components/dfs/dfs_v1/filesystems/elmfat/ff.h +++ b/components/dfs/dfs_v1/filesystems/elmfat/ff.h @@ -1,8 +1,8 @@ /*----------------------------------------------------------------------------/ -/ FatFs - Generic FAT Filesystem module R0.14b / +/ FatFs - Generic FAT Filesystem module R0.16 / /-----------------------------------------------------------------------------/ / -/ Copyright (C) 2021, ChaN, all right reserved. +/ Copyright (C) 2025, 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,15 +20,16 @@ #ifndef FF_DEFINED -#define FF_DEFINED 86631 /* Revision ID */ +#define FF_DEFINED 80386 /* Revision ID */ #ifdef __cplusplus extern "C" { #endif #include +#if !defined(FFCONF_DEF) #include "ffconf.h" /* FatFs configuration options */ - +#endif #if FF_DEFINED != FFCONF_DEF #error Wrong configuration file (ffconf.h). #endif @@ -49,18 +50,18 @@ typedef unsigned __int64 QWORD; #include 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 uint32_t DWORD; /* 32-bit unsigned integer */ -typedef uint64_t QWORD; /* 64-bit unsigned integer */ -typedef WORD WCHAR; /* UTF-16 character type */ +typedef uint16_t WORD; /* 16-bit unsigned */ +typedef uint32_t DWORD; /* 32-bit unsigned */ +typedef uint64_t QWORD; /* 64-bit unsigned */ +typedef WORD WCHAR; /* UTF-16 code unit */ #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 long DWORD; /* 32-bit unsigned integer */ -typedef WORD WCHAR; /* UTF-16 character type */ +typedef unsigned short WORD; /* short must be 16-bit */ +typedef unsigned long DWORD; /* long must be 32-bit */ +typedef WORD WCHAR; /* UTF-16 code unit */ #endif @@ -114,66 +115,78 @@ typedef char TCHAR; #if FF_MULTI_PARTITION /* Multiple partition configuration */ typedef struct { - BYTE pd; /* Physical drive number */ - BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */ + BYTE pd; /* Associated physical drive */ + BYTE pt; /* Associated partition (0:Auto detect, 1-4:Forced partition) */ } PARTITION; -extern PARTITION VolToPart[]; /* Volume - Partition mapping table */ +extern PARTITION VolToPart[]; /* Volume to partition mapping table */ #endif #if FF_STR_VOLUME_ID #ifndef FF_VOLUME_STRS -extern const char* VolumeStr[FF_VOLUMES]; /* User defied volume ID */ +extern const char* VolumeStr[FF_VOLUMES]; /* User defined volume ID table */ #endif #endif +/* Current working directory structure (FFXCWDS) */ + +#if FF_FS_EXFAT && FF_FS_RPATH +#if FF_PATH_DEPTH < 1 +#error FF_PATH_DEPTH must not be zero +#endif +typedef struct { + DWORD d_scl; /* Directory start cluster (0:root dir) */ + DWORD d_size; /* Size of directory (b7-b0: cluster chain status) (invalid if d_scl == 0) */ + DWORD nxt_ofs; /* Offset of entry of next dir in this directory (invalid if last link) */ +} FFXCWDL; +typedef struct { + UINT depth; /* Current directory depth (0:root dir) */ + FFXCWDL tbl[FF_PATH_DEPTH + 1]; /* Directory chain of current working directory path */ +} FFXCWDS; +#endif + /* Filesystem object structure (FATFS) */ typedef struct { - BYTE fs_type; /* Filesystem type (0:not mounted) */ - BYTE pdrv; /* Associated physical drive */ - BYTE n_fats; /* Number of FATs (1 or 2) */ - BYTE wflag; /* win[] flag (b0:dirty) */ - BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */ - WORD id; /* Volume mount ID */ - WORD n_rootdir; /* Number of root directory entries (FAT12/16) */ - WORD csize; /* Cluster size [sectors] */ + BYTE fs_type; /* Filesystem type (0:not mounted) */ + BYTE pdrv; /* Physical drive that holds this volume */ + BYTE ldrv; /* Logical drive number (used only when FF_FS_REENTRANT) */ + BYTE n_fats; /* Number of FATs (1 or 2) */ + BYTE wflag; /* win[] status (b0:dirty) */ + BYTE fsi_flag; /* Allocation information control (b7:disabled, b0:dirty) */ + WORD id; /* Volume mount ID */ + WORD n_rootdir; /* Number of root directory entries (FAT12/16) */ + WORD csize; /* Cluster size [sectors] */ #if FF_MAX_SS != FF_MIN_SS - WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */ + WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */ #endif #if FF_USE_LFN - WCHAR* lfnbuf; /* LFN working buffer */ -#endif -#if FF_FS_EXFAT - BYTE* dirbuf; /* Directory entry block scratchpad buffer for exFAT */ -#endif -#if FF_FS_REENTRANT - FF_SYNC_t sobj; /* Identifier of sync object */ + WCHAR* lfnbuf; /* Pointer to LFN working buffer */ #endif #if !FF_FS_READONLY - DWORD last_clst; /* Last allocated cluster */ - DWORD free_clst; /* Number of free clusters */ + DWORD last_clst; /* Last allocated cluster (invalid if >=n_fatent) */ + DWORD free_clst; /* Number of free clusters (invalid if >=fs->n_fatent-2) */ #endif #if FF_FS_RPATH - DWORD cdir; /* Current directory start cluster (0:root) */ + DWORD cdir; /* Current directory start cluster (0:root) */ +#endif + DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */ + DWORD fsize; /* Number of sectors per FAT */ + LBA_t winsect; /* Current sector appearing in the win[] */ + LBA_t volbase; /* Volume base sector */ + LBA_t fatbase; /* FAT base sector */ + LBA_t dirbase; /* Root directory base sector (FAT12/16) or cluster (FAT32/exFAT) */ + LBA_t database; /* Data base sector */ #if FF_FS_EXFAT - DWORD cdc_scl; /* Containing directory start cluster (invalid when cdir is 0) */ - DWORD cdc_size; /* b31-b8:Size of containing directory, b7-b0: Chain status */ - DWORD cdc_ofs; /* Offset in the containing directory (invalid when cdir is 0) */ -#endif + LBA_t bitbase; /* Allocation bitmap base sector */ + BYTE* dirbuf; /* Pointer to directory entry block buffer */ +#if FF_FS_RPATH + FFXCWDS xcwds; /* Crrent working directory structure */ + FFXCWDS xcwds2; /* Working buffer to follow the path */ #endif - DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */ - DWORD fsize; /* Size of an FAT [sectors] */ - 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 - LBA_t bitbase; /* Allocation bitmap base sector */ #endif - 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) */ + BYTE win[FF_MAX_SS]; /* Disk access window for directory, FAT (and file data in tiny cfg) */ } FATFS; @@ -181,21 +194,21 @@ typedef struct { /* Object ID and allocation information (FFOBJID) */ typedef struct { - FATFS* fs; /* Pointer to the hosting volume of this object */ - WORD id; /* Hosting volume mount ID */ - BYTE attr; /* Object attribute */ - BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:fragmented in this session, b2:sub-directory stretched) */ - DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */ - FSIZE_t objsize; /* Object size (valid when sclust != 0) */ + FATFS* fs; /* Pointer to the volume holding this object */ + WORD id; /* Volume mount ID when this object was opened */ + BYTE attr; /* Object attribute */ + BYTE stat; /* Object chain status (exFAT: b1-0: =0:not contiguous, =2:contiguous, =3:fragmented in this session, b2:sub-directory stretched) */ + DWORD sclust; /* Object data cluster (0:no data or root directory) */ + FSIZE_t objsize; /* Object size (valid when sclust != 0) */ #if FF_FS_EXFAT - DWORD n_cont; /* Size of first fragment - 1 (valid when stat == 3) */ - DWORD n_frag; /* Size of last fragment needs to be written to FAT (valid when not zero) */ - DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */ - DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */ - DWORD c_ofs; /* Offset in the containing directory (valid when file object and sclust != 0) */ + DWORD n_cont; /* Size of first fragment - 1 (valid when stat == 3) */ + DWORD n_frag; /* Size of last fragment needs to be written to FAT (valid when not zero) */ + DWORD c_scl; /* Cluster of directory holding this object (valid when sclust != 0) */ + DWORD c_size; /* Size of directory holding this object (b7-b0: allocation status, valid when c_scl != 0) */ + DWORD c_ofs; /* Offset of entry in the holding directory */ #endif #if FF_FS_LOCK - UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */ + UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */ #endif } FFOBJID; @@ -204,18 +217,18 @@ typedef struct { /* File object structure (FIL) */ typedef struct { - FFOBJID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */ - BYTE flag; /* File status flags */ - 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) */ - LBA_t sect; /* Sector number appearing in buf[] (0:invalid) */ + FFOBJID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */ + BYTE flag; /* File status flags */ + BYTE err; /* Abort flag (error code) */ + FSIZE_t fptr; /* File read/write pointer (0 on open) */ + DWORD clust; /* Current cluster of fptr (invalid when fptr is 0) */ + LBA_t sect; /* Sector number appearing in buf[] (0:invalid) */ #if !FF_FS_READONLY - 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) */ + LBA_t dir_sect; /* Sector number containing the directory entry (not used in exFAT) */ + BYTE* dir_ptr; /* Pointer to the directory entry in the win[] (not used in exFAT) */ #endif #if FF_USE_FASTSEEK - DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */ + DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open; set by application) */ #endif #if !FF_FS_TINY BYTE buf[FF_MAX_SS]; /* File private data read/write window */ @@ -227,40 +240,44 @@ typedef struct { /* Directory object structure (DIR) */ typedef struct { - FFOBJID obj; /* Object identifier */ - DWORD dptr; /* Current read/write offset */ - DWORD clust; /* Current cluster */ - 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]} */ + FFOBJID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */ + DWORD dptr; /* Current read/write offset */ + DWORD clust; /* Current cluster */ + LBA_t sect; /* Current sector (0:no more item to read) */ + BYTE* dir; /* Pointer to the directory item in the win[] in filesystem object */ + BYTE fn[12]; /* SFN (in/out) {body[0-7],ext[8-10],status[11]} */ #if FF_USE_LFN - DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */ + DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:invalid) */ #endif #if FF_USE_FIND - const TCHAR* pat; /* Pointer to the name matching pattern */ + const TCHAR *pat; /* Pointer to the name matching pattern */ #endif } DIR; -/* File information structure (FILINFO) */ +/* File/directory information structure (FILINFO) */ typedef struct { - FSIZE_t fsize; /* File size */ - WORD fdate; /* Modified date */ - WORD ftime; /* Modified time */ - BYTE fattrib; /* File attribute */ + FSIZE_t fsize; /* File size (invalid for directory) */ + WORD fdate; /* Date of file modification or directory creation */ + WORD ftime; /* Time of file modification or directory creation */ +#if FF_FS_CRTIME + WORD crdate; /* Date of object createion */ + WORD crtime; /* Time of object createion */ +#endif + BYTE fattrib; /* Object attribute */ #if FF_USE_LFN - TCHAR altname[FF_SFN_BUF + 1];/* Altenative file name */ - TCHAR fname[FF_LFN_BUF + 1]; /* Primary file name */ + TCHAR altname[FF_SFN_BUF + 1];/* Alternative object name */ + TCHAR fname[FF_LFN_BUF + 1]; /* Primary object name */ #else - TCHAR fname[12 + 1]; /* File name */ + TCHAR fname[12 + 1]; /* Object name */ #endif } FILINFO; -/* Format parameter structure (MKFS_PARM) */ +/* Format parameter structure (MKFS_PARM) used for f_mkfs() */ typedef struct { BYTE fmt; /* Format option (FM_FAT, FM_FAT32, FM_EXFAT and FM_SFD) */ @@ -275,32 +292,34 @@ typedef struct { /* File function return code (FRESULT) */ typedef enum { - FR_OK = 0, /* (0) Succeeded */ + FR_OK = 0, /* (0) Function succeeded */ FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */ FR_INT_ERR, /* (2) Assertion failed */ - FR_NOT_READY, /* (3) The physical drive cannot work */ + FR_NOT_READY, /* (3) The physical drive does not work */ FR_NO_FILE, /* (4) Could not find the file */ FR_NO_PATH, /* (5) Could not find the path */ FR_INVALID_NAME, /* (6) The path name format is invalid */ - FR_DENIED, /* (7) Access denied due to prohibited access or directory full */ - FR_EXIST, /* (8) Access denied due to prohibited access */ + FR_DENIED, /* (7) Access denied due to a prohibited access or directory full */ + FR_EXIST, /* (8) Access denied due to a prohibited access */ FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */ FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */ FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */ FR_NOT_ENABLED, /* (12) The volume has no work area */ - FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */ - FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any problem */ - FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */ + FR_NO_FILESYSTEM, /* (13) Could not find a valid FAT volume */ + FR_MKFS_ABORTED, /* (14) The f_mkfs function aborted due to some problem */ + FR_TIMEOUT, /* (15) Could not take control of the volume within defined period */ FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */ - FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */ + FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated, given buffer size is insufficient or too deep path */ FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > FF_FS_LOCK */ FR_INVALID_PARAMETER /* (19) Given parameter is invalid */ } FRESULT; + +/*--------------------------------------------------------------*/ +/* FatFs Module Application Interface */ /*--------------------------------------------------------------*/ -/* FatFs module application interface */ FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */ FRESULT f_close (FIL* fp); /* Close an open file object */ @@ -338,6 +357,8 @@ int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */ int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */ TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */ +/* Some API fucntions are implemented as macro */ + #define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize)) #define f_error(fp) ((fp)->err) #define f_tell(fp) ((fp)->fptr) @@ -351,40 +372,45 @@ TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the fil /*--------------------------------------------------------------*/ -/* Additional user defined functions */ +/* Additional Functions */ +/*--------------------------------------------------------------*/ -/* RTC function */ +/* RTC function (provided by user) */ #if !FF_FS_READONLY && !FF_FS_NORTC -DWORD get_fattime (void); +DWORD get_fattime (void); /* Get current time */ #endif -/* LFN support functions */ -#if FF_USE_LFN >= 1 /* Code conversion (defined in unicode.c) */ + +/* LFN support functions (defined in ffunicode.c) */ + +#if FF_USE_LFN >= 1 WCHAR ff_oem2uni (WCHAR oem, WORD cp); /* OEM code to Unicode conversion */ WCHAR ff_uni2oem (DWORD uni, WORD cp); /* Unicode to OEM code conversion */ DWORD ff_wtoupper (DWORD uni); /* Unicode upper-case conversion */ #endif -#if FF_USE_LFN == 3 /* Dynamic memory allocation */ -void* ff_memalloc (UINT msize); /* Allocate memory block */ -void ff_memfree (void* mblock); /* Free memory block */ -#endif -/* Sync functions */ -#if FF_FS_REENTRANT -int ff_cre_syncobj (BYTE vol, FF_SYNC_t* sobj); /* Create a sync object */ -int ff_req_grant (FF_SYNC_t sobj); /* Lock sync object */ -void ff_rel_grant (FF_SYNC_t sobj); /* Unlock sync object */ -int ff_del_syncobj (FF_SYNC_t sobj); /* Delete a sync object */ + +/* O/S dependent functions (samples available in ffsystem.c) */ + +#if FF_USE_LFN == 3 /* Dynamic memory allocation */ +void* ff_memalloc (UINT msize); /* Allocate memory block */ +void ff_memfree (void* mblock); /* Free memory block */ +#endif +#if FF_FS_REENTRANT /* Sync functions */ +int ff_mutex_create (int vol); /* Create a sync object */ +void ff_mutex_delete (int vol); /* Delete a sync object */ +int ff_mutex_take (int vol); /* Lock sync object */ +void ff_mutex_give (int vol); /* Unlock sync object */ #endif /*--------------------------------------------------------------*/ -/* Flags and offset address */ - +/* Flags and Offset Address */ +/*--------------------------------------------------------------*/ -/* File access mode and open method flags (3rd argument of f_open) */ +/* File access mode and open method flags (3rd argument of f_open function) */ #define FA_READ 0x01 #define FA_WRITE 0x02 #define FA_OPEN_EXISTING 0x00 @@ -393,10 +419,10 @@ int ff_del_syncobj (FF_SYNC_t sobj); /* Delete a sync object */ #define FA_OPEN_ALWAYS 0x10 #define FA_OPEN_APPEND 0x30 -/* Fast seek controls (2nd argument of f_lseek) */ +/* Fast seek controls (2nd argument of f_lseek function) */ #define CREATE_LINKMAP ((FSIZE_t)0 - 1) -/* Format options (2nd argument of f_mkfs) */ +/* Format options (2nd argument of f_mkfs function) */ #define FM_FAT 0x01 #define FM_FAT32 0x02 #define FM_EXFAT 0x04 diff --git a/components/dfs/dfs_v1/filesystems/elmfat/ffconf.h b/components/dfs/dfs_v1/filesystems/elmfat/ffconf.h index be6cf442db9..a99c908782f 100644 --- a/components/dfs/dfs_v1/filesystems/elmfat/ffconf.h +++ b/components/dfs/dfs_v1/filesystems/elmfat/ffconf.h @@ -1,8 +1,8 @@ /*---------------------------------------------------------------------------/ -/ FatFs Functional Configurations +/ Configurations of FatFs Module /---------------------------------------------------------------------------*/ -#define FFCONF_DEF 86631 /* Revision ID */ +#define FFCONF_DEF 80386 /* Revision ID */ /*---------------------------------------------------------------------------/ / Function Configurations @@ -31,36 +31,36 @@ #define FF_USE_MKFS 1 -/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */ +/* This option switches f_mkfs(). (0:Disable or 1:Enable) */ #define FF_USE_FASTSEEK 1 -/* This option switches fast seek function. (0:Disable or 1:Enable) */ +/* This option switches fast seek feature. (0:Disable or 1:Enable) */ #define FF_USE_EXPAND 0 -/* This option switches f_expand function. (0:Disable or 1:Enable) */ +/* This option switches f_expand(). (0:Disable or 1:Enable) */ #define FF_USE_CHMOD 0 -/* This option switches attribute manipulation functions, f_chmod() and f_utime(). +/* This option switches attribute control API functions, f_chmod() and f_utime(). / (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */ #define FF_USE_LABEL 0 -/* This option switches volume label functions, f_getlabel() and f_setlabel(). +/* This option switches volume label API functions, f_getlabel() and f_setlabel(). / (0:Disable or 1:Enable) */ #define FF_USE_FORWARD 0 -/* This option switches f_forward() function. (0:Disable or 1:Enable) */ +/* This option switches f_forward(). (0:Disable or 1:Enable) */ #define FF_USE_STRFUNC 0 #define FF_PRINT_LLI 0 #define FF_PRINT_FLOAT 0 #define FF_STRF_ENCODE 3 -/* FF_USE_STRFUNC switches string functions, f_gets(), f_putc(), f_puts() and +/* FF_USE_STRFUNC switches string API functions, f_gets(), f_putc(), f_puts() and / f_printf(). / / 0: Disable. FF_PRINT_LLI, FF_PRINT_FLOAT and FF_STRF_ENCODE have no effect. @@ -68,8 +68,8 @@ / 2: Enable with LF-CRLF conversion. / / FF_PRINT_LLI = 1 makes f_printf() support long long argument and FF_PRINT_FLOAT = 1/2 - makes f_printf() support floating point argument. These features want C99 or later. -/ When FF_LFN_UNICODE >= 1 with LFN enabled, string functions convert the character +/ makes f_printf() support floating point argument. These features want C99 or later. +/ When FF_LFN_UNICODE >= 1 with LFN enabled, string API functions convert the character / encoding in it. FF_STRF_ENCODE selects assumption of character encoding ON THE FILE / to be read/written via those functions. / @@ -127,15 +127,15 @@ /* 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. / -/ To enable the LFN, ffunicode.c needs to be added to the project. The LFN function +/ To enable the LFN, ffunicode.c needs to be added to the project. The LFN feature / 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 it 255 to fully support LFN +/ be in range of 12 to 255. It is recommended to be set 255 to fully support the 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 @@ -176,14 +176,26 @@ #define FF_FS_RPATH 0 -/* This option configures support for relative path. +/* This option configures support for relative path feature. / -/ 0: Disable relative path and remove related functions. -/ 1: Enable relative path. f_chdir() and f_chdrive() are available. -/ 2: f_getcwd() function is available in addition to 1. +/ 0: Disable relative path and remove related API functions. +/ 1: Enable relative path and dot names. f_chdir() and f_chdrive() are available. +/ 2: f_getcwd() is available in addition to 1. */ +#define FF_PATH_DEPTH 10 +/* This option defines maximum depth of directory in the exFAT volume. It is NOT +/ relevant to FAT/FAT32 volume. +/ For example, FF_PATH_DEPTH = 3 will able to follow a path "/dir1/dir2/dir3/file" +/ but a sub-directory in the dir3 will not able to be followed and set current +/ directory. +/ The size of filesystem object (FATFS) increases FF_PATH_DEPTH * 24 bytes. +/ When FF_FS_EXFAT == 0 or FF_FS_RPATH == 0, this option has no effect. +*/ + + + /*---------------------------------------------------------------------------/ / Drive/Volume Configurations /---------------------------------------------------------------------------*/ @@ -201,10 +213,10 @@ /* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings. / When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive / number in the path name. FF_VOLUME_STRS defines the volume ID strings for each -/ logical drives. Number of items must not be less than FF_VOLUMES. Valid +/ logical drive. Number of items must not be less than FF_VOLUMES. Valid / characters for the volume ID strings are A-Z, a-z and 0-9, however, they are / compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is -/ not defined, a user defined volume string table needs to be defined as: +/ not defined, a user defined volume string table is needed as: / / const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",... */ @@ -214,9 +226,9 @@ /* This option switches support for multiple volumes on the physical drive. / By default (0), each logical drive number is bound to the same physical drive / number and only an FAT volume found on the physical drive will be mounted. -/ When this function is enabled (1), each logical drive number can be bound to +/ When this feature is enabled (1), each logical drive number can be bound to / arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk() -/ funciton will be available. */ +/ will be available. */ #define FF_MIN_SS 512 @@ -228,8 +240,8 @@ /* This set of options configures the range of sector size to be supported. (512, / 1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and / harddisk, but a larger value may be required for on-board flash memory and some -/ type of optical media. When FF_MAX_SS is larger than FF_MIN_SS, FatFs is configured -/ for variable sector size mode and disk_ioctl() function needs to implement +/ type of optical media. When FF_MAX_SS is larger than FF_MIN_SS, FatFs is +/ configured for variable sector size mode and disk_ioctl() needs to implement / GET_SECTOR_SIZE command. */ @@ -239,14 +251,14 @@ #define FF_MIN_GPT 0x10000000 -/* Minimum number of sectors to switch GPT as partitioning format in f_mkfs and -/ f_fdisk function. 0x100000000 max. This option has no effect when FF_LBA64 == 0. */ +/* Minimum number of sectors to switch GPT as partitioning format in f_mkfs() and +/ f_fdisk(). 2^32 sectors maximum. 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. */ +/ To enable this feature, also CTRL_TRIM command should be implemented to +/ the disk_ioctl(). */ @@ -256,7 +268,7 @@ #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. +/ At the tiny configuration, size of file object (FIL) is reduced FF_MAX_SS bytes. / Instead of private sector buffer eliminated from the file object, common sector / buffer in the filesystem object (FATFS) is used for the file data transfer. */ @@ -273,20 +285,25 @@ #define FF_FS_NORTC 0 #define FF_NORTC_MON 1 #define FF_NORTC_MDAY 1 -#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 -/ the timestamp function. Every object modified by FatFs will have a fixed timestamp +#define FF_NORTC_YEAR 2025 +/* The option FF_FS_NORTC switches timestamp feature. If the system does not have +/ an RTC or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable the +/ timestamp feature. Every object modified by FatFs will have a fixed timestamp / defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time. -/ 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, +/ To enable timestamp function (FF_FS_NORTC = 0), get_fattime() 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 in read-only configuration (FF_FS_READONLY = 1). */ +#define FF_FS_CRTIME 0 +/* This option enables(1)/disables(0) the timestamp of the file created. When +/ set 1, the file created time is available in FILINFO structure. */ + + #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 +/* If you need to know the correct free space on the FAT32 volume, set bit 0 of +/ this option, and f_getfree() on the 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. @@ -323,19 +340,16 @@ /* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs / module itself. Note that regardless of this option, file access to different / volume is always re-entrant and volume control functions, f_mount(), f_mkfs() -/ and f_fdisk() function, are always not re-entrant. Only file/directory access -/ to the same volume is under control of this function. +/ and f_fdisk(), are always not re-entrant. Only file/directory access to +/ the same volume is under control of this featuer. / -/ 0: Disable re-entrancy. FF_FS_TIMEOUT and FF_SYNC_t have no effect. +/ 0: Disable re-entrancy. FF_FS_TIMEOUT have no effect. / 1: Enable re-entrancy. Also user provided synchronization handlers, -/ ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj() -/ function, must be added to the project. Samples are available in -/ option/syscall.c. +/ ff_mutex_create(), ff_mutex_delete(), ff_mutex_take() and ff_mutex_give(), +/ must be added to the project. Samples are available in ffsystem.c. / -/ The FF_FS_TIMEOUT defines timeout period in unit of time tick. -/ The FF_SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*, -/ SemaphoreHandle_t and etc. A header file for O/S definitions needs to be -/ included somewhere in the scope of ff.h. */ +/ The FF_FS_TIMEOUT defines timeout period in unit of O/S time tick. +*/ diff --git a/components/dfs/dfs_v1/filesystems/elmfat/ffunicode.c b/components/dfs/dfs_v1/filesystems/elmfat/ffunicode.c index a69b24c8306..e6bcacae6b3 100644 --- a/components/dfs/dfs_v1/filesystems/elmfat/ffunicode.c +++ b/components/dfs/dfs_v1/filesystems/elmfat/ffunicode.c @@ -1,13 +1,13 @@ /*------------------------------------------------------------------------*/ -/* Unicode handling functions for FatFs R0.13+ */ +/* Unicode Handling Functions for FatFs R0.13 and Later */ +/*------------------------------------------------------------------------*/ +/* This module will occupy a huge memory in the .rodata section when the */ +/* FatFs is configured for LFN with DBCS. If the system has a Unicode */ +/* library for the code conversion, this module should be modified to use */ +/* it to avoid silly memory consumption. */ /*------------------------------------------------------------------------*/ -/* 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 / -/ utilitiy for the code conversion, this module should be modified to use / -/ that function to avoid silly memory consumption. / -/-------------------------------------------------------------------------*/ /* -/ Copyright (C) 2014, ChaN, all right reserved. +/ Copyright (C) 2022, 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,7 +25,7 @@ #include "ff.h" -#if FF_USE_LFN /* This module will be blanked if non-LFN configuration */ +#if FF_USE_LFN != 0 /* This module will be blanked if in non-LFN configuration */ #define MERGE2(a, b) a ## b #define CVTBL(tbl, cp) MERGE2(tbl, cp) @@ -15214,8 +15214,8 @@ static const WCHAR uc869[] = { /* CP869(Greek 2) to Unicode conversion table */ /*------------------------------------------------------------------------*/ -/* OEM <==> Unicode conversions for static code page configuration */ -/* SBCS fixed code page */ +/* OEM <==> Unicode Conversions for Static Code Page Configuration with */ +/* SBCS Fixed Code Page */ /*------------------------------------------------------------------------*/ #if FF_CODE_PAGE != 0 && FF_CODE_PAGE < 900 @@ -15225,7 +15225,7 @@ WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */ ) { WCHAR c = 0; - const WCHAR *p = CVTBL(uc, FF_CODE_PAGE); + const WCHAR* p = CVTBL(uc, FF_CODE_PAGE); if (uni < 0x80) { /* ASCII? */ @@ -15247,7 +15247,7 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */ ) { WCHAR c = 0; - const WCHAR *p = CVTBL(uc, FF_CODE_PAGE); + const WCHAR* p = CVTBL(uc, FF_CODE_PAGE); if (oem < 0x80) { /* ASCII? */ @@ -15267,8 +15267,8 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */ /*------------------------------------------------------------------------*/ -/* OEM <==> Unicode conversions for static code page configuration */ -/* DBCS fixed code page */ +/* OEM <==> Unicode Conversions for Static Code Page Configuration with */ +/* DBCS Fixed Code Page */ /*------------------------------------------------------------------------*/ #if FF_CODE_PAGE >= 900 @@ -15277,7 +15277,7 @@ WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */ WORD cp /* Code page for the conversion */ ) { - const WCHAR *p; + const WCHAR* p; WCHAR c = 0, uc; UINT i = 0, n, li, hi; @@ -15313,7 +15313,7 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */ WORD cp /* Code page for the conversion */ ) { - const WCHAR *p; + const WCHAR* p; WCHAR c = 0; UINT i = 0, n, li, hi; @@ -15346,7 +15346,7 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */ /*------------------------------------------------------------------------*/ -/* OEM <==> Unicode conversions for dynamic code page configuration */ +/* OEM <==> Unicode Conversions for Dynamic Code Page Configuration */ /*------------------------------------------------------------------------*/ #if FF_CODE_PAGE == 0 @@ -15360,7 +15360,7 @@ WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */ WORD cp /* Code page for the conversion */ ) { - const WCHAR *p; + const WCHAR* p; WCHAR c = 0, uc; UINT i, n, li, hi; @@ -15412,7 +15412,7 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */ WORD cp /* Code page for the conversion */ ) { - const WCHAR *p; + const WCHAR* p; WCHAR c = 0; UINT i, n, li, hi; @@ -15458,14 +15458,14 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */ /*------------------------------------------------------------------------*/ -/* Unicode up-case conversion */ +/* Unicode Up-case Conversion */ /*------------------------------------------------------------------------*/ DWORD ff_wtoupper ( /* Returns up-converted code point */ DWORD uni /* Unicode code point to be up-converted */ ) { - const WORD *p; + const WORD* p; WORD uc, bc, nc, cmd; static const WORD cvt1[] = { /* Compressed up conversion table for U+0000 - U+0FFF */ /* Basic Latin */ @@ -15590,4 +15590,4 @@ DWORD ff_wtoupper ( /* Returns up-converted code point */ } -#endif /* #if FF_USE_LFN */ +#endif /* #if FF_USE_LFN != 0 */ diff --git a/components/dfs/dfs_v2/filesystems/elmfat/00history.txt b/components/dfs/dfs_v2/filesystems/elmfat/00history.txt index 7a153a2292e..11982e0410d 100644 --- a/components/dfs/dfs_v2/filesystems/elmfat/00history.txt +++ b/components/dfs/dfs_v2/filesystems/elmfat/00history.txt @@ -367,3 +367,23 @@ R0.15 (November 6, 2022) Fixed string functions cannot write the unicode characters not in BMP when FF_LFN_UNICODE == 2 (UTF-8). Fixed a compatibility issue in identification of GPT header. + + +R0.15a (November 22, 2024) + Fixed a complie error when FF_FS_LOCK != 0. + Fixed a potential issue when work FatFs concurrency with FF_FS_REENTRANT, FF_VOLUMES >= 2 and FF_FS_LOCK > 0. + Made f_setlabel() accept a volume label in Unix style volume ID when FF_STR_VOLUME_ID == 2. + Made FatFs update PercInUse field in exFAT VBR. (A preceding f_getfree() is needed for the accuracy) + + + +R0.15b (June 21, 2025) + Added support for timestamp of created time. (FF_FS_CRTIME) + Fixed FatFs fails to load the FsInfo in FAT32 volumes and the f_getfree always be forced a full FAT scan which takes a long time. (appeared at R0.15a) + + + +R0.16 (July 22, 2025) + Removed a long-pending limitation that f_getcwd and double-dot .. in the path name did not work on the exFAT volume. + Fixed f_readdir cannot detect end of directory and it leads the application process into infinite loop. (appeared at R0.15b) + Fixed dot names with terminating separator or duplicated separator are rejected when LFN is not enabled. diff --git a/components/dfs/dfs_v2/filesystems/elmfat/00readme.txt b/components/dfs/dfs_v2/filesystems/elmfat/00readme.txt index 3de3aeaa2dd..2dae010cc7a 100644 --- a/components/dfs/dfs_v2/filesystems/elmfat/00readme.txt +++ b/components/dfs/dfs_v2/filesystems/elmfat/00readme.txt @@ -1,4 +1,4 @@ -FatFs Module Source Files R0.15 +FatFs Module Source Files R0.16 FILES diff --git a/components/dfs/dfs_v2/filesystems/elmfat/diskio.h b/components/dfs/dfs_v2/filesystems/elmfat/diskio.h index e4ead783803..195f4325475 100644 --- a/components/dfs/dfs_v2/filesystems/elmfat/diskio.h +++ b/components/dfs/dfs_v2/filesystems/elmfat/diskio.h @@ -1,5 +1,5 @@ /*-----------------------------------------------------------------------/ -/ Low level disk interface modlue include file (C)ChaN, 2019 / +/ Low level disk interface modlue include file (C)ChaN, 2025 / /-----------------------------------------------------------------------*/ #ifndef _DISKIO_DEFINED @@ -55,7 +55,7 @@ DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff); #define CTRL_EJECT 7 /* Eject media */ #define CTRL_FORMAT 8 /* Create physical format on the media */ -/* MMC/SDC specific ioctl command */ +/* MMC/SDC specific ioctl command (Not used by FatFs) */ #define MMC_GET_TYPE 10 /* Get card type */ #define MMC_GET_CSD 11 /* Get CSD */ #define MMC_GET_CID 12 /* Get CID */ @@ -65,7 +65,7 @@ DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff); #define ISDIO_WRITE 56 /* Write data to SD iSDIO register */ #define ISDIO_MRITE 57 /* Masked write data to SD iSDIO register */ -/* ATA/CF specific ioctl command */ +/* ATA/CF specific ioctl command (Not used by FatFs) */ #define ATA_GET_REV 20 /* Get F/W revision */ #define ATA_GET_MODEL 21 /* Get model name */ #define ATA_GET_SN 22 /* Get serial number */ diff --git a/components/dfs/dfs_v2/filesystems/elmfat/ff.c b/components/dfs/dfs_v2/filesystems/elmfat/ff.c index 9fd16c6deba..c4df9864346 100644 --- a/components/dfs/dfs_v2/filesystems/elmfat/ff.c +++ b/components/dfs/dfs_v2/filesystems/elmfat/ff.c @@ -1,8 +1,8 @@ /*----------------------------------------------------------------------------/ -/ FatFs - Generic FAT Filesystem Module R0.15 w/patch1 / +/ FatFs - Generic FAT Filesystem Module R0.16 / /-----------------------------------------------------------------------------/ / -/ Copyright (C) 2022, ChaN, all right reserved. +/ Copyright (C) 2025, 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,9 +20,8 @@ #include -#include "ff.h" /* Declarations of FatFs API */ -#include "diskio.h" /* Declarations of device I/O functions */ - +#include "ff.h" /* Basic definitions and declarations of API */ +#include "diskio.h" /* Declarations of MAI */ /*-------------------------------------------------------------------------- @@ -30,17 +29,17 @@ ---------------------------------------------------------------------------*/ -#if FF_DEFINED != 80286 /* Revision ID */ +#if FF_DEFINED != 80386 /* Revision ID */ #error Wrong include file (ff.h). #endif /* Limits and boundaries */ -#define MAX_DIR 0x200000 /* Max size of FAT directory */ -#define MAX_DIR_EX 0x10000000 /* Max size of exFAT directory */ +#define MAX_DIR 0x200000 /* Max size of FAT directory (byte) */ +#define MAX_DIR_EX 0x10000000 /* Max size of exFAT directory (byte) */ #define MAX_FAT12 0xFF5 /* Max FAT12 clusters (differs from specs, but right for real DOS/Windows behavior) */ #define MAX_FAT16 0xFFF5 /* Max FAT16 clusters (differs from specs, but right for real DOS/Windows behavior) */ -#define MAX_FAT32 0x0FFFFFF5 /* Max FAT32 clusters (not specified, practical limit) */ +#define MAX_FAT32 0x0FFFFFF5 /* Max FAT32 clusters (not defined in specs, practical limit) */ #define MAX_EXFAT 0x7FFFFFFD /* Max exFAT clusters (differs from specs, implementation limit) */ @@ -89,7 +88,7 @@ #define ET_FILENAME 0xC1 /* Name extension */ -/* FatFs refers the FAT structure as simple byte array instead of structure member +/* FatFs refers the FAT structures as simple byte array instead of structure member / because the C structure is not binary compatible between different platforms */ #define BS_JmpBoot 0 /* x86 jump instruction (3-byte) */ @@ -113,7 +112,7 @@ #define BS_VolLab 43 /* Volume label string (8-byte) */ #define BS_FilSysType 54 /* Filesystem type string (8-byte) */ #define BS_BootCode 62 /* Boot code (448-byte) */ -#define BS_55AA 510 /* Signature word (WORD) */ +#define BS_55AA 510 /* Boot signature (WORD, for VBR and MBR) */ #define BPB_FATSz32 36 /* FAT32: FAT size [sector] (DWORD) */ #define BPB_ExtFlags32 40 /* FAT32: Extended flags (WORD) */ @@ -139,18 +138,18 @@ #define BPB_RootClusEx 96 /* exFAT: Root directory start cluster (DWORD) */ #define BPB_VolIDEx 100 /* exFAT: Volume serial number (DWORD) */ #define BPB_FSVerEx 104 /* exFAT: Filesystem version (WORD) */ -#define BPB_VolFlagEx 106 /* exFAT: Volume flags (WORD) */ +#define BPB_VolFlagEx 106 /* exFAT: Volume flags (WORD, out of check sum calculation) */ #define BPB_BytsPerSecEx 108 /* exFAT: Log2 of sector size in unit of byte (BYTE) */ #define BPB_SecPerClusEx 109 /* exFAT: Log2 of cluster size in unit of sector (BYTE) */ #define BPB_NumFATsEx 110 /* exFAT: Number of FATs (BYTE) */ #define BPB_DrvNumEx 111 /* exFAT: Physical drive number for int13h (BYTE) */ -#define BPB_PercInUseEx 112 /* exFAT: Percent in use (BYTE) */ +#define BPB_PercInUseEx 112 /* exFAT: Percent in use (BYTE, out of check sum calculation) */ #define BPB_RsvdEx 113 /* exFAT: Reserved (7-byte) */ #define BS_BootCodeEx 120 /* exFAT: Boot code (390-byte) */ #define DIR_Name 0 /* Short file name (11-byte) */ #define DIR_Attr 11 /* Attribute (BYTE) */ -#define DIR_NTres 12 /* Lower case flag (BYTE) */ +#define DIR_NTres 12 /* Low case flags of SFN (BYTE) */ #define DIR_CrtTime10 13 /* Created time sub-second (BYTE) */ #define DIR_CrtTime 14 /* Created time (DWORD) */ #define DIR_LstAccDate 18 /* Last accessed date (WORD) */ @@ -194,17 +193,18 @@ #define FSI_StrucSig 484 /* FAT32 FSI: Structure signature (DWORD) */ #define FSI_Free_Count 488 /* FAT32 FSI: Number of free clusters (DWORD) */ #define FSI_Nxt_Free 492 /* FAT32 FSI: Last allocated cluster (DWORD) */ +#define FSI_TrailSig 508 /* FAT32 FSI: Trailing signature (DWORD) */ #define MBR_Table 446 /* MBR: Offset of partition table in the MBR */ #define SZ_PTE 16 /* MBR: Size of a partition table entry */ #define PTE_Boot 0 /* MBR PTE: Boot indicator */ -#define PTE_StHead 1 /* MBR PTE: Start head */ -#define PTE_StSec 2 /* MBR PTE: Start sector */ -#define PTE_StCyl 3 /* MBR PTE: Start cylinder */ +#define PTE_StHead 1 /* MBR PTE: Start head in CHS */ +#define PTE_StSec 2 /* MBR PTE: Start sector in CHS */ +#define PTE_StCyl 3 /* MBR PTE: Start cylinder in CHS */ #define PTE_System 4 /* MBR PTE: System ID */ -#define PTE_EdHead 5 /* MBR PTE: End head */ -#define PTE_EdSec 6 /* MBR PTE: End sector */ -#define PTE_EdCyl 7 /* MBR PTE: End cylinder */ +#define PTE_EdHead 5 /* MBR PTE: End head in CHS */ +#define PTE_EdSec 6 /* MBR PTE: End sector in CHS */ +#define PTE_EdCyl 7 /* MBR PTE: End cylinder in CHS */ #define PTE_StLba 8 /* MBR PTE: Start in LBA */ #define PTE_SizLba 12 /* MBR PTE: Size in LBA */ @@ -221,7 +221,7 @@ #define GPTH_PtNum 80 /* GPT HDR: Number of table entries (DWORD) */ #define GPTH_PteSize 84 /* GPT HDR: Size of table entry (DWORD) */ #define GPTH_PtBcc 88 /* GPT HDR: Partition table BCC (DWORD) */ -#define SZ_GPTE 128 /* GPT PTE: Size of partition table entry */ +#define SZ_GPTE 128 /* GPT PTE: Size of a GPT 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 of partition (QWORD) */ @@ -245,10 +245,10 @@ #endif -/* Definitions of logical drive - physical location conversion */ +/* Definitions of logical drive to 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 number (0:auto search, 1..:forced partition number) */ +#define LD2PD(vol) VolToPart[vol].pd /* Get physical drive number from the mapping table */ +#define LD2PT(vol) VolToPart[vol].pt /* Get partition number from the mapping table (0:auto search, 1-:forced partition number) */ #else #define LD2PD(vol) (BYTE)(vol) /* Each logical drive is associated with the same physical drive number */ #define LD2PT(vol) 0 /* Auto partition search */ @@ -282,11 +282,11 @@ #if FF_FS_READONLY #error FF_FS_LOCK must be 0 at read-only configuration #endif -typedef struct { - FATFS* fs; /* Object ID 1, volume (NULL:blank entry) */ - DWORD clu; /* Object ID 2, containing directory (0:root) */ - DWORD ofs; /* Object ID 3, offset in the directory */ - UINT ctr; /* Object open counter, 0:none, 0x01..0xFF:read mode open count, 0x100:write mode */ +typedef struct { /* Open object identifier with status */ + FATFS* fs; /* Object ID 1, volume (NULL:blank entry) */ + DWORD clu; /* Object ID 2, containing directory (0:root) */ + DWORD ofs; /* Object ID 3, offset in the directory */ + UINT ctr; /* Object open status, 0:none, 0x01..0xFF:read mode open count, 0x100:write mode */ } FILESEM; #endif @@ -464,14 +464,15 @@ typedef struct { static FATFS *FatFs[FF_VOLUMES]; /* Pointer to the filesystem objects (logical drives) */ static WORD Fsid; /* Filesystem mount ID */ -#if FF_FS_RPATH != 0 -static BYTE CurrVol; /* Current drive set by f_chdrive() */ +#if FF_FS_RPATH +static BYTE CurrVol; /* Current drive number set by f_chdrive() */ #endif -#if FF_FS_LOCK != 0 +#if FF_FS_LOCK static FILESEM Files[FF_FS_LOCK]; /* Open object lock semaphores */ #if FF_FS_REENTRANT -static BYTE SysLock; /* System lock flag (0:no mutex, 1:unlocked, 2:locked) */ +static volatile BYTE SysLock; /* System lock flag to protect Files[] (0:no mutex, 1:unlocked, 2:locked) */ +static volatile BYTE SysLockVolume; /* Volume id who is locking Files[] */ #endif #endif @@ -498,9 +499,9 @@ static const BYTE GUID_MS_Basic[16] = {0xA2,0xA0,0xD0,0xEB,0xE5,0xB9,0x33,0x44,0 #if FF_FS_EXFAT #error LFN must be enabled when enable exFAT #endif -#define DEF_NAMBUF -#define INIT_NAMBUF(fs) -#define FREE_NAMBUF() +#define DEF_NAMEBUFF +#define INIT_NAMEBUFF(fs) +#define FREE_NAMEBUFF() #define LEAVE_MKFS(res) return res #else /* LFN configurations */ @@ -521,32 +522,32 @@ static const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30}; /* FAT: Offset static BYTE DirBuf[MAXDIRB(FF_MAX_LFN)]; /* Directory entry block scratchpad buffer */ #endif static WCHAR LfnBuf[FF_MAX_LFN + 1]; /* LFN working buffer */ -#define DEF_NAMBUF -#define INIT_NAMBUF(fs) -#define FREE_NAMBUF() +#define DEF_NAMEBUFF +#define INIT_NAMEBUFF(fs) +#define FREE_NAMEBUFF() #define LEAVE_MKFS(res) return res #elif FF_USE_LFN == 2 /* LFN enabled with dynamic working buffer on the stack */ #if FF_FS_EXFAT -#define DEF_NAMBUF WCHAR lbuf[FF_MAX_LFN+1]; BYTE dbuf[MAXDIRB(FF_MAX_LFN)]; /* LFN working buffer and directory entry block scratchpad buffer */ -#define INIT_NAMBUF(fs) { (fs)->lfnbuf = lbuf; (fs)->dirbuf = dbuf; } -#define FREE_NAMBUF() +#define DEF_NAMEBUFF WCHAR lbuf[FF_MAX_LFN+1]; BYTE dbuf[MAXDIRB(FF_MAX_LFN)]; /* LFN working buffer and directory entry block scratchpad buffer */ +#define INIT_NAMEBUFF(fs) { (fs)->lfnbuf = lbuf; (fs)->dirbuf = dbuf; } +#define FREE_NAMEBUFF() #else -#define DEF_NAMBUF WCHAR lbuf[FF_MAX_LFN+1]; /* LFN working buffer */ -#define INIT_NAMBUF(fs) { (fs)->lfnbuf = lbuf; } -#define FREE_NAMBUF() +#define DEF_NAMEBUFF WCHAR lbuf[FF_MAX_LFN+1]; /* LFN working buffer */ +#define INIT_NAMEBUFF(fs) { (fs)->lfnbuf = lbuf; } +#define FREE_NAMEBUFF() #endif #define LEAVE_MKFS(res) return res #elif FF_USE_LFN == 3 /* LFN enabled with dynamic working buffer on the heap */ #if FF_FS_EXFAT -#define DEF_NAMBUF WCHAR *lfn; /* Pointer to LFN working buffer and directory entry block scratchpad buffer */ -#define INIT_NAMBUF(fs) { lfn = ff_memalloc((FF_MAX_LFN+1)*2 + MAXDIRB(FF_MAX_LFN)); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; (fs)->dirbuf = (BYTE*)(lfn+FF_MAX_LFN+1); } -#define FREE_NAMBUF() ff_memfree(lfn) +#define DEF_NAMEBUFF WCHAR *lfn; /* Pointer to LFN working buffer and directory entry block scratchpad buffer */ +#define INIT_NAMEBUFF(fs) { lfn = ff_memalloc((FF_MAX_LFN+1)*2 + MAXDIRB(FF_MAX_LFN)); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; (fs)->dirbuf = (BYTE*)(lfn+FF_MAX_LFN+1); } +#define FREE_NAMEBUFF() ff_memfree(lfn) #else -#define DEF_NAMBUF WCHAR *lfn; /* Pointer to LFN working buffer */ -#define INIT_NAMBUF(fs) { lfn = ff_memalloc((FF_MAX_LFN+1)*2); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; } -#define FREE_NAMBUF() ff_memfree(lfn) +#define DEF_NAMEBUFF WCHAR *lfn; /* Pointer to LFN working buffer */ +#define INIT_NAMEBUFF(fs) { lfn = ff_memalloc((FF_MAX_LFN+1)*2); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; } +#define FREE_NAMEBUFF() ff_memfree(lfn) #endif #define LEAVE_MKFS(res) { if (!work) ff_memfree(buf); return res; } #define MAX_MALLOC 0x8000 /* Must be >=FF_MAX_SS */ @@ -566,8 +567,8 @@ static WCHAR LfnBuf[FF_MAX_LFN + 1]; /* LFN working buffer */ #if FF_CODE_PAGE == 0 /* Run-time code page configuration */ #define CODEPAGE CodePage static WORD CodePage; /* Current code page */ -static const BYTE* ExCvt; /* Ptr to SBCS up-case table Ct???[] (null:not used) */ -static const BYTE* DbcTbl; /* Ptr to DBCS code range table Dc???[] (null:not used) */ +static const BYTE* ExCvt; /* Pointer to SBCS up-case table Ct???[] (null:disabled) */ +static const BYTE* DbcTbl; /* Pointer to DBCS code range table Dc???[] (null:disabled) */ static const BYTE Ct437[] = TBL_CT437; static const BYTE Ct720[] = TBL_CT720; @@ -615,7 +616,7 @@ static const BYTE DbcTbl[] = MKCVTBL(TBL_DC, FF_CODE_PAGE); /* Load/Store multi-byte word in the FAT structure */ /*-----------------------------------------------------------------------*/ -static WORD ld_word (const BYTE* ptr) /* Load a 2-byte little-endian word */ +static WORD ld_16 (const BYTE* ptr) /* Load a 2-byte little-endian word */ { WORD rv; @@ -624,7 +625,7 @@ static WORD ld_word (const BYTE* ptr) /* Load a 2-byte little-endian word */ return rv; } -static DWORD ld_dword (const BYTE* ptr) /* Load a 4-byte little-endian word */ +static DWORD ld_32 (const BYTE* ptr) /* Load a 4-byte little-endian word */ { DWORD rv; @@ -636,7 +637,7 @@ static DWORD ld_dword (const BYTE* ptr) /* Load a 4-byte little-endian word */ } #if FF_FS_EXFAT -static QWORD ld_qword (const BYTE* ptr) /* Load an 8-byte little-endian word */ +static QWORD ld_64 (const BYTE* ptr) /* Load an 8-byte little-endian word */ { QWORD rv; @@ -653,13 +654,13 @@ static QWORD ld_qword (const BYTE* ptr) /* Load an 8-byte little-endian word */ #endif #if !FF_FS_READONLY -static void st_word (BYTE* ptr, WORD val) /* Store a 2-byte word in little-endian */ +static void st_16 (BYTE* ptr, WORD val) /* Store a 2-byte word in little-endian */ { *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; } -static void st_dword (BYTE* ptr, DWORD val) /* Store a 4-byte word in little-endian */ +static void st_32 (BYTE* ptr, DWORD val) /* Store a 4-byte word in little-endian */ { *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; val >>= 8; @@ -668,7 +669,7 @@ static void st_dword (BYTE* ptr, DWORD val) /* Store a 4-byte word in little-end } #if FF_FS_EXFAT -static void st_qword (BYTE* ptr, QWORD val) /* Store an 8-byte word in little-endian */ +static void st_64 (BYTE* ptr, QWORD val) /* Store an 8-byte word in little-endian */ { *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; val >>= 8; @@ -743,7 +744,7 @@ static DWORD tchar2uni ( /* Returns a character in UTF-16 encoding (>=0x10000 on #if FF_LFN_UNICODE == 1 /* UTF-16 input */ WCHAR wc; - uc = *p++; /* Get a unit */ + uc = *p++; /* Get an encoding unit */ if (IsSurrogate(uc)) { /* Surrogate? */ wc = *p++; /* Get low surrogate */ if (!IsSurrogateH(uc) || !IsSurrogateL(wc)) return 0xFFFFFFFF; /* Wrong surrogate? */ @@ -751,7 +752,7 @@ static DWORD tchar2uni ( /* Returns a character in UTF-16 encoding (>=0x10000 on } #elif FF_LFN_UNICODE == 2 /* UTF-8 input */ - BYTE b; + BYTE tb; int nf; uc = (BYTE)*p++; /* Get an encoding unit */ @@ -765,10 +766,10 @@ static DWORD tchar2uni ( /* Returns a character in UTF-16 encoding (>=0x10000 on } else { /* Wrong sequence */ return 0xFFFFFFFF; } - do { /* Get trailing bytes */ - b = (BYTE)*p++; - if ((b & 0xC0) != 0x80) return 0xFFFFFFFF; /* Wrong sequence? */ - uc = uc << 6 | (b & 0x3F); + do { /* Get and merge trailing bytes */ + tb = (BYTE)*p++; + if ((tb & 0xC0) != 0x80) return 0xFFFFFFFF; /* Wrong sequence? */ + uc = uc << 6 | (tb & 0x3F); } while (--nf != 0); if (uc < 0x80 || IsSurrogate(uc) || uc >= 0x110000) return 0xFFFFFFFF; /* Wrong code? */ if (uc >= 0x010000) uc = 0xD800DC00 | ((uc - 0x10000) << 6 & 0x3FF0000) | (uc & 0x3FF); /* Make a surrogate pair if needed */ @@ -780,14 +781,14 @@ static DWORD tchar2uni ( /* Returns a character in UTF-16 encoding (>=0x10000 on if (uc >= 0x010000) uc = 0xD800DC00 | ((uc - 0x10000) << 6 & 0x3FF0000) | (uc & 0x3FF); /* Make a surrogate pair if needed */ #else /* ANSI/OEM input */ - BYTE b; + BYTE sb; WCHAR wc; wc = (BYTE)*p++; /* Get a byte */ if (dbc_1st((BYTE)wc)) { /* Is it a DBC 1st byte? */ - b = (BYTE)*p++; /* Get 2nd byte */ - if (!dbc_2nd(b)) return 0xFFFFFFFF; /* Invalid code? */ - wc = (wc << 8) + b; /* Make a DBC */ + sb = (BYTE)*p++; /* Get 2nd byte */ + if (!dbc_2nd(sb)) return 0xFFFFFFFF; /* Invalid code? */ + wc = (wc << 8) + sb; /* Make a DBC */ } if (wc != 0) { wc = ff_oem2uni(wc, CODEPAGE); /* ANSI/OEM ==> Unicode */ @@ -879,7 +880,7 @@ static UINT put_utf ( /* Returns number of encoding units written (0:buffer over *buf++ = (TCHAR)wc; /* Store DBC 2nd byte */ return 2; } - if (wc == 0 || szb < 1) return 0; /* Invalid char or buffer overflow? */ + if (wc == 0 || szb < 1) return 0; /* Invalid character or buffer overflow? */ *buf++ = (TCHAR)wc; /* Store the character */ return 1; #endif @@ -905,6 +906,7 @@ static int lock_volume ( /* 1:Ok, 0:timeout */ if (rv && syslock) { /* System lock reqiered? */ rv = ff_mutex_take(FF_VOLUMES); /* Lock the system */ if (rv) { + SysLockVolume = fs->ldrv; SysLock = 2; /* System lock succeeded */ } else { ff_mutex_give(fs->ldrv); /* Failed system lock */ @@ -924,7 +926,7 @@ static void unlock_volume ( { if (fs && res != FR_NOT_ENABLED && res != FR_INVALID_DRIVE && res != FR_TIMEOUT) { #if FF_FS_LOCK - if (SysLock == 2) { /* Is the system locked? */ + if (SysLock == 2 && SysLockVolume == fs->ldrv) { /* Unlock system if it has been locked by this task */ SysLock = 1; ff_mutex_give(FF_VOLUMES); } @@ -939,7 +941,7 @@ static void unlock_volume ( #if FF_FS_LOCK /*-----------------------------------------------------------------------*/ -/* File shareing control functions */ +/* File sharing control functions */ /*-----------------------------------------------------------------------*/ static FRESULT chk_share ( /* Check if the file can be accessed */ @@ -1114,17 +1116,30 @@ static FRESULT sync_fs ( /* Returns FR_OK or FR_DISK_ERR */ res = sync_window(fs); if (res == FR_OK) { - if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) { /* FAT32: Update FSInfo sector if needed */ - /* Create FSInfo structure */ - memset(fs->win, 0, sizeof fs->win); - st_word(fs->win + BS_55AA, 0xAA55); /* Boot signature */ - st_dword(fs->win + FSI_LeadSig, 0x41615252); /* Leading signature */ - st_dword(fs->win + FSI_StrucSig, 0x61417272); /* Structure signature */ - st_dword(fs->win + FSI_Free_Count, fs->free_clst); /* Number of free clusters */ - st_dword(fs->win + FSI_Nxt_Free, fs->last_clst); /* Last allocated culuster */ - fs->winsect = fs->volbase + 1; /* Write it into the FSInfo sector (Next to VBR) */ - disk_write(fs->pdrv, fs->win, fs->winsect, 1); + if (fs->fsi_flag == 1) { /* Allocation changed? */ fs->fsi_flag = 0; + if (fs->fs_type == FS_FAT32) { /* FAT32: Update FSInfo sector */ + /* Create FSInfo structure */ + memset(fs->win, 0, sizeof fs->win); + st_32(fs->win + FSI_LeadSig, 0x41615252); /* Leading signature */ + st_32(fs->win + FSI_StrucSig, 0x61417272); /* Structure signature */ + st_32(fs->win + FSI_Free_Count, fs->free_clst); /* Number of free clusters */ + st_32(fs->win + FSI_Nxt_Free, fs->last_clst); /* Last allocated culuster */ + st_32(fs->win + FSI_TrailSig, 0xAA550000); /* Trailing signature */ + disk_write(fs->pdrv, fs->win, fs->winsect = fs->volbase + 1, 1); /* Write it into the FSInfo sector (Next to VBR) */ + } +#if FF_FS_EXFAT + else if (fs->fs_type == FS_EXFAT) { /* exFAT: Update PercInUse field in BPB */ + if (disk_read(fs->pdrv, fs->win, fs->winsect = fs->volbase, 1) == RES_OK) { /* Load VBR */ + BYTE perc_inuse = (fs->free_clst <= fs->n_fatent - 2) ? (BYTE)((QWORD)(fs->n_fatent - 2 - fs->free_clst) * 100 / (fs->n_fatent - 2)) : 0xFF; /* Precent in use 0-100 or 0xFF(unknown) */ + + if (fs->win[BPB_PercInUseEx] != perc_inuse) { /* Write it back into VBR if needed */ + fs->win[BPB_PercInUseEx] = perc_inuse; + disk_write(fs->pdrv, fs->win, fs->winsect, 1); + } + } + } +#endif } /* Make sure that no pending write process in the lower layer */ if (disk_ioctl(fs->pdrv, CTRL_SYNC, 0) != RES_OK) res = FR_DISK_ERR; @@ -1186,12 +1201,12 @@ static DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x7FFFFFF case FS_FAT16 : if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))) != FR_OK) break; - val = ld_word(fs->win + clst * 2 % SS(fs)); /* Simple WORD array */ + val = ld_16(fs->win + clst * 2 % SS(fs)); /* Simple WORD array */ break; case FS_FAT32 : if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break; - val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x0FFFFFFF; /* Simple DWORD array but mask out upper 4 bits */ + val = ld_32(fs->win + clst * 4 % SS(fs)) & 0x0FFFFFFF; /* Simple DWORD array but mask out upper 4 bits */ break; #if FF_FS_EXFAT case FS_EXFAT : @@ -1212,7 +1227,7 @@ static DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x7FFFFFF val = 0x7FFFFFFF; /* Generate EOC */ } else { if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break; - val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x7FFFFFFF; + val = ld_32(fs->win + clst * 4 % SS(fs)) & 0x7FFFFFFF; } break; } @@ -1266,7 +1281,7 @@ static FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */ case FS_FAT16: res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))); if (res != FR_OK) break; - st_word(fs->win + clst * 2 % SS(fs), (WORD)val); /* Simple WORD array */ + st_16(fs->win + clst * 2 % SS(fs), (WORD)val); /* Simple WORD array */ fs->wflag = 1; break; @@ -1277,9 +1292,9 @@ static FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */ res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))); if (res != FR_OK) break; if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { - val = (val & 0x0FFFFFFF) | (ld_dword(fs->win + clst * 4 % SS(fs)) & 0xF0000000); + val = (val & 0x0FFFFFFF) | (ld_32(fs->win + clst * 4 % SS(fs)) & 0xF0000000); } - st_dword(fs->win + clst * 4 % SS(fs), val); + st_32(fs->win + clst * 4 % SS(fs), val); fs->wflag = 1; break; } @@ -1460,7 +1475,7 @@ static FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ res = put_fat(fs, clst, 0); /* Mark the cluster 'free' on the FAT */ if (res != FR_OK) return res; } - if (fs->free_clst < fs->n_fatent - 2) { /* Update FSINFO */ + if (fs->free_clst < fs->n_fatent - 2) { /* Update allocation information if it is valid */ fs->free_clst++; fs->fsi_flag |= 1; } @@ -1483,7 +1498,7 @@ static FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ } #endif clst = nxt; /* Next cluster */ - } while (clst < fs->n_fatent); /* Repeat while not the last link */ + } while (clst < fs->n_fatent); /* Repeat until the last link */ #if FF_FS_EXFAT /* Some post processes for chain status */ @@ -1603,10 +1618,12 @@ static DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:D } } - if (res == FR_OK) { /* Update FSINFO if function succeeded. */ + if (res == FR_OK) { /* Update allocation information if the function succeeded */ fs->last_clst = ncl; - if (fs->free_clst <= fs->n_fatent - 2) fs->free_clst--; - fs->fsi_flag |= 1; + if (fs->free_clst > 0 && fs->free_clst <= fs->n_fatent - 2) { + fs->free_clst--; + fs->fsi_flag |= 1; + } } else { ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1; /* Failed. Generate error status */ } @@ -1852,9 +1869,9 @@ static DWORD ld_clust ( /* Returns the top cluster value of the SFN entry */ { DWORD cl; - cl = ld_word(dir + DIR_FstClusLO); + cl = ld_16(dir + DIR_FstClusLO); if (fs->fs_type == FS_FAT32) { - cl |= (DWORD)ld_word(dir + DIR_FstClusHI) << 16; + cl |= (DWORD)ld_16(dir + DIR_FstClusHI) << 16; } return cl; @@ -1868,9 +1885,9 @@ static void st_clust ( DWORD cl /* Value to be set */ ) { - st_word(dir + DIR_FstClusLO, (WORD)cl); + st_16(dir + DIR_FstClusLO, (WORD)cl); if (fs->fs_type == FS_FAT32) { - st_word(dir + DIR_FstClusHI, (WORD)(cl >> 16)); + st_16(dir + DIR_FstClusHI, (WORD)(cl >> 16)); } } #endif @@ -1883,31 +1900,31 @@ static void st_clust ( /*--------------------------------------------------------*/ static int cmp_lfn ( /* 1:matched, 0:not matched */ - const WCHAR* lfnbuf, /* Pointer to the LFN working buffer to be compared */ - BYTE* dir /* Pointer to the directory entry containing the part of LFN */ + const WCHAR* lfnbuf, /* Pointer to the LFN to be compared */ + BYTE* dir /* Pointer to the LFN entry */ ) { - UINT i, s; - WCHAR wc, uc; + UINT ni, di; + WCHAR pchr, chr; - if (ld_word(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO */ + if (ld_16(dir + LDIR_FstClusLO) != 0) return 0; /* Check if LDIR_FstClusLO is 0 */ - i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */ + ni = (UINT)((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the name to be compared */ - for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */ - uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */ - if (wc != 0) { - if (i >= FF_MAX_LFN + 1 || ff_wtoupper(uc) != ff_wtoupper(lfnbuf[i++])) { /* Compare it */ + for (pchr = 1, di = 0; di < 13; di++) { /* Process all characters in the entry */ + chr = ld_16(dir + LfnOfs[di]); /* Pick a character from the entry */ + if (pchr != 0) { + if (ni >= FF_MAX_LFN + 1 || ff_wtoupper(chr) != ff_wtoupper(lfnbuf[ni++])) { /* Compare it with name */ return 0; /* Not matched */ } - wc = uc; + pchr = chr; } else { - if (uc != 0xFFFF) return 0; /* Check filler */ + if (chr != 0xFFFF) return 0; /* Check filler */ } } - if ((dir[LDIR_Ord] & LLEF) && wc && lfnbuf[i]) return 0; /* Last segment matched but different length */ + if ((dir[LDIR_Ord] & LLEF) && pchr && lfnbuf[ni]) return 0; /* Last name segment matched but different length */ return 1; /* The part of LFN matched */ } @@ -1919,31 +1936,31 @@ static int cmp_lfn ( /* 1:matched, 0:not matched */ /*-----------------------------------------------------*/ static int pick_lfn ( /* 1:succeeded, 0:buffer overflow or invalid LFN entry */ - WCHAR* lfnbuf, /* Pointer to the LFN working buffer */ - BYTE* dir /* Pointer to the LFN entry */ + WCHAR* lfnbuf, /* Pointer to the name buffer to be stored */ + const BYTE* dir /* Pointer to the LFN entry */ ) { - UINT i, s; - WCHAR wc, uc; + UINT ni, di; + WCHAR pchr, chr; - if (ld_word(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO is 0 */ + if (ld_16(dir + LDIR_FstClusLO) != 0) return 0; /* Check if LDIR_FstClusLO is 0 */ - i = ((dir[LDIR_Ord] & ~LLEF) - 1) * 13; /* Offset in the LFN buffer */ + ni = (UINT)((dir[LDIR_Ord] & ~LLEF) - 1) * 13; /* Offset in the name buffer */ - for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */ - uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */ - if (wc != 0) { - if (i >= FF_MAX_LFN + 1) return 0; /* Buffer overflow? */ - lfnbuf[i++] = wc = uc; /* Store it */ + for (pchr = 1, di = 0; di < 13; di++) { /* Process all characters in the entry */ + chr = ld_16(dir + LfnOfs[di]); /* Pick a character from the entry */ + if (pchr != 0) { + if (ni >= FF_MAX_LFN + 1) return 0; /* Buffer overflow? */ + lfnbuf[ni++] = pchr = chr; /* Store it */ } else { - if (uc != 0xFFFF) return 0; /* Check filler */ + if (chr != 0xFFFF) return 0; /* Check filler */ } } - if (dir[LDIR_Ord] & LLEF && wc != 0) { /* Put terminator if it is the last LFN part and not terminated */ - if (i >= FF_MAX_LFN + 1) return 0; /* Buffer overflow? */ - lfnbuf[i] = 0; + if (dir[LDIR_Ord] & LLEF && pchr != 0) { /* Put terminator if it is the last LFN part and not terminated */ + if (ni >= FF_MAX_LFN + 1) return 0; /* Buffer overflow? */ + lfnbuf[ni] = 0; } return 1; /* The part of LFN is valid */ @@ -1963,24 +1980,24 @@ static void put_lfn ( BYTE sum /* Checksum of the corresponding SFN */ ) { - UINT i, s; - WCHAR wc; + UINT ni, di; + WCHAR chr; dir[LDIR_Chksum] = sum; /* Set checksum */ - dir[LDIR_Attr] = AM_LFN; /* Set attribute. LFN entry */ + dir[LDIR_Attr] = AM_LFN; /* Set attribute */ dir[LDIR_Type] = 0; - st_word(dir + LDIR_FstClusLO, 0); - - i = (ord - 1) * 13; /* Get offset in the LFN working buffer */ - s = wc = 0; - 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 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 */ + st_16(dir + LDIR_FstClusLO, 0); + + ni = (UINT)(ord - 1) * 13; /* Offset in the name */ + di = chr = 0; + do { /* Fill the directory entry */ + if (chr != 0xFFFF) chr = lfn[ni++]; /* Get an effective character */ + st_16(dir + LfnOfs[di], chr); /* Set it */ + if (chr == 0) chr = 0xFFFF; /* Padding characters after the terminator */ + } while (++di < 13); + if (chr == 0xFFFF || !lfn[ni]) ord |= LLEF; /* Last LFN part is the start of an enrty set */ + dir[LDIR_Ord] = ord; /* Set order in the entry set */ } #endif /* !FF_FS_READONLY */ @@ -1997,31 +2014,31 @@ static void gen_numname ( BYTE* dst, /* Pointer to the buffer to store numbered SFN */ const BYTE* src, /* Pointer to SFN in directory form */ const WCHAR* lfn, /* Pointer to LFN */ - UINT seq /* Sequence number */ + WORD seq /* Sequence number */ ) { BYTE ns[8], c; UINT i, j; - WCHAR wc; - DWORD sreg; memcpy(dst, src, 11); /* Prepare the SFN to be modified */ if (seq > 5) { /* In case of many collisions, generate a hash number instead of sequential number */ - sreg = seq; - while (*lfn) { /* Create a CRC as hash value */ + WCHAR wc; + DWORD crc_sreg = seq; + + while (*lfn) { /* Create a CRC value as a hash of LFN */ wc = *lfn++; for (i = 0; i < 16; i++) { - sreg = (sreg << 1) + (wc & 1); + crc_sreg = (crc_sreg << 1) + (wc & 1); wc >>= 1; - if (sreg & 0x10000) sreg ^= 0x11021; + if (crc_sreg & 0x10000) crc_sreg ^= 0x11021; } } - seq = (UINT)sreg; + seq = (WORD)crc_sreg; } - /* Make suffix (~ + hexadecimal) */ + /* Make suffix (~ + 4-digit hexadecimal) */ i = 7; do { c = (BYTE)((seq % 16) + '0'); seq /= 16; @@ -2080,7 +2097,7 @@ static WORD xdir_sum ( /* Get checksum of the directoly entry block */ WORD sum; - szblk = (dir[XDIR_NumSec] + 1) * SZDIRE; /* Number of bytes of the entry block */ + szblk = ((UINT)dir[XDIR_NumSec] + 1) * SZDIRE; /* Number of bytes of the entry block */ for (i = sum = 0; i < szblk; i++) { if (i == XDIR_SetSum) { /* Skip 2-byte sum field */ i++; @@ -2136,13 +2153,13 @@ static FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */ BYTE *dirb = dp->obj.fs->dirbuf; /* Pointer to the on-memory directory entry block 85+C0+C1s */ - /* Load file directory entry */ + /* Load file-directory entry */ res = move_window(dp->obj.fs, dp->sect); if (res != FR_OK) return res; - if (dp->dir[XDIR_Type] != ET_FILEDIR) return FR_INT_ERR; /* Invalid order */ + if (dp->dir[XDIR_Type] != ET_FILEDIR) return FR_INT_ERR; /* Invalid order? */ memcpy(dirb + 0 * SZDIRE, dp->dir, SZDIRE); - sz_ent = (dirb[XDIR_NumSec] + 1) * SZDIRE; - if (sz_ent < 3 * SZDIRE || sz_ent > 19 * SZDIRE) return FR_INT_ERR; + sz_ent = ((UINT)dirb[XDIR_NumSec] + 1) * SZDIRE; /* Size of this entry block */ + if (sz_ent < 3 * SZDIRE || sz_ent > 19 * SZDIRE) return FR_INT_ERR; /* Invalid block size? */ /* Load stream extension entry */ res = dir_next(dp, 0); @@ -2150,9 +2167,9 @@ static FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */ if (res != FR_OK) return res; res = move_window(dp->obj.fs, dp->sect); if (res != FR_OK) return res; - if (dp->dir[XDIR_Type] != ET_STREAM) return FR_INT_ERR; /* Invalid order */ + if (dp->dir[XDIR_Type] != ET_STREAM) return FR_INT_ERR; /* Invalid order? */ memcpy(dirb + 1 * SZDIRE, dp->dir, SZDIRE); - if (MAXDIRB(dirb[XDIR_NumName]) > sz_ent) return FR_INT_ERR; + if (MAXDIRB(dirb[XDIR_NumName]) > sz_ent) return FR_INT_ERR; /* Invalid block size for the name? */ /* Load file name entries */ i = 2 * SZDIRE; /* Name offset to load */ @@ -2162,14 +2179,15 @@ static FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */ if (res != FR_OK) return res; res = move_window(dp->obj.fs, dp->sect); if (res != FR_OK) return res; - if (dp->dir[XDIR_Type] != ET_FILENAME) return FR_INT_ERR; /* Invalid order */ - if (i < MAXDIRB(FF_MAX_LFN)) memcpy(dirb + i, dp->dir, SZDIRE); + if (dp->dir[XDIR_Type] != ET_FILENAME) return FR_INT_ERR; /* Invalid order? */ + if (i < MAXDIRB(FF_MAX_LFN)) memcpy(dirb + i, dp->dir, SZDIRE); /* Load name entries only if the object is accessible */ } while ((i += SZDIRE) < sz_ent); /* Sanity check (do it for only accessible object) */ if (i <= MAXDIRB(FF_MAX_LFN)) { - if (xdir_sum(dirb) != ld_word(dirb + XDIR_SetSum)) return FR_INT_ERR; + if (xdir_sum(dirb) != ld_16(dirb + XDIR_SetSum)) return FR_INT_ERR; } + return FR_OK; } @@ -2179,19 +2197,27 @@ static FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */ /*------------------------------------------------------------------*/ static void init_alloc_info ( - FATFS* fs, /* Filesystem object */ - FFOBJID* obj /* Object allocation information to be initialized */ + FFOBJID* dobj, /* Object allocation information to be initialized */ + DIR* sdir /* Additional source about containing direcotry */ ) { - obj->sclust = ld_dword(fs->dirbuf + XDIR_FstClus); /* Start cluster */ - obj->objsize = ld_qword(fs->dirbuf + XDIR_FileSize); /* Size */ - obj->stat = fs->dirbuf[XDIR_GenFlags] & 2; /* Allocation status */ - obj->n_frag = 0; /* No last fragment info */ + FATFS *fs = dobj->fs; + + + if (sdir) { /* Initialize the containing directory. This block needs to precede the followings. */ + dobj->c_scl = sdir->obj.sclust; + dobj->c_size = ((DWORD)sdir->obj.objsize & 0xFFFFFF00) | sdir->obj.stat; + dobj->c_ofs = sdir->blk_ofs; + } + dobj->sclust = ld_32(fs->dirbuf + XDIR_FstClus); /* Start cluster */ + dobj->objsize = ld_64(fs->dirbuf + XDIR_FileSize); /* Size */ + dobj->stat = fs->dirbuf[XDIR_GenFlags] & 2; /* Allocation status */ + dobj->n_frag = 0; /* No last fragment info */ } -#if !FF_FS_READONLY || FF_FS_RPATH != 0 +#if !FF_FS_READONLY || FF_FS_RPATH /*------------------------------------------------*/ /* exFAT: Load the object's directory entry block */ /*------------------------------------------------*/ @@ -2231,22 +2257,24 @@ static FRESULT store_xdir ( { FRESULT res; UINT nent; - BYTE *dirb = dp->obj.fs->dirbuf; /* Pointer to the directory entry block 85+C0+C1s */ + BYTE *dirb = dp->obj.fs->dirbuf; /* Pointer to the entry set 85+C0+C1s */ + - /* Create set sum */ - st_word(dirb + XDIR_SetSum, xdir_sum(dirb)); - nent = dirb[XDIR_NumSec] + 1; + st_16(dirb + XDIR_SetSum, xdir_sum(dirb)); /* Create check sum */ - /* Store the directory entry block to the directory */ - res = dir_sdi(dp, dp->blk_ofs); + /* Store the entry set to the directory */ + nent = dirb[XDIR_NumSec] + 1; /* Number of entries */ + res = dir_sdi(dp, dp->blk_ofs); /* Top of the entry set */ while (res == FR_OK) { + /* Set an entry to the directory */ res = move_window(dp->obj.fs, dp->sect); if (res != FR_OK) break; memcpy(dp->dir, dirb, SZDIRE); dp->obj.fs->wflag = 1; - if (--nent == 0) break; + + if (--nent == 0) break; /* All done? */ dirb += SZDIRE; - res = dir_next(dp, 0); + res = dir_next(dp, 0); /* Next entry */ } return (res == FR_OK || res == FR_DISK_ERR) ? res : FR_INT_ERR; } @@ -2263,31 +2291,31 @@ static void create_xdir ( ) { UINT i; - BYTE nc1, nlen; - WCHAR wc; + BYTE n_c1, nlen; + WCHAR chr; - /* Create file-directory and stream-extension entry */ + /* Create file-directory and stream-extension entry (1st and 2nd entry) */ memset(dirb, 0, 2 * SZDIRE); dirb[0 * SZDIRE + XDIR_Type] = ET_FILEDIR; dirb[1 * SZDIRE + XDIR_Type] = ET_STREAM; - /* Create file-name entries */ - i = SZDIRE * 2; /* Top of file_name entries */ - nlen = nc1 = 0; wc = 1; + /* Create file name entries (3rd enrty and follows) */ + i = SZDIRE * 2; /* Top of file name entries */ + nlen = n_c1 = 0; chr = 1; do { dirb[i++] = ET_FILENAME; dirb[i++] = 0; do { /* Fill name field */ - if (wc != 0 && (wc = lfn[nlen]) != 0) nlen++; /* Get a character if exist */ - st_word(dirb + i, wc); /* Store it */ + if (chr != 0 && (chr = lfn[nlen]) != 0) nlen++; /* Get a character if exist */ + st_16(dirb + i, chr); /* Store it */ i += 2; } while (i % SZDIRE != 0); - nc1++; - } while (lfn[nlen]); /* Fill next entry if any char follows */ + n_c1++; + } while (lfn[nlen]); /* Fill next C1 entry if any char follows */ dirb[XDIR_NumName] = nlen; /* Set name length */ - dirb[XDIR_NumSec] = 1 + nc1; /* Set secondary count (C0 + C1s) */ - st_word(dirb + XDIR_NameHash, xname_sum(lfn)); /* Set name hash */ + dirb[XDIR_NumSec] = 1 + n_c1; /* Set secondary count (C0 + C1s) */ + st_16(dirb + XDIR_NameHash, xname_sum(lfn)); /* Set name hash */ } #endif /* !FF_FS_READONLY */ @@ -2310,7 +2338,7 @@ static FRESULT dir_read ( { FRESULT res = FR_NO_FILE; FATFS *fs = dp->obj.fs; - BYTE attr, b; + BYTE attr, et; #if FF_USE_LFN BYTE ord = 0xFF, sum = 0xFF; #endif @@ -2318,16 +2346,16 @@ static FRESULT dir_read ( while (dp->sect) { res = move_window(fs, dp->sect); if (res != FR_OK) break; - b = dp->dir[DIR_Name]; /* Test for the entry type */ - if (b == 0) { + et = dp->dir[DIR_Name]; /* Test for the entry type */ + if (et == 0) { res = FR_NO_FILE; break; /* Reached to end of the directory */ } #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ if (FF_USE_LABEL && vol) { - if (b == ET_VLABEL) break; /* Volume label entry? */ + if (et == ET_VLABEL) break; /* Volume label entry? */ } else { - if (b == ET_FILEDIR) { /* Start of the file entry block? */ + if (et == ET_FILEDIR) { /* Start of the file entry block? */ dp->blk_ofs = dp->dptr; /* Get location of the block */ res = load_xdir(dp); /* Load the entry block */ if (res == FR_OK) { @@ -2341,17 +2369,17 @@ static FRESULT dir_read ( { /* On the FAT/FAT32 volume */ dp->obj.attr = attr = dp->dir[DIR_Attr] & AM_MASK; /* Get attribute */ #if FF_USE_LFN /* LFN configuration */ - if (b == DDEM || b == '.' || (int)((attr & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */ + if (et == DDEM || et == '.' || (int)((attr & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */ ord = 0xFF; } else { if (attr == AM_LFN) { /* An LFN entry is found */ - if (b & LLEF) { /* Is it start of an LFN sequence? */ + if (et & LLEF) { /* Is it start of an LFN sequence? */ sum = dp->dir[LDIR_Chksum]; - b &= (BYTE)~LLEF; ord = b; + et &= (BYTE)~LLEF; ord = et; dp->blk_ofs = dp->dptr; } /* Check LFN validity and capture it */ - ord = (b == ord && sum == dp->dir[LDIR_Chksum] && pick_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF; + ord = (et == ord && sum == dp->dir[LDIR_Chksum] && pick_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF; } else { /* An SFN entry is found */ if (ord != 0 || sum != sum_sfn(dp->dir)) { /* Is there a valid LFN? */ dp->blk_ofs = 0xFFFFFFFF; /* It has no LFN. */ @@ -2360,7 +2388,7 @@ static FRESULT dir_read ( } } #else /* Non LFN configuration */ - if (b != DDEM && b != '.' && attr != AM_LFN && (int)((attr & ~AM_ARC) == AM_VOL) == vol) { /* Is it a valid entry? */ + if (et != DDEM && et != '.' && attr != AM_LFN && (int)((attr & ~AM_ARC) == AM_VOL) == vol) { /* Is it a valid entry? */ break; } #endif @@ -2387,9 +2415,9 @@ static FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ { FRESULT res; FATFS *fs = dp->obj.fs; - BYTE c; + BYTE et; #if FF_USE_LFN - BYTE a, ord, sum; + BYTE attr, ord, sum; #endif res = dir_sdi(dp, 0); /* Rewind directory object */ @@ -2404,10 +2432,10 @@ static FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ #if FF_MAX_LFN < 255 if (fs->dirbuf[XDIR_NumName] > FF_MAX_LFN) continue; /* Skip comparison if inaccessible object name */ #endif - if (ld_word(fs->dirbuf + XDIR_NameHash) != hash) continue; /* Skip comparison if hash mismatched */ + if (ld_16(fs->dirbuf + XDIR_NameHash) != hash) continue; /* Skip comparison if hash mismatched */ for (nc = fs->dirbuf[XDIR_NumName], di = SZDIRE * 2, ni = 0; nc; nc--, di += 2, ni++) { /* Compare the name */ if ((di % SZDIRE) == 0) di += 2; - if (ff_wtoupper(ld_word(fs->dirbuf + di)) != ff_wtoupper(fs->lfnbuf[ni])) break; + if (ff_wtoupper(ld_16(fs->dirbuf + di)) != ff_wtoupper(fs->lfnbuf[ni])) break; } if (nc == 0 && !fs->lfnbuf[ni]) break; /* Name matched? */ } @@ -2421,27 +2449,28 @@ static FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ do { res = move_window(fs, dp->sect); if (res != FR_OK) break; - c = dp->dir[DIR_Name]; - if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */ + et = dp->dir[DIR_Name]; /* Entry type */ + if (et == 0) { res = FR_NO_FILE; break; } /* Reached end of directory table */ #if FF_USE_LFN /* LFN configuration */ - dp->obj.attr = a = dp->dir[DIR_Attr] & AM_MASK; - if (c == DDEM || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */ + dp->obj.attr = attr = dp->dir[DIR_Attr] & AM_MASK; + if (et == DDEM || ((attr & AM_VOL) && attr != AM_LFN)) { /* An entry without valid data */ ord = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ } else { - if (a == AM_LFN) { /* An LFN entry is found */ + if (attr == AM_LFN) { /* Is it an LFN entry? */ if (!(dp->fn[NSFLAG] & NS_NOLFN)) { - if (c & LLEF) { /* Is it start of LFN sequence? */ - sum = dp->dir[LDIR_Chksum]; - c &= (BYTE)~LLEF; ord = c; /* LFN start order */ - dp->blk_ofs = dp->dptr; /* Start offset of LFN */ + if (et & LLEF) { /* Is it start of an entry set? */ + et &= (BYTE)~LLEF; + ord = et; /* Number of LFN entries */ + dp->blk_ofs = dp->dptr; /* Start offset of LFN */ + sum = dp->dir[LDIR_Chksum]; /* Sum of the SFN */ } /* Check validity of the LFN entry and compare it with given name */ - ord = (c == ord && sum == dp->dir[LDIR_Chksum] && cmp_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF; + ord = (et == ord && sum == dp->dir[LDIR_Chksum] && cmp_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF; } - } else { /* An SFN entry is found */ + } else { /* SFN entry */ if (ord == 0 && sum == sum_sfn(dp->dir)) break; /* LFN matched? */ if (!(dp->fn[NSFLAG] & NS_LOSS) && !memcmp(dp->dir, dp->fn, 11)) break; /* SFN matched? */ - ord = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ + ord = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Not matched, reset LFN sequence */ } } #else /* Non LFN configuration */ @@ -2470,7 +2499,7 @@ static FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too FATFS *fs = dp->obj.fs; #if FF_USE_LFN /* LFN configuration */ UINT n, len, n_ent; - BYTE sn[12], sum; + BYTE sn[12]; if (dp->fn[NSFLAG] & (NS_DOT | NS_NONAME)) return FR_INVALID_NAME; /* Check name validity */ @@ -2495,11 +2524,17 @@ 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); - st_qword(fs->dirbuf + XDIR_ValidFileSize, dp->obj.objsize); - fs->dirbuf[XDIR_GenFlags] = dp->obj.stat | 1; /* Update the allocation status */ + st_64(fs->dirbuf + XDIR_FileSize, dp->obj.objsize); + st_64(fs->dirbuf + XDIR_ValidFileSize, dp->obj.objsize); + 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; +#if FF_FS_RPATH /* Refrect changes to the current dir chain if the stretched dir is in it */ + for (n = 1; n <= fs->xcwds.depth && dp->obj.sclust != fs->xcwds.tbl[n].d_scl; n++) ; /* Check if the dir is in the current dir path */ + if (n <= fs->xcwds.depth) { /* If exist, update it */ + fs->xcwds.tbl[n].d_size = (DWORD)dp->obj.objsize | dp->obj.stat; + } +#endif } } @@ -2512,7 +2547,7 @@ static FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too if (sn[NSFLAG] & NS_LOSS) { /* When LFN is out of 8.3 format, generate a numbered name */ dp->fn[NSFLAG] = NS_NOLFN; /* Find only SFN */ for (n = 1; n < 100; n++) { - gen_numname(dp->fn, sn, fs->lfnbuf, n); /* Generate a numbered name */ + gen_numname(dp->fn, sn, fs->lfnbuf, (WORD)n); /* Generate a numbered name */ res = dir_find(dp); /* Check if the name collides with existing SFN */ if (res != FR_OK) break; } @@ -2527,7 +2562,8 @@ static FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too if (res == FR_OK && --n_ent) { /* Set LFN entry if needed */ res = dir_sdi(dp, dp->dptr - n_ent * SZDIRE); if (res == FR_OK) { - sum = sum_sfn(dp->fn); /* Checksum value of the SFN tied to the LFN */ + BYTE sum = sum_sfn(dp->fn); /* Checksum value of the SFN tied to the LFN */ + do { /* Store LFN entries in bottom first */ res = move_window(fs, dp->sect); if (res != FR_OK) break; @@ -2550,7 +2586,7 @@ static FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too memset(dp->dir, 0, SZDIRE); /* Clean the entry */ memcpy(dp->dir + DIR_Name, dp->fn, 11); /* Put SFN */ #if FF_USE_LFN - dp->dir[DIR_NTres] = dp->fn[NSFLAG] & (NS_BODY | NS_EXT); /* Put NT flag */ + dp->dir[DIR_NTres] = dp->fn[NSFLAG] & (NS_BODY | NS_EXT); /* Put low-case flags */ #endif fs->wflag = 1; } @@ -2621,7 +2657,6 @@ static void get_fileinfo ( { UINT si, di; #if FF_USE_LFN - BYTE lcf; WCHAR wc, hs; FATFS *fs = dp->obj.fs; UINT nw; @@ -2630,7 +2665,7 @@ static void get_fileinfo ( #endif - fno->fname[0] = 0; /* Invaidate file info */ + fno->fname[0] = 0; if (dp->sect == 0) return; /* Exit if read pointer has reached end of directory */ #if FF_USE_LFN /* LFN configuration */ @@ -2645,7 +2680,7 @@ static void get_fileinfo ( di = 0; break; } if ((si % SZDIRE) == 0) si += 2; /* Skip entry type field */ - wc = ld_word(fs->dirbuf + si); si += 2; nc++; /* Get a character */ + wc = ld_16(fs->dirbuf + si); si += 2; nc++; /* Get a character */ if (hs == 0 && IsSurrogate(wc)) { /* Is it a surrogate? */ hs = wc; continue; /* Get low surrogate */ } @@ -2661,10 +2696,14 @@ static void get_fileinfo ( fno->fname[di] = 0; /* Terminate the name */ fno->altname[0] = 0; /* exFAT does not support SFN */ - fno->fattrib = fs->dirbuf[XDIR_Attr] & AM_MASKX; /* Attribute */ - fno->fsize = (fno->fattrib & AM_DIR) ? 0 : ld_qword(fs->dirbuf + XDIR_FileSize); /* Size */ - fno->ftime = ld_word(fs->dirbuf + XDIR_ModTime + 0); /* Time */ - fno->fdate = ld_word(fs->dirbuf + XDIR_ModTime + 2); /* Date */ + fno->fattrib = fs->dirbuf[XDIR_Attr] & AM_MASKX; /* Attribute */ + fno->fsize = (fno->fattrib & AM_DIR) ? 0 : ld_64(fs->dirbuf + XDIR_FileSize); /* Size */ + fno->ftime = ld_16(fs->dirbuf + XDIR_ModTime + 0); /* Last modified time */ + fno->fdate = ld_16(fs->dirbuf + XDIR_ModTime + 2); /* Last modified date */ +#if FF_FS_CRTIME + fno->crtime = ld_16(fs->dirbuf + XDIR_CrtTime + 0); /* Created time */ + fno->crdate = ld_16(fs->dirbuf + XDIR_CrtTime + 2); /* Created date */ +#endif return; } else #endif @@ -2714,14 +2753,16 @@ static void get_fileinfo ( } fno->altname[di] = 0; /* Terminate the SFN (null string means SFN is invalid) */ - if (fno->fname[0] == 0) { /* If LFN is invalid, altname[] needs to be copied to fname[] */ - if (di == 0) { /* If LFN and SFN both are invalid, this object is inaccessible */ - fno->fname[di++] = '\?'; + if (!fno->fname[0]) { /* If LFN is invalid, altname[] needs to be copied to fname[] */ + if (di == 0) { /* If LFN and SFN both are invalid, */ + fno->fname[di++] = '\?'; /* This object is inaccessible due to wrong buffer or locale settings */ } else { - for (si = di = 0, lcf = NS_BODY; fno->altname[si]; si++, di++) { /* Copy altname[] to fname[] with case information */ + BYTE lcflg = NS_BODY; + + for (si = di = 0; fno->altname[si]; si++, di++) { /* Copy altname[] to fname[] with case information */ wc = (WCHAR)fno->altname[si]; - if (wc == '.') lcf = NS_EXT; - if (IsUpper(wc) && (dp->dir[DIR_NTres] & lcf)) wc += 0x20; + if (wc == '.') lcflg = NS_EXT; + if (IsUpper(wc) && (dp->dir[DIR_NTres] & lcflg)) wc += 0x20; fno->fname[di] = (TCHAR)wc; } } @@ -2741,10 +2782,14 @@ static void get_fileinfo ( fno->fname[di] = 0; /* Terminate the SFN */ #endif - fno->fattrib = dp->dir[DIR_Attr] & AM_MASK; /* Attribute */ - fno->fsize = ld_dword(dp->dir + DIR_FileSize); /* Size */ - fno->ftime = ld_word(dp->dir + DIR_ModTime + 0); /* Time */ - fno->fdate = ld_word(dp->dir + DIR_ModTime + 2); /* Date */ + fno->fattrib = dp->dir[DIR_Attr] & AM_MASK; /* Attribute */ + fno->fsize = ld_32(dp->dir + DIR_FileSize); /* Size */ + fno->ftime = ld_16(dp->dir + DIR_ModTime + 0); /* Last modified time */ + fno->fdate = ld_16(dp->dir + DIR_ModTime + 2); /* Last Modified date */ +#if FF_FS_CRTIME + fno->crtime = ld_16(dp->dir + DIR_CrtTime + 0); /* Created time */ + fno->crdate = ld_16(dp->dir + DIR_CrtTime + 2); /* Created date */ +#endif } #endif /* FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 */ @@ -2775,9 +2820,9 @@ static DWORD get_achar ( /* Get a character and advance ptr */ chr = (BYTE)*(*ptr)++; /* Get a byte */ if (IsLower(chr)) chr -= 0x20; /* To upper ASCII char */ #if FF_CODE_PAGE == 0 - if (ExCvt && chr >= 0x80) chr = ExCvt[chr - 0x80]; /* To upper SBCS extended char */ + if (ExCvt && chr >= 0x80) chr = ExCvt[chr - 0x80]; /* To upper (SBCS extended char) */ #elif FF_CODE_PAGE < 900 - if (chr >= 0x80) chr = ExCvt[chr - 0x80]; /* To upper SBCS extended char */ + if (chr >= 0x80) chr = ExCvt[chr - 0x80]; /* To upper (SBCS extended char) */ #endif #if FF_CODE_PAGE == 0 || FF_CODE_PAGE >= 900 if (dbc_1st((BYTE)chr)) { /* Get DBC 2nd byte if needed */ @@ -2858,7 +2903,7 @@ static FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not cr UINT i, ni, si, di; - /* Create LFN into LFN working buffer */ + /* Create an LFN into LFN working buffer */ p = *path; lfn = dp->obj.fs->lfnbuf; di = 0; for (;;) { uc = tchar2uni(&p); /* Get a character */ @@ -2879,7 +2924,7 @@ static FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not cr } *path = p; /* Return pointer to the next segment */ -#if FF_FS_RPATH != 0 +#if FF_FS_RPATH if ((di == 1 && lfn[di - 1] == '.') || (di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) { /* Is this segment a dot name? */ lfn[di] = 0; @@ -2986,14 +3031,19 @@ static FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not cr p = *path; sfn = dp->fn; memset(sfn, ' ', 11); si = i = 0; ni = 8; -#if FF_FS_RPATH != 0 +#if FF_FS_RPATH if (p[si] == '.') { /* Is this a dot entry? */ - for (;;) { + for (;;) { /* Copy one or two dots */ c = (BYTE)p[si++]; if (c != '.' || si >= 3) break; sfn[i++] = c; } - if (!IsSeparator(c) && c > ' ') return FR_INVALID_NAME; + if (IsSeparator(c)) { + while (IsSeparator(p[si])) si++; /* Skip duplicated separators */ + if ((BYTE)p[si] <= ' ') c = 0; /* Terminate if no segment follows */ + } else if (c > ' ') { /* Not in dot name */ + return FR_INVALID_NAME; + } *path = p + si; /* Return pointer to the next segment */ sfn[NSFLAG] = (c <= ' ') ? NS_LAST | NS_DOT : NS_DOT; /* Set last segment flag if end of the path */ return FR_OK; @@ -3003,7 +3053,7 @@ static FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not cr c = (BYTE)p[si++]; /* Get a byte */ if (c <= ' ') break; /* Break if end of the path name */ if (IsSeparator(c)) { /* Break if a separator is found */ - while (IsSeparator(p[si])) si++; /* Skip duplicated separator if exist */ + while (IsSeparator(p[si])) si++; /* Skip duplicated separators */ break; } if (c == '.' || i >= ni) { /* End of body or field overflow? */ @@ -3058,28 +3108,33 @@ static FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ FATFS *fs = dp->obj.fs; -#if FF_FS_RPATH != 0 + /* Determins the start directory (current directory or forced root directory) */ +#if FF_FS_RPATH if (!IsSeparator(*path) && (FF_STR_VOLUME_ID != 2 || !IsTerminator(*path))) { /* Without heading separator */ dp->obj.sclust = fs->cdir; /* Start at the current directory */ } else #endif { /* With heading separator */ - while (IsSeparator(*path)) path++; /* Strip separators */ - dp->obj.sclust = 0; /* Start from the root directory */ + while (IsSeparator(*path)) path++; /* Strip heading separators */ + dp->obj.sclust = 0; /* Start at the root directory */ } + #if FF_FS_EXFAT dp->obj.n_frag = 0; /* Invalidate last fragment counter of the object */ -#if FF_FS_RPATH != 0 - if (fs->fs_type == FS_EXFAT && dp->obj.sclust) { /* exFAT: Retrieve the sub-directory's status */ - DIR dj; - - dp->obj.c_scl = fs->cdc_scl; - dp->obj.c_size = fs->cdc_size; - dp->obj.c_ofs = fs->cdc_ofs; - res = load_obj_xdir(&dj, &dp->obj); - if (res != FR_OK) return res; - dp->obj.objsize = ld_dword(fs->dirbuf + XDIR_FileSize); - dp->obj.stat = fs->dirbuf[XDIR_GenFlags] & 2; +#if FF_FS_RPATH + if (fs->fs_type == FS_EXFAT) { /* exFAT: Retrieve the start-directory's status */ + if (dp->obj.sclust) { /* Start directory is a sub-directory */ + /* Load the current directory chain into working buffer and initialize directory object as current dir */ + memcpy(&fs->xcwds2, &fs->xcwds, sizeof fs->xcwds2); + dp->obj.stat = (BYTE)fs->xcwds2.tbl[fs->xcwds2.depth].d_size; + dp->obj.objsize = fs->xcwds2.tbl[fs->xcwds2.depth].d_size & 0xFFFFFF00; + dp->obj.c_scl = fs->xcwds2.tbl[fs->xcwds2.depth - 1].d_scl; + dp->obj.c_size = fs->xcwds2.tbl[fs->xcwds2.depth - 1].d_size & 0xFFFFFF00; + dp->obj.c_ofs = fs->xcwds2.tbl[fs->xcwds2.depth - 1].nxt_ofs; + } else { /* Start directory is the root directory */ + /* Clear the directory path working buffer as root directory */ + memset(&fs->xcwds2, 0, sizeof fs->xcwds2); + } } #endif #endif @@ -3092,11 +3147,31 @@ static FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ for (;;) { res = create_name(dp, &path); /* Get a segment name of the path */ if (res != FR_OK) break; - res = dir_find(dp); /* Find an object with the segment name */ ns = dp->fn[NSFLAG]; +#if FF_FS_EXFAT && FF_FS_RPATH + if (fs->fs_type == FS_EXFAT && (ns & NS_DOT)) { /* Is it a dot name? */ + /* There is no dot entry in exFAT volume, so it needs to follow the parent directory with recorded path */ + if (fs->lfnbuf[1] == '.' && fs->xcwds2.depth) { /* ".." in the sub-dir? */ + fs->xcwds2.depth--; /* Get into the parent directory and load the directory info */ + dp->obj.sclust = fs->xcwds2.tbl[fs->xcwds2.depth].d_scl; + dp->obj.stat = (BYTE)fs->xcwds2.tbl[fs->xcwds2.depth].d_size; + dp->obj.objsize = fs->xcwds2.tbl[fs->xcwds2.depth].d_size & 0xFFFFFF00; + if (fs->xcwds2.depth) { /* Load containing dir info if needed */ + dp->obj.c_scl = fs->xcwds2.tbl[fs->xcwds2.depth - 1].d_scl; + dp->obj.c_size = fs->xcwds2.tbl[fs->xcwds2.depth - 1].d_size; + dp->obj.c_ofs = fs->xcwds2.tbl[fs->xcwds2.depth - 1].nxt_ofs; + } + } + dp->obj.attr |= AM_DIR; /* This is a directory */ + dp->fn[NSFLAG] |= NS_NONAME; /* but dot names in exFAT volume are not directory entry */ + if (ns & NS_LAST) break; /* Last segment? */ + continue; /* Follow next segment */ + } +#endif + res = dir_find(dp); /* Find an object with the segment name */ if (res != FR_OK) { /* Failed to find the object */ if (res == FR_NO_FILE) { /* Object is not found */ - if (FF_FS_RPATH && (ns & NS_DOT)) { /* If dot entry is not exist, stay there */ + if (FF_FS_RPATH && (ns & NS_DOT)) { /* If dot entry is not exist, stay there (may be root dir in FAT volume) */ if (!(ns & NS_LAST)) continue; /* Continue to follow if not last segment */ dp->fn[NSFLAG] = NS_NONAME; res = FR_OK; @@ -3106,17 +3181,24 @@ static FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ } break; } - if (ns & NS_LAST) break; /* Last segment matched. Function completed. */ +#if FF_FS_EXFAT && FF_FS_RPATH + if (fs->fs_type == FS_EXFAT && (dp->obj.attr & AM_DIR)) { /* Record the path if it is a sub-directory */ + fs->xcwds2.tbl[fs->xcwds2.depth].nxt_ofs = dp->blk_ofs; + if (++fs->xcwds2.depth >= sizeof fs->xcwds2.tbl / sizeof fs->xcwds2.tbl[0]) { /* Is it too deep path? */ + res = FR_NOT_ENOUGH_CORE; break; + } + fs->xcwds2.tbl[fs->xcwds2.depth].d_scl = ld_32(fs->dirbuf + XDIR_FstClus); + fs->xcwds2.tbl[fs->xcwds2.depth].d_size = ld_32(fs->dirbuf + XDIR_FileSize) | (fs->dirbuf[XDIR_GenFlags] & 2); + } +#endif + if (ns & NS_LAST) break; /* If last segment matched, the function completed */ /* Get into the sub-directory */ - if (!(dp->obj.attr & AM_DIR)) { /* It is not a sub-directory and cannot follow */ - res = FR_NO_PATH; break; + if (!(dp->obj.attr & AM_DIR)) { + res = FR_NO_PATH; break; /* It is not a sub-directory and cannot follow the path */ } #if FF_FS_EXFAT - if (fs->fs_type == FS_EXFAT) { /* Save containing directory information for next dir */ - dp->obj.c_scl = dp->obj.sclust; - dp->obj.c_size = ((DWORD)dp->obj.objsize & 0xFFFFFF00) | dp->obj.stat; - dp->obj.c_ofs = dp->blk_ofs; - init_alloc_info(fs, &dp->obj); /* Open next directory */ + if (fs->fs_type == FS_EXFAT) { + init_alloc_info(&dp->obj, dp); /* Open next directory */ } else #endif { @@ -3141,70 +3223,64 @@ static int get_ldnumber ( /* Returns logical drive number (-1:invalid drive numb { const TCHAR *tp; const TCHAR *tt; - TCHAR tc; + TCHAR chr; int i; - int vol = -1; #if FF_STR_VOLUME_ID /* Find string volume ID */ - const char *sp; - char c; + const char *vsp; + char vchr; #endif tt = tp = *path; - if (!tp) return vol; /* Invalid path name? */ + if (!tp) return -1; /* Invalid path name? */ do { /* Find a colon in the path */ - tc = *tt++; - } while (!IsTerminator(tc) && tc != ':'); + chr = *tt++; + } while (!IsTerminator(chr) && chr != ':'); - if (tc == ':') { /* DOS/Windows style volume ID? */ + if (chr == ':') { /* Is there a DOS/Windows style volume ID? */ i = FF_VOLUMES; - if (IsDigit(*tp) && tp + 2 == tt) { /* Is there a numeric volume ID + colon? */ - i = (int)*tp - '0'; /* Get the LD number */ + if (IsDigit(*tp) && tp + 2 == tt) { /* Is it a numeric volume ID + colon? */ + i = (int)*tp - '0'; /* Get the logical drive number */ } -#if FF_STR_VOLUME_ID == 1 /* Arbitrary string is enabled */ +#if FF_STR_VOLUME_ID == 1 /* Arbitrary string volume ID is enabled */ else { - i = 0; + i = 0; /* Find volume ID string in the preconfigured table */ do { - sp = VolumeStr[i]; tp = *path; /* This string volume ID and path name */ - do { /* Compare the volume ID with path name */ - c = *sp++; tc = *tp++; - if (IsLower(c)) c -= 0x20; - if (IsLower(tc)) tc -= 0x20; - } while (c && (TCHAR)c == tc); - } while ((c || tp != tt) && ++i < FF_VOLUMES); /* Repeat for each id until pattern match */ + vsp = VolumeStr[i]; tp = *path; /* Preconfigured string and path name to test */ + do { /* Compare the volume ID with path name in case-insensitive */ + vchr = *vsp++; chr = *tp++; + if (IsLower(vchr)) vchr -= 0x20; + if (IsLower(chr)) chr -= 0x20; + } while (vchr && (TCHAR)vchr == chr); + } while ((vchr || tp != tt) && ++i < FF_VOLUMES); /* Repeat for each id until pattern match */ } #endif - if (i < FF_VOLUMES) { /* If a volume ID is found, get the drive number and strip it */ - vol = i; /* Drive number */ - *path = tt; /* Snip the drive prefix off */ - } - return vol; + if (i >= FF_VOLUMES) return -1; /* Not found or invalid volume ID */ + *path = tt; /* Snip the drive prefix off */ + return i; /* Return the found drive number */ } #if FF_STR_VOLUME_ID == 2 /* Unix style volume ID is enabled */ if (*tp == '/') { /* Is there a volume ID? */ while (*(tp + 1) == '/') tp++; /* Skip duplicated separator */ i = 0; do { - tt = tp; sp = VolumeStr[i]; /* Path name and this string volume ID */ - do { /* Compare the volume ID with path name */ - c = *sp++; tc = *(++tt); - if (IsLower(c)) c -= 0x20; - if (IsLower(tc)) tc -= 0x20; - } while (c && (TCHAR)c == tc); - } while ((c || (tc != '/' && !IsTerminator(tc))) && ++i < FF_VOLUMES); /* Repeat for each ID until pattern match */ - if (i < FF_VOLUMES) { /* If a volume ID is found, get the drive number and strip it */ - vol = i; /* Drive number */ - *path = tt; /* Snip the drive prefix off */ - } - return vol; - } -#endif - /* No drive prefix is found */ -#if FF_FS_RPATH != 0 - vol = CurrVol; /* Default drive is current drive */ + vsp = VolumeStr[i]; tt = tp; /* Preconfigured string and path name to test */ + do { /* Compare the volume ID with path name in case-insensitive */ + vchr = *vsp++; chr = *(++tt); + if (IsLower(vchr)) vchr -= 0x20; + if (IsLower(chr)) chr -= 0x20; + } while (vchr && (TCHAR)vchr == chr); + } while ((vchr || (chr != '/' && !IsTerminator(chr))) && ++i < FF_VOLUMES); /* Repeat for each ID until pattern match */ + if (i >= FF_VOLUMES) return -1; /* Not found (invalid volume ID) */ + *path = tt; /* Snip the node name off */ + return i; /* Return the found drive number */ + } +#endif + /* No drive prefix */ +#if FF_FS_RPATH + return (int)CurrVol; /* Default drive is current drive */ #else - vol = 0; /* Default drive is 0 */ + return 0; /* Default drive is 0 */ #endif - return vol; /* Return the default drive */ } @@ -3245,25 +3321,25 @@ static int test_gpt_header ( /* 0:Invalid, 1:Valid */ if (memcmp(gpth + GPTH_Sign, "EFI PART" "\0\0\1", 12)) return 0; /* Check signature and version (1.0) */ - hlen = ld_dword(gpth + GPTH_Size); /* Check header size */ + hlen = ld_32(gpth + GPTH_Size); /* Check header size */ if (hlen < 92 || hlen > FF_MIN_SS) return 0; for (i = 0, bcc = 0xFFFFFFFF; i < hlen; 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) */ + if (~bcc != ld_32(gpth + GPTH_Bcc)) return 0; + if (ld_32(gpth + GPTH_PteSize) != SZ_GPTE) return 0; /* Table entry size (must be SZ_GPTE bytes) */ + if (ld_32(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 */ +/* Generate a random value */ +static DWORD make_rand ( /* Returns a seed value for next */ + DWORD seed, /* Seed value */ + BYTE *buff, /* Output buffer */ + UINT n /* Data length */ ) { UINT r; @@ -3299,7 +3375,7 @@ static UINT check_fs ( /* 0:FAT/FAT32 VBR, 1:exFAT VBR, 2:Not FAT and valid BS, fs->wflag = 0; fs->winsect = (LBA_t)0 - 1; /* Invaidate window */ if (move_window(fs, sect) != FR_OK) return 4; /* Load the boot sector */ - sign = ld_word(fs->win + BS_55AA); + sign = ld_16(fs->win + BS_55AA); #if FF_FS_EXFAT if (sign == 0xAA55 && !memcmp(fs->win + BS_JmpBoot, "\xEB\x76\x90" "EXFAT ", 11)) return 1; /* It is an exFAT VBR */ #endif @@ -3308,20 +3384,20 @@ static UINT check_fs ( /* 0:FAT/FAT32 VBR, 1:exFAT VBR, 2:Not FAT and valid BS, if (sign == 0xAA55 && !memcmp(fs->win + BS_FilSysType32, "FAT32 ", 8)) { return 0; /* It is an FAT32 VBR */ } - /* FAT volumes formatted with early MS-DOS lack BS_55AA and BS_FilSysType, so FAT VBR needs to be identified without them. */ - w = ld_word(fs->win + BPB_BytsPerSec); + /* FAT volumes created in the early MS-DOS era lack BS_55AA and BS_FilSysType, so FAT VBR needs to be identified without them. */ + w = ld_16(fs->win + BPB_BytsPerSec); b = fs->win[BPB_SecPerClus]; if ((w & (w - 1)) == 0 && w >= FF_MIN_SS && w <= FF_MAX_SS /* Properness of sector size (512-4096 and 2^n) */ && b != 0 && (b & (b - 1)) == 0 /* Properness of cluster size (2^n) */ - && ld_word(fs->win + BPB_RsvdSecCnt) != 0 /* Properness of reserved sectors (MNBZ) */ - && (UINT)fs->win[BPB_NumFATs] - 1 <= 1 /* Properness of FATs (1 or 2) */ - && ld_word(fs->win + BPB_RootEntCnt) != 0 /* Properness of root dir entries (MNBZ) */ - && (ld_word(fs->win + BPB_TotSec16) >= 128 || ld_dword(fs->win + BPB_TotSec32) >= 0x10000) /* Properness of volume sectors (>=128) */ - && ld_word(fs->win + BPB_FATSz16) != 0) { /* Properness of FAT size (MNBZ) */ + && ld_16(fs->win + BPB_RsvdSecCnt) != 0 /* Properness of number of reserved sectors (MNBZ) */ + && (UINT)fs->win[BPB_NumFATs] - 1 <= 1 /* Properness of number of FATs (1 or 2) */ + && ld_16(fs->win + BPB_RootEntCnt) != 0 /* Properness of root dir size (MNBZ) */ + && (ld_16(fs->win + BPB_TotSec16) >= 128 || ld_32(fs->win + BPB_TotSec32) >= 0x10000) /* Properness of volume size (>=128) */ + && ld_16(fs->win + BPB_FATSz16) != 0) { /* Properness of FAT size (MNBZ) */ return 0; /* It can be presumed an FAT VBR */ } } - return sign == 0xAA55 ? 2 : 3; /* Not an FAT VBR (valid or invalid BS) */ + return sign == 0xAA55 ? 2 : 3; /* Not an FAT VBR (with valid or invalid BS) */ } @@ -3340,7 +3416,7 @@ static UINT find_volume ( /* Returns BS status found in the hosting drive */ fmt = check_fs(fs, 0); /* Load sector 0 and check if it is an FAT VBR as SFD format */ if (fmt != 2 && (fmt >= 3 || part == 0)) return fmt; /* Returns if it is an 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 */ + /* Sector 0 is not an FAT VBR or forced partition number wants a partitioned drive */ #if FF_LBA64 if (fs->win[MBR_Table + PTE_System] == 0xEE) { /* GPT protective MBR? */ @@ -3349,14 +3425,14 @@ static UINT find_volume ( /* Returns BS status found in the hosting drive */ 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 */ + n_ent = ld_32(fs->win + GPTH_PtNum); /* Number of entries */ + pt_lba = ld_64(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 (!memcmp(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 */ + v_ent++; /* Order of MS BDP */ + fmt = check_fs(fs, ld_64(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) */ } @@ -3364,9 +3440,9 @@ static UINT find_volume ( /* Returns BS status found in the hosting drive */ return 3; /* Not found */ } #endif - if (FF_MULTI_PARTITION && part > 4) return 3; /* MBR has 4 partitions max */ + if (FF_MULTI_PARTITION && part > 4) return 3; /* MBR has four primary partitions max (FatFs does not support logical partition) */ 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); + mbr_pt[i] = ld_32(fs->win + MBR_Table + i * SZ_PTE + PTE_StLba); } i = part ? part - 1 : 0; /* Table index to find first */ do { /* Find an FAT volume */ @@ -3392,8 +3468,6 @@ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ FATFS *fs; DSTATUS stat; LBA_t bsect; - DWORD tsect, sysect, fasize, nclst, szbfat; - WORD nrsv; UINT fmt; @@ -3448,21 +3522,21 @@ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ #if FF_FS_EXFAT if (fmt == 1) { QWORD maxlba; - DWORD so, cv, bcl, i; + DWORD so, cv, bcl, ncl, 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; - if (ld_word(fs->win + BPB_FSVerEx) != 0x100) return FR_NO_FILESYSTEM; /* Check exFAT version (must be version 1.0) */ + if (ld_16(fs->win + BPB_FSVerEx) != 0x100) return FR_NO_FILESYSTEM; /* Check exFAT version (must be version 1.0) */ if (1 << fs->win[BPB_BytsPerSecEx] != SS(fs)) { /* (BPB_BytsPerSecEx must be equal to the physical sector size) */ return FR_NO_FILESYSTEM; } - maxlba = ld_qword(fs->win + BPB_TotSecEx) + bsect; /* Last LBA of the volume + 1 */ + maxlba = ld_64(fs->win + BPB_TotSecEx) + bsect; /* Last LBA of the volume + 1 */ if (!FF_LBA64 && maxlba >= 0x100000000) return FR_NO_FILESYSTEM; /* (It cannot be accessed in 32-bit LBA) */ - fs->fsize = ld_dword(fs->win + BPB_FatSzEx); /* Number of sectors per FAT */ + fs->fsize = ld_32(fs->win + BPB_FatSzEx); /* Number of sectors per FAT */ fs->n_fats = fs->win[BPB_NumFATsEx]; /* Number of FATs */ if (fs->n_fats != 1) return FR_NO_FILESYSTEM; /* (Supports only 1 FAT) */ @@ -3470,16 +3544,16 @@ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ fs->csize = 1 << fs->win[BPB_SecPerClusEx]; /* Cluster size */ if (fs->csize == 0) return FR_NO_FILESYSTEM; /* (Must be 1..32768 sectors) */ - nclst = ld_dword(fs->win + BPB_NumClusEx); /* Number of clusters */ - if (nclst > MAX_EXFAT) return FR_NO_FILESYSTEM; /* (Too many clusters) */ - fs->n_fatent = nclst + 2; + ncl = ld_32(fs->win + BPB_NumClusEx); /* Number of clusters */ + if (ncl > MAX_EXFAT) return FR_NO_FILESYSTEM; /* (Too many clusters) */ + fs->n_fatent = ncl + 2; /* Boundaries and Limits */ fs->volbase = bsect; - fs->database = bsect + ld_dword(fs->win + BPB_DataOfsEx); - fs->fatbase = bsect + ld_dword(fs->win + BPB_FatOfsEx); - if (maxlba < (QWORD)fs->database + nclst * fs->csize) return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size required) */ - fs->dirbase = ld_dword(fs->win + BPB_RootClusEx); + fs->database = bsect + ld_32(fs->win + BPB_DataOfsEx); + fs->fatbase = bsect + ld_32(fs->win + BPB_FatOfsEx); + if (maxlba < (QWORD)fs->database + ncl * fs->csize) return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size required) */ + fs->dirbase = ld_32(fs->win + BPB_RootClusEx); /* Get bitmap location and check if it is contiguous (implementation assumption) */ so = i = 0; @@ -3489,30 +3563,33 @@ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ 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? */ + if (fs->win[i] == ET_BITMAP) break; /* Is it a bitmap entry? */ i = (i + SZDIRE) % SS(fs); /* Next entry */ } - bcl = ld_dword(fs->win + i + 20); /* Bitmap cluster */ + bcl = ld_32(fs->win + i + 20); /* Bitmap cluster */ if (bcl < 2 || bcl >= fs->n_fatent) return FR_NO_FILESYSTEM; /* (Wrong cluster#) */ fs->bitbase = fs->database + fs->csize * (bcl - 2); /* Bitmap sector */ for (;;) { /* Check if bitmap is contiguous */ if (move_window(fs, fs->fatbase + bcl / (SS(fs) / 4)) != FR_OK) return FR_DISK_ERR; - cv = ld_dword(fs->win + bcl % (SS(fs) / 4) * 4); + cv = ld_32(fs->win + bcl % (SS(fs) / 4) * 4); if (cv == 0xFFFFFFFF) break; /* Last link? */ if (cv != ++bcl) return FR_NO_FILESYSTEM; /* Fragmented bitmap? */ } - #if !FF_FS_READONLY - fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */ + fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Invalidate cluster allocation information */ + fs->fsi_flag = 0; /* Enable to sync PercInUse value in VBR */ #endif fmt = FS_EXFAT; /* FAT sub-type */ } else #endif /* FF_FS_EXFAT */ { - if (ld_word(fs->win + BPB_BytsPerSec) != SS(fs)) return FR_NO_FILESYSTEM; /* (BPB_BytsPerSec must be equal to the physical sector size) */ + DWORD tsect, sysect, fasize, nclst, szbfat; + WORD nrsv; + + if (ld_16(fs->win + BPB_BytsPerSec) != SS(fs)) return FR_NO_FILESYSTEM; /* (BPB_BytsPerSec must be equal to the physical sector size) */ - fasize = ld_word(fs->win + BPB_FATSz16); /* Number of sectors per FAT */ - if (fasize == 0) fasize = ld_dword(fs->win + BPB_FATSz32); + fasize = ld_16(fs->win + BPB_FATSz16); /* Number of sectors per FAT */ + if (fasize == 0) fasize = ld_32(fs->win + BPB_FATSz32); fs->fsize = fasize; fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FATs */ @@ -3522,13 +3599,13 @@ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ fs->csize = fs->win[BPB_SecPerClus]; /* Cluster size */ if (fs->csize == 0 || (fs->csize & (fs->csize - 1))) return FR_NO_FILESYSTEM; /* (Must be power of 2) */ - fs->n_rootdir = ld_word(fs->win + BPB_RootEntCnt); /* Number of root directory entries */ + fs->n_rootdir = ld_16(fs->win + BPB_RootEntCnt); /* Number of root directory entries */ if (fs->n_rootdir % (SS(fs) / SZDIRE)) return FR_NO_FILESYSTEM; /* (Must be sector aligned) */ - tsect = ld_word(fs->win + BPB_TotSec16); /* Number of sectors on the volume */ - if (tsect == 0) tsect = ld_dword(fs->win + BPB_TotSec32); + tsect = ld_16(fs->win + BPB_TotSec16); /* Number of sectors on the volume */ + if (tsect == 0) tsect = ld_32(fs->win + BPB_TotSec32); - nrsv = ld_word(fs->win + BPB_RsvdSecCnt); /* Number of reserved sectors */ + nrsv = ld_16(fs->win + BPB_RsvdSecCnt); /* Number of reserved sectors */ if (nrsv == 0) return FR_NO_FILESYSTEM; /* (Must not be 0) */ /* Determine the FAT sub type */ @@ -3548,9 +3625,9 @@ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ fs->fatbase = bsect + nrsv; /* FAT start sector */ fs->database = bsect + sysect; /* Data start sector */ if (fmt == FS_FAT32) { - if (ld_word(fs->win + BPB_FSVer32) != 0) return FR_NO_FILESYSTEM; /* (Must be FAT32 revision 0.0) */ + if (ld_16(fs->win + BPB_FSVer32) != 0) return FR_NO_FILESYSTEM; /* (Must be FAT32 revision 0.0) */ if (fs->n_rootdir != 0) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */ - fs->dirbase = ld_dword(fs->win + BPB_RootClus32); /* Root directory start cluster */ + fs->dirbase = ld_32(fs->win + BPB_RootClus32); /* Root directory start cluster */ szbfat = fs->n_fatent * 4; /* (Needed FAT size) */ } else { if (fs->n_rootdir == 0) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must not be 0) */ @@ -3562,44 +3639,49 @@ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ #if !FF_FS_READONLY /* Get FSInfo if available */ - fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */ - fs->fsi_flag = 0x80; -#if (FF_FS_NOFSINFO & 3) != 3 - if (fmt == FS_FAT32 /* Allow to update FSInfo only if BPB_FSInfo32 == 1 */ - && ld_word(fs->win + BPB_FSInfo32) == 1 + fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Invalidate cluster allocation information */ + fs->fsi_flag = 0x80; /* Disable FSInfo by default */ + if (fmt == FS_FAT32 + && ld_16(fs->win + BPB_FSInfo32) == 1 /* FAT32: Enable FSInfo feature only if FSInfo sector is next to VBR */ && move_window(fs, bsect + 1) == FR_OK) { fs->fsi_flag = 0; - if (ld_word(fs->win + BS_55AA) == 0xAA55 /* Load FSInfo data if available */ - && ld_dword(fs->win + FSI_LeadSig) == 0x41615252 - && ld_dword(fs->win + FSI_StrucSig) == 0x61417272) + if ( ld_32(fs->win + FSI_LeadSig) == 0x41615252 /* Load FSInfo data if available */ + && ld_32(fs->win + FSI_StrucSig) == 0x61417272 + && ld_32(fs->win + FSI_TrailSig) == 0xAA550000) { -#if (FF_FS_NOFSINFO & 1) == 0 - fs->free_clst = ld_dword(fs->win + FSI_Free_Count); +#if (FF_FS_NOFSINFO & 1) == 0 /* Get free cluster count if trust it */ + fs->free_clst = ld_32(fs->win + FSI_Free_Count); #endif -#if (FF_FS_NOFSINFO & 2) == 0 - fs->last_clst = ld_dword(fs->win + FSI_Nxt_Free); +#if (FF_FS_NOFSINFO & 2) == 0 /* Get next free cluster if rtust it */ + fs->last_clst = ld_32(fs->win + FSI_Nxt_Free); #endif } } -#endif /* (FF_FS_NOFSINFO & 3) != 3 */ #endif /* !FF_FS_READONLY */ } fs->fs_type = (BYTE)fmt;/* FAT sub-type (the filesystem object gets valid) */ fs->id = ++Fsid; /* Volume mount ID */ -#if FF_USE_LFN == 1 - fs->lfnbuf = LfnBuf; /* Static LFN working buffer */ + +#if FF_USE_LFN == 1 /* Initilize pointers to the static working buffers */ + fs->lfnbuf = LfnBuf; /* LFN working buffer */ #if FF_FS_EXFAT - fs->dirbuf = DirBuf; /* Static directory block scratchpad buuffer */ + fs->dirbuf = DirBuf; /* Directory block scratchpad buuffer */ +#endif #endif + +#if FF_FS_RPATH /* Set the current directory top layer (root) */ + fs->cdir = 0; +#if FF_FS_EXFAT + memset(&fs->xcwds, 0, sizeof fs->xcwds); #endif -#if FF_FS_RPATH != 0 - fs->cdir = 0; /* Initialize current directory */ #endif + #if FF_FS_LOCK /* Clear file lock semaphores */ clear_share(fs); #endif + return FR_OK; } @@ -3621,7 +3703,7 @@ static FRESULT validate ( /* Returns FR_OK or FR_INVALID_OBJECT */ if (obj && obj->fs && obj->fs->fs_type && obj->id == obj->fs->id) { /* Test if the object is valid */ #if FF_FS_REENTRANT if (lock_volume(obj->fs, 0)) { /* Take a grant to access the volume */ - if (!(disk_status(obj->fs->pdrv) & STA_NOINIT)) { /* Test if the hosting phsical drive is kept initialized */ + if (!(disk_status(obj->fs->pdrv) & STA_NOINIT)) { /* Test if the hosting physical drive is kept initialized */ res = FR_OK; } else { unlock_volume(obj->fs, FR_OK); /* Invalidated volume, abort to access */ @@ -3630,7 +3712,7 @@ static FRESULT validate ( /* Returns FR_OK or FR_INVALID_OBJECT */ res = FR_TIMEOUT; } #else - if (!(disk_status(obj->fs->pdrv) & STA_NOINIT)) { /* Test if the hosting phsical drive is kept initialized */ + if (!(disk_status(obj->fs->pdrv) & STA_NOINIT)) { /* Test if the hosting physical drive is kept initialized */ res = FR_OK; } #endif @@ -3651,7 +3733,7 @@ static FRESULT validate ( /* Returns FR_OK or FR_INVALID_OBJECT */ /*-----------------------------------------------------------------------*/ -/* Mount/Unmount a Logical Drive */ +/* API: Mount/Unmount a Logical Drive */ /*-----------------------------------------------------------------------*/ FRESULT f_mount ( @@ -3669,11 +3751,11 @@ FRESULT f_mount ( /* Get volume ID (logical drive number) */ vol = get_ldnumber(&rp); if (vol < 0) return FR_INVALID_DRIVE; - cfs = FatFs[vol]; /* Pointer to the filesystem object of the volume */ - if (cfs) { /* Unregister current filesystem object if regsitered */ + cfs = FatFs[vol]; /* Pointer to the filesystem object of the volume */ + if (cfs) { /* Unregister current filesystem object */ FatFs[vol] = 0; -#if FF_FS_LOCK +#if FF_FS_LOCK /* Clear file lock semaphores correspond to this volume */ clear_share(cfs); #endif #if FF_FS_REENTRANT /* Discard mutex of the current volume */ @@ -3698,12 +3780,12 @@ FRESULT f_mount ( #endif #endif fs->fs_type = 0; /* Invalidate the new filesystem object */ - FatFs[vol] = fs; /* Register new fs object */ + FatFs[vol] = fs; /* Register it */ } if (opt == 0) return FR_OK; /* Do not mount now, it will be mounted in subsequent file functions */ - res = mount_volume(&path, &fs, 0); /* Force mounted the volume */ + res = mount_volume(&path, &fs, 0); /* Force mounted the volume in this function */ LEAVE_FF(fs, res); } @@ -3711,7 +3793,7 @@ FRESULT f_mount ( /*-----------------------------------------------------------------------*/ -/* Open or Create a File */ +/* API: Open or Create a File */ /*-----------------------------------------------------------------------*/ FRESULT f_open ( @@ -3723,22 +3805,19 @@ FRESULT f_open ( FRESULT res; DIR dj; FATFS *fs; -#if !FF_FS_READONLY - DWORD cl, bcs, clst, tm; - LBA_t sc; - FSIZE_t ofs; -#endif - DEF_NAMBUF + DEF_NAMEBUFF - if (!fp) return FR_INVALID_OBJECT; + if (!fp) return FR_INVALID_OBJECT; /* Reject null pointer */ - /* Get logical drive number */ + /* Get logical drive number and mount the volume if needed */ mode &= FF_FS_READONLY ? FA_READ : FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_CREATE_NEW | FA_OPEN_ALWAYS | FA_OPEN_APPEND; res = mount_volume(&path, &fs, mode); + if (res == FR_OK) { + fp->obj.fs = fs; dj.obj.fs = fs; - INIT_NAMBUF(fs); + INIT_NAMEBUFF(fs); res = follow_path(&dj, path); /* Follow the file path */ #if !FF_FS_READONLY /* Read/Write configuration */ if (res == FR_OK) { @@ -3763,24 +3842,25 @@ FRESULT f_open ( } mode |= FA_CREATE_ALWAYS; /* File is created */ } - else { /* Any object with the same name is already existing */ - if (dj.obj.attr & (AM_RDO | AM_DIR)) { /* Cannot overwrite it (R/O or DIR) */ - res = FR_DENIED; + else { /* An object with the same name is already existing */ + if (mode & FA_CREATE_NEW) { + res = FR_EXIST; /* Cannot create as new file */ } else { - if (mode & FA_CREATE_NEW) res = FR_EXIST; /* Cannot create as new file */ + if (dj.obj.attr & (AM_RDO | AM_DIR)) res = FR_DENIED; /* Cannot overwrite it (R/O or DIR) */ } } if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) { /* Truncate the file if overwrite mode */ + DWORD tm = GET_FATTIME(); #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* Get current allocation info */ - fp->obj.fs = fs; - init_alloc_info(fs, &fp->obj); - /* Set directory entry block initial state */ + init_alloc_info(&fp->obj, 0); + /* Set exFAT directory entry block initial state */ memset(fs->dirbuf + 2, 0, 30); /* Clear 85 entry except for NumSec */ memset(fs->dirbuf + 38, 0, 26); /* Clear C0 entry except for NumName and NameHash */ fs->dirbuf[XDIR_Attr] = AM_ARC; - st_dword(fs->dirbuf + XDIR_CrtTime, GET_FATTIME()); + st_32(fs->dirbuf + XDIR_CrtTime, tm); /* Set created time */ + st_32(fs->dirbuf + XDIR_ModTime, tm); /* Set modified time (tmp setting) */ fs->dirbuf[XDIR_GenFlags] = 1; res = store_xdir(&dj); if (res == FR_OK && fp->obj.sclust != 0) { /* Remove the cluster chain if exist */ @@ -3790,17 +3870,18 @@ FRESULT f_open ( } else #endif { - /* Set directory entry initial state */ - tm = GET_FATTIME(); /* Set created time */ - st_dword(dj.dir + DIR_CrtTime, tm); - st_dword(dj.dir + DIR_ModTime, tm); + DWORD cl; + /* Set FAT directory entry initial state */ + st_32(dj.dir + DIR_CrtTime, tm); /* Set created time */ + st_32(dj.dir + DIR_ModTime, tm); /* Set modified time (tmp setting) */ cl = ld_clust(fs, dj.dir); /* Get current cluster chain */ dj.dir[DIR_Attr] = AM_ARC; /* Reset attribute */ st_clust(fs, dj.dir, 0); /* Reset file allocation info */ - st_dword(dj.dir + DIR_FileSize, 0); + st_32(dj.dir + DIR_FileSize, 0); fs->wflag = 1; if (cl != 0) { /* Remove the cluster chain if exist */ - sc = fs->winsect; + LBA_t sc = fs->winsect; + res = remove_chain(&dj.obj, cl, 0); if (res == FR_OK) { res = move_window(fs, sc); @@ -3830,7 +3911,8 @@ FRESULT f_open ( if (fp->obj.lockid == 0) res = FR_INT_ERR; #endif } -#else /* R/O configuration */ + +#else /* R/O configuration */ if (res == FR_OK) { if (dj.fn[NSFLAG] & NS_NONAME) { /* Is it origin directory itself? */ res = FR_INVALID_NAME; @@ -3845,21 +3927,17 @@ FRESULT f_open ( if (res == FR_OK) { #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { - fp->obj.c_scl = dj.obj.sclust; /* Get containing directory info */ - fp->obj.c_size = ((DWORD)dj.obj.objsize & 0xFFFFFF00) | dj.obj.stat; - fp->obj.c_ofs = dj.blk_ofs; - init_alloc_info(fs, &fp->obj); + init_alloc_info(&fp->obj, &dj); } else #endif { fp->obj.sclust = ld_clust(fs, dj.dir); /* Get object allocation info */ - fp->obj.objsize = ld_dword(dj.dir + DIR_FileSize); + fp->obj.objsize = ld_32(dj.dir + DIR_FileSize); } #if FF_USE_FASTSEEK fp->cltbl = 0; /* Disable fast seek mode */ #endif - fp->obj.fs = fs; /* Validate the file object */ - fp->obj.id = fs->id; + fp->obj.id = fs->id; /* Set current volume mount ID */ fp->flag = mode; /* Set file access mode */ fp->err = 0; /* Clear error flag */ fp->sect = 0; /* Invalidate current data sector */ @@ -3869,6 +3947,9 @@ FRESULT f_open ( memset(fp->buf, 0, sizeof fp->buf); /* Clear sector buffer */ #endif if ((mode & FA_SEEKEND) && fp->obj.objsize > 0) { /* Seek to end of file if FA_OPEN_APPEND is specified */ + DWORD bcs, clst; + FSIZE_t ofs; + fp->fptr = fp->obj.objsize; /* Offset to seek */ bcs = (DWORD)fs->csize * SS(fs); /* Cluster size in byte */ clst = fp->obj.sclust; /* Follow the cluster chain */ @@ -3879,11 +3960,12 @@ FRESULT f_open ( } fp->clust = clst; if (res == FR_OK && ofs % SS(fs)) { /* Fill sector buffer if not on the sector boundary */ - sc = clst2sect(fs, clst); - if (sc == 0) { + LBA_t sec = clst2sect(fs, clst); + + if (sec == 0) { res = FR_INT_ERR; } else { - fp->sect = sc + (DWORD)(ofs / SS(fs)); + fp->sect = sec + (DWORD)(ofs / SS(fs)); #if !FF_FS_TINY if (disk_read(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) res = FR_DISK_ERR; #endif @@ -3896,7 +3978,7 @@ FRESULT f_open ( #endif } - FREE_NAMBUF(); + FREE_NAMEBUFF(); } if (res != FR_OK) fp->obj.fs = 0; /* Invalidate file object on error */ @@ -3908,7 +3990,7 @@ FRESULT f_open ( /*-----------------------------------------------------------------------*/ -/* Read File */ +/* API: Read File */ /*-----------------------------------------------------------------------*/ FRESULT f_read ( @@ -3920,7 +4002,6 @@ FRESULT f_read ( { FRESULT res; FATFS *fs; - DWORD clst; LBA_t sect; FSIZE_t remain; UINT rcnt, cc, csect; @@ -3938,6 +4019,8 @@ FRESULT f_read ( if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */ csect = (UINT)(fp->fptr / SS(fs) & (fs->csize - 1)); /* Sector offset in the cluster */ if (csect == 0) { /* On the cluster boundary? */ + DWORD clst; + if (fp->fptr == 0) { /* On the top of the file? */ clst = fp->obj.sclust; /* Follow cluster chain from the origin */ } else { /* Middle or end of the file */ @@ -4008,7 +4091,7 @@ FRESULT f_read ( #if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ -/* Write File */ +/* API: Write File */ /*-----------------------------------------------------------------------*/ FRESULT f_write ( @@ -4129,7 +4212,7 @@ FRESULT f_write ( /*-----------------------------------------------------------------------*/ -/* Synchronize the File */ +/* API: Synchronize the File */ /*-----------------------------------------------------------------------*/ FRESULT f_sync ( @@ -4138,8 +4221,6 @@ FRESULT f_sync ( { FRESULT res; FATFS *fs; - DWORD tm; - BYTE *dir; res = validate(&fp->obj, &fs); /* Check validity of the file object */ @@ -4152,7 +4233,6 @@ FRESULT f_sync ( } #endif /* Update the directory entry */ - tm = GET_FATTIME(); /* Modified time */ #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { res = fill_first_frag(&fp->obj); /* Fill first fragment on the FAT if needed */ @@ -4161,40 +4241,43 @@ FRESULT f_sync ( } if (res == FR_OK) { DIR dj; - DEF_NAMBUF + DEF_NAMEBUFF - INIT_NAMBUF(fs); + INIT_NAMEBUFF(fs); res = load_obj_xdir(&dj, &fp->obj); /* Load directory entry block */ 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); /* 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_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_32(fs->dirbuf + XDIR_FstClus, fp->obj.sclust); /* Update start cluster */ + st_64(fs->dirbuf + XDIR_FileSize, fp->obj.objsize); /* Update file size */ + st_64(fs->dirbuf + XDIR_ValidFileSize, fp->obj.objsize); /* (FatFs does not support Valid File Size feature) */ + st_32(fs->dirbuf + XDIR_ModTime, GET_FATTIME()); /* Update modified time */ fs->dirbuf[XDIR_ModTime10] = 0; - st_dword(fs->dirbuf + XDIR_AccTime, 0); - res = store_xdir(&dj); /* Restore it to the directory */ + fs->dirbuf[XDIR_ModTZ] = 0; + st_32(fs->dirbuf + XDIR_AccTime, 0); /* Invalidate last access time */ + fs->dirbuf[XDIR_AccTZ] = 0; + res = store_xdir(&dj); /* Restore it to the directory */ if (res == FR_OK) { res = sync_fs(fs); fp->flag &= (BYTE)~FA_MODIFIED; } } - FREE_NAMBUF(); + FREE_NAMEBUFF(); } } else #endif { res = move_window(fs, fp->dir_sect); if (res == FR_OK) { - dir = fp->dir_ptr; - dir[DIR_Attr] |= AM_ARC; /* Set archive attribute to indicate that the file has been changed */ - st_clust(fp->obj.fs, dir, fp->obj.sclust); /* Update file allocation information */ - st_dword(dir + DIR_FileSize, (DWORD)fp->obj.objsize); /* Update file size */ - st_dword(dir + DIR_ModTime, tm); /* Update modified time */ - st_word(dir + DIR_LstAccDate, 0); + BYTE *dir = fp->dir_ptr; + + dir[DIR_Attr] |= AM_ARC; /* Set archive attribute to indicate that the file has been changed */ + st_clust(fp->obj.fs, dir, fp->obj.sclust); /* Update file allocation information */ + st_32(dir + DIR_FileSize, (DWORD)fp->obj.objsize); /* Update file size */ + st_32(dir + DIR_ModTime, GET_FATTIME()); /* Update modified time */ + st_16(dir + DIR_LstAccDate, 0); /* Invalidate last access date */ fs->wflag = 1; - res = sync_fs(fs); /* Restore it to the directory */ + res = sync_fs(fs); /* Restore it to the directory */ fp->flag &= (BYTE)~FA_MODIFIED; } } @@ -4210,7 +4293,7 @@ FRESULT f_sync ( /*-----------------------------------------------------------------------*/ -/* Close File */ +/* API: Close File */ /*-----------------------------------------------------------------------*/ FRESULT f_close ( @@ -4246,7 +4329,7 @@ FRESULT f_close ( #if FF_FS_RPATH >= 1 /*-----------------------------------------------------------------------*/ -/* Change Current Directory or Current Drive, Get Current Directory */ +/* API: Change Current Drive */ /*-----------------------------------------------------------------------*/ FRESULT f_chdrive ( @@ -4266,57 +4349,56 @@ FRESULT f_chdrive ( + +/*-----------------------------------------------------------------------*/ +/* API: Change Current Directory */ +/*-----------------------------------------------------------------------*/ + FRESULT f_chdir ( const TCHAR* path /* Pointer to the directory path */ ) { -#if FF_STR_VOLUME_ID == 2 - UINT i; -#endif FRESULT res; DIR dj; FATFS *fs; - DEF_NAMBUF + DEF_NAMEBUFF - /* Get logical drive */ - res = mount_volume(&path, &fs, 0); + res = mount_volume(&path, &fs, 0); /* Get logical drive and mount the volume if needed */ if (res == FR_OK) { dj.obj.fs = fs; - INIT_NAMBUF(fs); + INIT_NAMEBUFF(fs); res = follow_path(&dj, path); /* Follow the path */ if (res == FR_OK) { /* Follow completed */ if (dj.fn[NSFLAG] & NS_NONAME) { /* Is it the start directory itself? */ - fs->cdir = dj.obj.sclust; #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { - fs->cdc_scl = dj.obj.c_scl; - fs->cdc_size = dj.obj.c_size; - fs->cdc_ofs = dj.obj.c_ofs; + memcpy(&fs->xcwds, &fs->xcwds2, sizeof fs->xcwds); } #endif + fs->cdir = dj.obj.sclust; } else { if (dj.obj.attr & AM_DIR) { /* It is a sub-directory */ #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { - fs->cdir = ld_dword(fs->dirbuf + XDIR_FstClus); /* Sub-directory cluster */ - fs->cdc_scl = dj.obj.sclust; /* Save containing directory information */ - fs->cdc_size = ((DWORD)dj.obj.objsize & 0xFFFFFF00) | dj.obj.stat; - fs->cdc_ofs = dj.blk_ofs; + memcpy(&fs->xcwds, &fs->xcwds2, sizeof fs->xcwds); + fs->cdir = fs->xcwds.tbl[fs->xcwds.depth].d_scl; /* Sub-directory cluster */ } else #endif { - fs->cdir = ld_clust(fs, dj.dir); /* Sub-directory cluster */ + fs->cdir = ld_clust(fs, dj.dir); /* Sub-directory cluster */ } } else { res = FR_NO_PATH; /* Reached but a file */ } } } - FREE_NAMBUF(); + FREE_NAMEBUFF(); if (res == FR_NO_FILE) res = FR_NO_PATH; #if FF_STR_VOLUME_ID == 2 /* Also current drive is changed if in Unix style volume ID */ if (res == FR_OK) { + UINT i; + for (i = FF_VOLUMES - 1; i && fs != FatFs[i]; i--) ; /* Set current drive */ CurrVol = (BYTE)i; } @@ -4327,96 +4409,136 @@ FRESULT f_chdir ( } + + #if FF_FS_RPATH >= 2 +/*-----------------------------------------------------------------------*/ +/* API: Get Curent Directory */ +/*-----------------------------------------------------------------------*/ + FRESULT f_getcwd ( - TCHAR* buff, /* Pointer to the directory path */ + TCHAR* buff, /* Pointer to the buffer to store the current direcotry path */ UINT len /* Size of buff in unit of TCHAR */ ) { FRESULT res; DIR dj; FATFS *fs; - UINT i, n; - DWORD ccl; - TCHAR *tp = buff; #if FF_VOLUMES >= 2 UINT vl; #if FF_STR_VOLUME_ID - const char *vp; + const char *vid; #endif #endif FILINFO fno; - DEF_NAMBUF + DEF_NAMEBUFF - /* Get logical drive */ - buff[0] = 0; /* Set null string to get current volume */ - res = mount_volume((const TCHAR**)&buff, &fs, 0); /* Get current volume */ + buff[0] = 0; /* A null str to get current drive */ + res = mount_volume((const TCHAR**)&buff, &fs, 0); if (res == FR_OK) { dj.obj.fs = fs; - INIT_NAMBUF(fs); + INIT_NAMEBUFF(fs); +#if FF_FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ + UINT wi = 0; + UINT di, ni; + +#if FF_VOLUMES >= 2 /* Add drive prefix if needed */ +#if FF_STR_VOLUME_ID == 0 /* Numeric volume ID */ + if (wi < len) buff[wi++] = '0' + CurrVol; +#else /* String volume ID */ + if (FF_STR_VOLUME_ID == 2 && wi < len) buff[wi++] = '/'; + for (vid = (const char*)VolumeStr[CurrVol]; *vid && wi < len; buff[wi++] = *vid++) ; +#endif + if (FF_STR_VOLUME_ID <= 1 && wi < len) buff[wi++] = ':'; +#endif + if (wi < len) buff[wi++] = '/'; + for (di = 0; wi < len && di < fs->xcwds.depth; di++) { /* Follow current directory path with cwd structure */ + dj.obj.sclust = fs->xcwds.tbl[di].d_scl; /* Open this directory */ + dj.obj.stat = (BYTE)fs->xcwds.tbl[di].d_size; + dj.obj.objsize = fs->xcwds.tbl[di].d_size & 0xFFFFFF00; + res = dir_sdi(&dj, fs->xcwds.tbl[di].nxt_ofs); /* Find next directory */ + if (res != FR_OK) break; + res = DIR_READ_FILE(&dj); /* Get the directory name */ + if (res != FR_OK) break; + get_fileinfo(&dj, &fno); + if (di > 0 && wi < len) buff[wi++] = '/'; /* Add the directory name with a directory separator */ + for (ni = 0; fno.fname[ni] && wi < len; buff[wi++] = fno.fname[ni++]) ; + } + if (wi == len) { /* Buffer overflow? */ + res = FR_NOT_ENOUGH_CORE; + } else { + buff[wi] = 0; /* Terminate the string */ + } + } + else +#endif + { /* On the FAT/FAT32 volume */ + TCHAR *tp = buff; + UINT i, nl; + DWORD ccl; - /* Follow parent directories and create the path */ - i = len; /* Bottom of buffer (directory stack base) */ - if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { /* (Cannot do getcwd on exFAT and returns root path) */ + /* Follow parent directories toward the root directory and create the cwd path */ + i = len; /* Bottom of buffer (directory stack base) */ dj.obj.sclust = fs->cdir; /* Start to follow upper directory from current directory */ while ((ccl = dj.obj.sclust) != 0) { /* Repeat while current directory is a sub-directory */ - res = dir_sdi(&dj, 1 * SZDIRE); /* Get parent directory */ + res = dir_sdi(&dj, 1 * SZDIRE); /* Get parent directory */ if (res != FR_OK) break; res = move_window(fs, dj.sect); if (res != FR_OK) break; - dj.obj.sclust = ld_clust(fs, dj.dir); /* Goto parent directory */ + dj.obj.sclust = ld_clust(fs, dj.dir); /* Go to parent directory */ res = dir_sdi(&dj, 0); if (res != FR_OK) break; - do { /* Find the entry links to the child directory */ + do { /* Find the entry links to this sub-directory */ res = DIR_READ_FILE(&dj); if (res != FR_OK) break; if (ccl == ld_clust(fs, dj.dir)) break; /* Found the entry */ res = dir_next(&dj, 0); } while (res == FR_OK); - if (res == FR_NO_FILE) res = FR_INT_ERR;/* It cannot be 'not found'. */ + if (res == FR_NO_FILE) res = FR_INT_ERR; /* It cannot be 'not found'. */ if (res != FR_OK) break; - get_fileinfo(&dj, &fno); /* Get the directory name and push it to the buffer */ - for (n = 0; fno.fname[n]; n++) ; /* Name length */ - if (i < n + 1) { /* Insufficient space to store the path name? */ + get_fileinfo(&dj, &fno); /* Get the directory name and push it to the buffer */ + for (nl = 0; fno.fname[nl]; nl++) ; /* Name length */ + if (i < nl + 1) { /* Insufficient space to store the path name? */ res = FR_NOT_ENOUGH_CORE; break; } - while (n) buff[--i] = fno.fname[--n]; /* Stack the name */ + while (nl) buff[--i] = fno.fname[--nl]; /* Stack the name */ buff[--i] = '/'; } - } - if (res == FR_OK) { - if (i == len) buff[--i] = '/'; /* Is it the root-directory? */ + if (res == FR_OK) { + if (i == len) buff[--i] = '/'; /* Is it the root-directory? */ #if FF_VOLUMES >= 2 /* Put drive prefix */ - vl = 0; + vl = 0; #if FF_STR_VOLUME_ID >= 1 /* String volume ID */ - for (n = 0, vp = (const char*)VolumeStr[CurrVol]; vp[n]; n++) ; - if (i >= n + 2) { - if (FF_STR_VOLUME_ID == 2) *tp++ = (TCHAR)'/'; - for (vl = 0; vl < n; *tp++ = (TCHAR)vp[vl], vl++) ; - if (FF_STR_VOLUME_ID == 1) *tp++ = (TCHAR)':'; - vl++; - } + for (nl = 0, vid = (const char*)VolumeStr[CurrVol]; vid[nl]; nl++) ; /* Volume ID length */ + if (i >= nl + 2) { + if (FF_STR_VOLUME_ID == 2) *tp++ = '/'; /* Unix style */ + for (vl = 0; vl < nl; *tp++ = vid[vl], vl++) ; + if (FF_STR_VOLUME_ID == 1) *tp++ = ':'; /* DOS/Windows style */ + vl++; + } #else /* Numeric volume ID */ - if (i >= 3) { - *tp++ = (TCHAR)'0' + CurrVol; - *tp++ = (TCHAR)':'; - vl = 2; - } + if (i >= 3) { + *tp++ = '0' + CurrVol; + *tp++ = ':'; + vl = 2; + } #endif - if (vl == 0) res = FR_NOT_ENOUGH_CORE; + if (vl == 0) res = FR_NOT_ENOUGH_CORE; #endif - /* Add current directory path */ - if (res == FR_OK) { - do { /* Copy stacked path string */ - *tp++ = buff[i++]; - } while (i < len); + /* Add current directory path */ + if (res == FR_OK) { + do { /* Copy stacked path string */ + *tp++ = buff[i++]; + } while (i < len); + } } + *tp = 0; } - FREE_NAMBUF(); + FREE_NAMEBUFF(); } - *tp = 0; LEAVE_FF(fs, res); } @@ -4427,7 +4549,7 @@ FRESULT f_getcwd ( #if FF_FS_MINIMIZE <= 2 /*-----------------------------------------------------------------------*/ -/* Seek File Read/Write Pointer */ +/* API: Seek File Read/Write Pointer */ /*-----------------------------------------------------------------------*/ FRESULT f_lseek ( @@ -4440,11 +4562,7 @@ FRESULT f_lseek ( DWORD clst, bcs; LBA_t nsect; FSIZE_t ifptr; -#if FF_USE_FASTSEEK - DWORD cl, pcl, ncl, tcl, tlen, ulen; - DWORD *tbl; - LBA_t dsc; -#endif + res = validate(&fp->obj, &fs); /* Check validity of the file object */ if (res == FR_OK) res = (FRESULT)fp->err; @@ -4457,6 +4575,10 @@ FRESULT f_lseek ( #if FF_USE_FASTSEEK if (fp->cltbl) { /* Fast seek */ + DWORD cl, pcl, ncl, tcl, tlen, ulen; + DWORD *tbl; + LBA_t dsc; + if (ofs == CREATE_LINKMAP) { /* Create CLMT */ tbl = fp->cltbl; tlen = *tbl++; ulen = 2; /* Given table size and required table size */ @@ -4591,7 +4713,7 @@ FRESULT f_lseek ( #if FF_FS_MINIMIZE <= 1 /*-----------------------------------------------------------------------*/ -/* Create a Directory Object */ +/* API: Create a Directory Object */ /*-----------------------------------------------------------------------*/ FRESULT f_opendir ( @@ -4601,26 +4723,22 @@ FRESULT f_opendir ( { FRESULT res; FATFS *fs; - DEF_NAMBUF + DEF_NAMEBUFF - if (!dp) return FR_INVALID_OBJECT; + if (!dp) return FR_INVALID_OBJECT; /* Reject null pointer */ - /* Get logical drive */ - res = mount_volume(&path, &fs, 0); + res = mount_volume(&path, &fs, 0); /* Get logical drive and mount the volume if needed */ if (res == FR_OK) { dp->obj.fs = fs; - INIT_NAMBUF(fs); + INIT_NAMEBUFF(fs); res = follow_path(dp, path); /* Follow the path to the directory */ if (res == FR_OK) { /* Follow completed */ - if (!(dp->fn[NSFLAG] & NS_NONAME)) { /* It is not the origin directory itself */ + if (!(dp->fn[NSFLAG] & NS_NONAME)) { /* It is neither the origin directory itself nor dot name in exFAT */ if (dp->obj.attr & AM_DIR) { /* This object is a sub-directory */ #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { - dp->obj.c_scl = dp->obj.sclust; /* Get containing directory inforamation */ - dp->obj.c_size = ((DWORD)dp->obj.objsize & 0xFFFFFF00) | dp->obj.stat; - dp->obj.c_ofs = dp->blk_ofs; - init_alloc_info(fs, &dp->obj); /* Get object allocation info */ + init_alloc_info(&dp->obj, dp); /* Get object allocation info */ } else #endif { @@ -4631,21 +4749,21 @@ FRESULT f_opendir ( } } if (res == FR_OK) { - dp->obj.id = fs->id; - res = dir_sdi(dp, 0); /* Rewind directory */ + dp->obj.id = fs->id; /* Set current volume mount ID */ + res = dir_sdi(dp, 0); /* Rewind directory */ #if FF_FS_LOCK if (res == FR_OK) { - if (dp->obj.sclust != 0) { - dp->obj.lockid = inc_share(dp, 0); /* Lock the sub directory */ + if (dp->obj.sclust) { /* Is this a sub-directory? */ + dp->obj.lockid = inc_share(dp, 0); /* Lock the sub-directory */ if (!dp->obj.lockid) res = FR_TOO_MANY_OPEN_FILES; } else { - dp->obj.lockid = 0; /* Root directory need not to be locked */ + dp->obj.lockid = 0; /* Root directory does not need to be locked */ } } #endif } } - FREE_NAMBUF(); + FREE_NAMEBUFF(); if (res == FR_NO_FILE) res = FR_NO_PATH; } if (res != FR_OK) dp->obj.fs = 0; /* Invalidate the directory object if function failed */ @@ -4657,7 +4775,7 @@ FRESULT f_opendir ( /*-----------------------------------------------------------------------*/ -/* Close Directory */ +/* API: Close Directory */ /*-----------------------------------------------------------------------*/ FRESULT f_closedir ( @@ -4687,7 +4805,7 @@ FRESULT f_closedir ( /*-----------------------------------------------------------------------*/ -/* Read Directory Entries in Sequence */ +/* API: Read Directory Entries in Sequence */ /*-----------------------------------------------------------------------*/ FRESULT f_readdir ( @@ -4697,7 +4815,7 @@ FRESULT f_readdir ( { FRESULT res; FATFS *fs; - DEF_NAMBUF + DEF_NAMEBUFF res = validate(&dp->obj, &fs); /* Check validity of the directory object */ @@ -4705,7 +4823,8 @@ FRESULT f_readdir ( if (!fno) { res = dir_sdi(dp, 0); /* Rewind the directory object */ } else { - INIT_NAMBUF(fs); + INIT_NAMEBUFF(fs); + fno->fname[0] = 0; /* Clear file information */ res = DIR_READ_FILE(dp); /* Read an item */ if (res == FR_NO_FILE) res = FR_OK; /* Ignore end of directory */ if (res == FR_OK) { /* A valid entry is found */ @@ -4713,9 +4832,11 @@ FRESULT f_readdir ( res = dir_next(dp, 0); /* Increment index for next */ if (res == FR_NO_FILE) res = FR_OK; /* Ignore end of directory now */ } - FREE_NAMBUF(); + FREE_NAMEBUFF(); } } + + if (fno && res != FR_OK) fno->fname[0] = 0; /* Clear the file information if any error occured */ LEAVE_FF(fs, res); } @@ -4740,7 +4861,7 @@ FRESULT f_seekdir( #if FF_USE_FIND /*-----------------------------------------------------------------------*/ -/* Find Next File */ +/* API: Find Next File */ /*-----------------------------------------------------------------------*/ FRESULT f_findnext ( @@ -4765,7 +4886,7 @@ FRESULT f_findnext ( /*-----------------------------------------------------------------------*/ -/* Find First File */ +/* API: Find First File */ /*-----------------------------------------------------------------------*/ FRESULT f_findfirst ( @@ -4792,7 +4913,7 @@ FRESULT f_findfirst ( #if FF_FS_MINIMIZE == 0 /*-----------------------------------------------------------------------*/ -/* Get File Status */ +/* API: Get File Status */ /*-----------------------------------------------------------------------*/ FRESULT f_stat ( @@ -4802,13 +4923,14 @@ FRESULT f_stat ( { FRESULT res; DIR dj; - DEF_NAMBUF + DEF_NAMEBUFF - /* Get logical drive */ + /* Get logical drive and mount the volume if needed */ res = mount_volume(&path, &dj.obj.fs, 0); + if (res == FR_OK) { - INIT_NAMBUF(dj.obj.fs); + INIT_NAMEBUFF(dj.obj.fs); res = follow_path(&dj, path); /* Follow the file path */ if (res == FR_OK) { /* Follow completed */ if (dj.fn[NSFLAG] & NS_NONAME) { /* It is origin directory */ @@ -4817,9 +4939,10 @@ FRESULT f_stat ( if (fno) get_fileinfo(&dj, fno); } } - FREE_NAMBUF(); + FREE_NAMEBUFF(); } + if (fno && res != FR_OK) fno->fname[0] = 0; /* Invalidate the file information if an error occured */ LEAVE_FF(dj.obj.fs, res); } @@ -4827,13 +4950,13 @@ FRESULT f_stat ( #if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ -/* Get Number of Free Clusters */ +/* API: Get Number of Free Clusters */ /*-----------------------------------------------------------------------*/ FRESULT f_getfree ( const TCHAR* path, /* Logical drive number */ DWORD* nclst, /* Pointer to a variable to return number of free clusters */ - FATFS** fatfs /* Pointer to return pointer to corresponding filesystem object */ + FATFS** fatfs /* Pointer to a pointer to return corresponding filesystem object */ ) { FRESULT res; @@ -4844,15 +4967,16 @@ FRESULT f_getfree ( FFOBJID obj; - /* Get logical drive */ + /* Get logical drive and mount the volume if needed */ 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 */ if (fs->free_clst <= fs->n_fatent - 2) { *nclst = fs->free_clst; } else { - /* Scan FAT to obtain number of free clusters */ + /* Scan FAT to obtain the correct free cluster count */ nfree = 0; if (fs->fs_type == FS_FAT12) { /* FAT12: Scan bit field FAT entries */ clst = 2; obj.fs = fs; @@ -4875,16 +4999,16 @@ FRESULT f_getfree ( clst = fs->n_fatent - 2; /* Number of clusters */ sect = fs->bitbase; /* Bitmap sector */ i = 0; /* Offset in the sector */ - do { /* Counts numbuer of bits with zero in the bitmap */ + do { /* Counts numbuer of clear bits (free clusters) in the bitmap */ if (i == 0) { /* New sector? */ res = move_window(fs, sect++); if (res != FR_OK) break; } - for (b = 8, bm = ~fs->win[i]; b && clst; b--, clst--) { + for (b = 8, bm = ~fs->win[i]; b && clst; b--, clst--) { /* Count clear bits in a byte */ nfree += bm & 1; bm >>= 1; } - i = (i + 1) % SS(fs); + i = (i + 1) % SS(fs); /* Next byte */ } while (clst); } else #endif @@ -4898,11 +5022,11 @@ FRESULT f_getfree ( if (res != FR_OK) break; } if (fs->fs_type == FS_FAT16) { - if (ld_word(fs->win + i) == 0) nfree++; - i += 2; + if (ld_16(fs->win + i) == 0) nfree++; /* FAT16: Is this cluster free? */ + i += 2; /* Next entry */ } else { - if ((ld_dword(fs->win + i) & 0x0FFFFFFF) == 0) nfree++; - i += 4; + if ((ld_32(fs->win + i) & 0x0FFFFFFF) == 0) nfree++; /* FAT32: Is this cluster free? */ + i += 4; /* Next entry */ } i %= SS(fs); } while (--clst); @@ -4910,8 +5034,8 @@ FRESULT f_getfree ( } if (res == FR_OK) { /* Update parameters if succeeded */ *nclst = nfree; /* Return the free clusters */ - fs->free_clst = nfree; /* Now free_clst is valid */ - fs->fsi_flag |= 1; /* FAT32: FSInfo is to be updated */ + fs->free_clst = nfree; /* Now free cluster count is valid */ + fs->fsi_flag |= 1; /* FAT32/exfAT : Allocation information is to be updated */ } } } @@ -4923,7 +5047,7 @@ FRESULT f_getfree ( /*-----------------------------------------------------------------------*/ -/* Truncate File */ +/* API: Truncate File */ /*-----------------------------------------------------------------------*/ FRESULT f_truncate ( @@ -4935,7 +5059,8 @@ FRESULT f_truncate ( DWORD ncl; - res = validate(&fp->obj, &fs); /* Check validity of the file object */ + /* Check validity of the file object */ + res = validate(&fp->obj, &fs); if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ @@ -4973,7 +5098,7 @@ FRESULT f_truncate ( /*-----------------------------------------------------------------------*/ -/* Delete a File/Directory */ +/* API: Delete a File/Directory */ /*-----------------------------------------------------------------------*/ FRESULT f_unlink ( @@ -4987,77 +5112,72 @@ FRESULT f_unlink ( #if FF_FS_EXFAT FFOBJID obj; #endif - DEF_NAMBUF - + DEF_NAMEBUFF - /* Get logical drive */ + /* Get logical drive and mount the volume if needed */ res = mount_volume(&path, &fs, FA_WRITE); if (res == FR_OK) { dj.obj.fs = fs; - INIT_NAMBUF(fs); - res = follow_path(&dj, path); /* Follow the file path */ - if (FF_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) { - res = FR_INVALID_NAME; /* Cannot remove dot entry */ - } + INIT_NAMEBUFF(fs); + res = follow_path(&dj, path); /* Follow the path to the object */ + if (res == FR_OK) { + if (dj.fn[NSFLAG] & (NS_DOT | NS_NONAME)) { + res = FR_INVALID_NAME; /* It must be a real object */ + } else if (dj.obj.attr & AM_RDO) { + res = FR_DENIED; /* The object must not be read-only */ #if FF_FS_LOCK - if (res == FR_OK) res = chk_share(&dj, 2); /* Check if it is an open object */ -#endif - if (res == FR_OK) { /* The object is accessible */ - if (dj.fn[NSFLAG] & NS_NONAME) { - res = FR_INVALID_NAME; /* Cannot remove the origin directory */ } else { - if (dj.obj.attr & AM_RDO) { - res = FR_DENIED; /* Cannot remove R/O object */ - } + res = chk_share(&dj, 2); /* Check if the object is in use */ +#endif } - if (res == FR_OK) { + } + if (res == FR_OK) { /* The object is accessible */ #if FF_FS_EXFAT - obj.fs = fs; - if (fs->fs_type == FS_EXFAT) { - init_alloc_info(fs, &obj); - dclst = obj.sclust; + obj.fs = fs; + if (fs->fs_type == FS_EXFAT) { + init_alloc_info(&obj, 0); + dclst = obj.sclust; + } else +#endif + { + dclst = ld_clust(fs, dj.dir); + } + if (dj.obj.attr & AM_DIR) { /* Is the object a sub-directory? */ +#if FF_FS_RPATH + if (dclst == fs->cdir) { + res = FR_DENIED; /* Current directory cannot be removed */ } else #endif { - dclst = ld_clust(fs, dj.dir); - } - if (dj.obj.attr & AM_DIR) { /* Is it a sub-directory? */ -#if FF_FS_RPATH != 0 - if (dclst == fs->cdir) { /* Is it the current directory? */ - res = FR_DENIED; - } else -#endif - { - sdj.obj.fs = fs; /* Open the sub-directory */ - sdj.obj.sclust = dclst; + sdj.obj.fs = fs; /* Open the sub-directory */ + sdj.obj.sclust = dclst; #if FF_FS_EXFAT - if (fs->fs_type == FS_EXFAT) { - sdj.obj.objsize = obj.objsize; - sdj.obj.stat = obj.stat; - } + if (fs->fs_type == FS_EXFAT) { + sdj.obj.objsize = obj.objsize; + sdj.obj.stat = obj.stat; + } #endif - res = dir_sdi(&sdj, 0); - if (res == FR_OK) { - res = DIR_READ_FILE(&sdj); /* Test if the directory is empty */ - if (res == FR_OK) res = FR_DENIED; /* Not empty? */ - if (res == FR_NO_FILE) res = FR_OK; /* Empty? */ - } + res = dir_sdi(&sdj, 0); + if (res == FR_OK) { + res = DIR_READ_FILE(&sdj); /* Check if the sub-directory is empty */ + if (res == FR_OK) res = FR_DENIED; /* Not empty? */ + if (res == FR_NO_FILE) res = FR_OK; /* Empty? */ } } } - if (res == FR_OK) { - res = dir_remove(&dj); /* Remove the directory entry */ - if (res == FR_OK && dclst != 0) { /* Remove the cluster chain if exist */ + } + if (res == FR_OK) { /* It is ready to remove the object */ + res = dir_remove(&dj); /* Remove the directory entry */ + if (res == FR_OK && dclst != 0) { /* Remove the cluster chain if exist */ #if FF_FS_EXFAT - res = remove_chain(&obj, dclst, 0); + res = remove_chain(&obj, dclst, 0); #else - res = remove_chain(&dj.obj, dclst, 0); + res = remove_chain(&dj.obj, dclst, 0); #endif - } - if (res == FR_OK) res = sync_fs(fs); } + if (res == FR_OK) res = sync_fs(fs); } - FREE_NAMBUF(); + FREE_NAMEBUFF(); } LEAVE_FF(fs, res); @@ -5067,7 +5187,7 @@ FRESULT f_unlink ( /*-----------------------------------------------------------------------*/ -/* Create a Directory */ +/* API: Create a Directory */ /*-----------------------------------------------------------------------*/ FRESULT f_mkdir ( @@ -5079,20 +5199,19 @@ FRESULT f_mkdir ( DIR dj; FFOBJID sobj; DWORD dcl, pcl, tm; - DEF_NAMBUF + DEF_NAMEBUFF - res = mount_volume(&path, &fs, FA_WRITE); /* Get logical drive */ + res = mount_volume(&path, &fs, FA_WRITE); /* Get logical drive and mount the volume if needed */ if (res == FR_OK) { dj.obj.fs = fs; - INIT_NAMBUF(fs); + INIT_NAMEBUFF(fs); res = follow_path(&dj, path); /* Follow the file path */ - if (res == FR_OK) res = FR_EXIST; /* Name collision? */ - if (FF_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) { /* Invalid name? */ - res = FR_INVALID_NAME; + if (res == FR_OK) { /* Invalid name or name collision */ + res = (dj.fn[NSFLAG] & (NS_DOT | NS_NONAME)) ? FR_INVALID_NAME : FR_EXIST; } if (res == FR_NO_FILE) { /* It is clear to create a new directory */ - sobj.fs = fs; /* New object id to create a new chain */ + sobj.fs = fs; /* New object ID to create a new chain */ dcl = create_chain(&sobj, 0); /* Allocate a cluster for the new directory */ res = FR_OK; if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster? */ @@ -5100,36 +5219,38 @@ FRESULT f_mkdir ( if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR; /* Disk error? */ tm = GET_FATTIME(); if (res == FR_OK) { - res = dir_clear(fs, dcl); /* Clean up the new table */ + res = dir_clear(fs, dcl); /* Clear the allocated cluster as new direcotry table */ if (res == FR_OK) { if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { /* Create dot entries (FAT only) */ memset(fs->win + DIR_Name, ' ', 11); /* Create "." entry */ fs->win[DIR_Name] = '.'; fs->win[DIR_Attr] = AM_DIR; - st_dword(fs->win + DIR_ModTime, tm); + st_32(fs->win + DIR_ModTime, tm); st_clust(fs, fs->win, dcl); memcpy(fs->win + SZDIRE, fs->win, SZDIRE); /* Create ".." entry */ fs->win[SZDIRE + 1] = '.'; pcl = dj.obj.sclust; st_clust(fs, fs->win + SZDIRE, pcl); fs->wflag = 1; } - res = dir_register(&dj); /* Register the object to the parent directoy */ + res = dir_register(&dj); /* Register the object to the parent directory */ } } if (res == FR_OK) { #if FF_FS_EXFAT 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)); /* 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 */ + st_32(fs->dirbuf + XDIR_CrtTime, tm); /* Created time */ + st_32(fs->dirbuf + XDIR_ModTime, tm); + st_32(fs->dirbuf + XDIR_FstClus, dcl); /* Table start cluster */ + st_32(fs->dirbuf + XDIR_FileSize, (DWORD)fs->csize * SS(fs)); /* Directory size needs to be valid */ + st_32(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 */ res = store_xdir(&dj); } else #endif { - st_dword(dj.dir + DIR_ModTime, tm); /* Created time */ + st_32(dj.dir + DIR_CrtTime, tm); /* Created time */ + st_32(dj.dir + DIR_ModTime, tm); st_clust(fs, dj.dir, dcl); /* Table start cluster */ dj.dir[DIR_Attr] = AM_DIR; /* Attribute */ fs->wflag = 1; @@ -5141,7 +5262,7 @@ FRESULT f_mkdir ( remove_chain(&sobj, dcl, 0); /* Could not register, remove the allocated cluster */ } } - FREE_NAMBUF(); + FREE_NAMEBUFF(); } LEAVE_FF(fs, res); @@ -5151,7 +5272,7 @@ FRESULT f_mkdir ( /*-----------------------------------------------------------------------*/ -/* Rename a File/Directory */ +/* API: Rename a File/Directory */ /*-----------------------------------------------------------------------*/ FRESULT f_rename ( @@ -5163,42 +5284,55 @@ FRESULT f_rename ( FATFS *fs; DIR djo, djn; BYTE buf[FF_FS_EXFAT ? SZDIRE * 2 : SZDIRE], *dir; - LBA_t sect; - DEF_NAMBUF + DEF_NAMEBUFF - get_ldnumber(&path_new); /* Snip the drive number of new name off */ + get_ldnumber(&path_new); /* Snip the drive number of new name off */ 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); - res = follow_path(&djo, path_old); /* Check old object */ - if (res == FR_OK && (djo.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check validity of name */ -#if FF_FS_LOCK + INIT_NAMEBUFF(fs); + res = follow_path(&djo, path_old); /* Check old object */ if (res == FR_OK) { - res = chk_share(&djo, 2); - } + if (djo.fn[NSFLAG] & (NS_DOT | NS_NONAME)) { + res = FR_INVALID_NAME; /* Object must not be a dot name or blank name */ +#if FF_FS_LOCK + } else { + res = chk_share(&djo, 2); /* Check if the object is in use */ #endif - if (res == FR_OK) { /* Object to be renamed is found */ + } + } + if (res == FR_OK) { /* It is ready to rename the object */ #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* At exFAT volume */ - BYTE nf, nn; - WORD nh; +#if FF_FS_RPATH + UINT i; + DWORD dscl = ld_32(fs->dirbuf + XDIR_FstClus); - memcpy(buf, fs->dirbuf, SZDIRE * 2); /* Save 85+C0 entry of old object */ - memcpy(&djn, &djo, sizeof djo); - res = follow_path(&djn, path_new); /* Make sure if new object name is not in use */ - if (res == FR_OK) { /* Is new name already in use by any other object? */ + for (i = 1; i <= fs->xcwds.depth && dscl != fs->xcwds.tbl[i].d_scl; i++) ; /* Check if the object is a sub-dir in the current dir path */ + if (i <= fs->xcwds.depth) { + res = FR_DENIED; /* Reject to rename a sub-dir in the current dir path */ + } else +#endif + { + memcpy(buf, fs->dirbuf, SZDIRE * 2); /* Save 85+C0 entry of old object */ + memcpy(&djn, &djo, sizeof djn); + res = follow_path(&djn, path_new); /* Check if new object name collides with an existing one */ + } + if (res == FR_OK) { /* Is new name already in use by another object? */ res = (djn.obj.sclust == djo.obj.sclust && djn.dptr == djo.dptr) ? FR_NO_FILE : FR_EXIST; } - if (res == FR_NO_FILE) { /* It is a valid path and no name collision */ - res = dir_register(&djn); /* Register the new entry */ + if (res == FR_NO_FILE) { /* It is a valid path and no name collision */ + res = dir_register(&djn); /* Register the new entry */ if (res == FR_OK) { - nf = fs->dirbuf[XDIR_NumSec]; nn = fs->dirbuf[XDIR_NumName]; - nh = ld_word(fs->dirbuf + XDIR_NameHash); + BYTE nf, nn; + WORD nh; + + nf = fs->dirbuf[XDIR_NumSec]; nn = fs->dirbuf[XDIR_NumName]; /* Save name length and hash */ + nh = ld_16(fs->dirbuf + XDIR_NameHash); memcpy(fs->dirbuf, buf, SZDIRE * 2); /* Restore 85+C0 entry */ - fs->dirbuf[XDIR_NumSec] = nf; fs->dirbuf[XDIR_NumName] = nn; - st_word(fs->dirbuf + XDIR_NameHash, nh); + fs->dirbuf[XDIR_NumSec] = nf; fs->dirbuf[XDIR_NumName] = nn; /* Restore name length and hash */ + st_16(fs->dirbuf + XDIR_NameHash, nh); if (!(fs->dirbuf[XDIR_Attr] & AM_DIR)) fs->dirbuf[XDIR_Attr] |= AM_ARC; /* Set archive attribute if it is a file */ /* Start of critical section where an interruption can cause a cross-link */ res = store_xdir(&djn); @@ -5208,9 +5342,9 @@ FRESULT f_rename ( #endif { /* At FAT/FAT32 volume */ memcpy(buf, djo.dir, SZDIRE); /* Save directory entry of the object */ - memcpy(&djn, &djo, sizeof (DIR)); /* Duplicate the directory object */ + memcpy(&djn, &djo, sizeof djn); /* Duplicate the directory object */ res = follow_path(&djn, path_new); /* Make sure if new object name is not in use */ - if (res == FR_OK) { /* Is new name already in use by any other object? */ + if (res == FR_OK) { /* Is new name already in use by another object? */ res = (djn.obj.sclust == djo.obj.sclust && djn.dptr == djo.dptr) ? FR_NO_FILE : FR_EXIST; } if (res == FR_NO_FILE) { /* It is a valid path and no name collision */ @@ -5221,14 +5355,15 @@ FRESULT f_rename ( dir[DIR_Attr] = buf[DIR_Attr]; 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 */ - sect = clst2sect(fs, ld_clust(fs, dir)); + if ((dir[DIR_Attr] & AM_DIR) && djo.obj.sclust != djn.obj.sclust) { /* Update .. entry in the sub-directory being moved if needed */ + LBA_t 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, sect); - dir = fs->win + SZDIRE * 1; /* Ptr to .. entry */ + dir = fs->win + SZDIRE * 1; /* Pointer to .. entry */ if (res == FR_OK && dir[1] == '.') { st_clust(fs, dir, djn.obj.sclust); fs->wflag = 1; @@ -5238,15 +5373,15 @@ FRESULT f_rename ( } } } - if (res == FR_OK) { - res = dir_remove(&djo); /* Remove old entry */ + if (res == FR_OK) { /* New entry has been created */ + res = dir_remove(&djo); /* Remove old entry */ if (res == FR_OK) { res = sync_fs(fs); } } /* End of the critical section */ } - FREE_NAMBUF(); + FREE_NAMEBUFF(); } LEAVE_FF(fs, res); @@ -5261,25 +5396,27 @@ FRESULT f_rename ( #if FF_USE_CHMOD && !FF_FS_READONLY /*-----------------------------------------------------------------------*/ -/* Change Attribute */ +/* API: Change Attribute */ /*-----------------------------------------------------------------------*/ FRESULT f_chmod ( const TCHAR* path, /* Pointer to the file path */ - BYTE attr, /* Attribute bits */ + BYTE attr, /* Attribute bits to set/clear */ BYTE mask /* Attribute mask to change */ ) { FRESULT res; FATFS *fs; DIR dj; - DEF_NAMBUF + DEF_NAMEBUFF + + /* Get logical drive and mount the volume if needed */ + res = mount_volume(&path, &fs, FA_WRITE); - res = mount_volume(&path, &fs, FA_WRITE); /* Get logical drive */ if (res == FR_OK) { dj.obj.fs = fs; - INIT_NAMBUF(fs); + INIT_NAMEBUFF(fs); res = follow_path(&dj, path); /* Follow the file path */ if (res == FR_OK && (dj.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check object validity */ if (res == FR_OK) { @@ -5298,7 +5435,7 @@ FRESULT f_chmod ( res = sync_fs(fs); } } - FREE_NAMBUF(); + FREE_NAMEBUFF(); } LEAVE_FF(fs, res); @@ -5308,42 +5445,63 @@ FRESULT f_chmod ( /*-----------------------------------------------------------------------*/ -/* Change Timestamp */ +/* API: Change Timestamp */ /*-----------------------------------------------------------------------*/ FRESULT f_utime ( const TCHAR* path, /* Pointer to the file/directory name */ - const FILINFO* fno /* Pointer to the timestamp to be set */ + const FILINFO* fno /* Timestamp to be set */ ) { FRESULT res; FATFS *fs; DIR dj; - DEF_NAMBUF + DEF_NAMEBUFF - res = mount_volume(&path, &fs, FA_WRITE); /* Get logical drive */ + /* Get logical drive and mount the volume if needed */ + res = mount_volume(&path, &fs, FA_WRITE); + if (res == FR_OK) { dj.obj.fs = fs; - INIT_NAMBUF(fs); + INIT_NAMEBUFF(fs); res = follow_path(&dj, path); /* Follow the file path */ if (res == FR_OK && (dj.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check object validity */ if (res == FR_OK) { #if FF_FS_EXFAT - if (fs->fs_type == FS_EXFAT) { - st_dword(fs->dirbuf + XDIR_ModTime, (DWORD)fno->fdate << 16 | fno->ftime); + if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ + if (fno->fdate) { /* Change last modified time if needed */ + st_32(fs->dirbuf + XDIR_ModTime, (DWORD)fno->fdate << 16 | fno->ftime); + fs->dirbuf[XDIR_ModTime10] = 0; + fs->dirbuf[XDIR_ModTZ] = 0; + } +#if FF_FS_CRTIME + if (fno->crdate) { /* Change created time if needed */ + st_32(fs->dirbuf + XDIR_CrtTime, (DWORD)fno->crdate << 16 | fno->crtime); + fs->dirbuf[XDIR_CrtTime10] = 0; + fs->dirbuf[XDIR_CrtTZ] = 0; + } +#endif res = store_xdir(&dj); } else #endif - { - st_dword(dj.dir + DIR_ModTime, (DWORD)fno->fdate << 16 | fno->ftime); + { /* On the FAT volume */ + if (fno->fdate) { /* Change last modified time if needed */ + st_32(dj.dir + DIR_ModTime, (DWORD)fno->fdate << 16 | fno->ftime); + } +#if FF_FS_CRTIME + if (fno->crdate) { /* Change created time if needed */ + st_32(dj.dir + DIR_CrtTime, (DWORD)fno->crdate << 16 | fno->crtime); + dj.dir[DIR_CrtTime10] = 0; + } +#endif fs->wflag = 1; } if (res == FR_OK) { res = sync_fs(fs); } } - FREE_NAMBUF(); + FREE_NAMEBUFF(); } LEAVE_FF(fs, res); @@ -5355,7 +5513,7 @@ FRESULT f_utime ( #if FF_USE_LABEL /*-----------------------------------------------------------------------*/ -/* Get Volume Label */ +/* API: Get Volume Label */ /*-----------------------------------------------------------------------*/ FRESULT f_getlabel ( @@ -5370,8 +5528,8 @@ FRESULT f_getlabel ( UINT si, di; WCHAR wc; - /* Get logical drive */ - res = mount_volume(&path, &fs, 0); + + res = mount_volume(&path, &fs, 0); /* Get logical drive and mount the volume if needed */ /* Get volume label */ if (res == FR_OK && label) { @@ -5386,7 +5544,7 @@ FRESULT f_getlabel ( UINT nw; for (si = di = hs = 0; si < dj.dir[XDIR_NumLabel]; si++) { /* Extract volume label from 83 entry */ - wc = ld_word(dj.dir + XDIR_Label + si * 2); + wc = ld_16(dj.dir + XDIR_Label + si * 2); if (hs == 0 && IsSurrogate(wc)) { /* Is the code a surrogate? */ hs = wc; continue; } @@ -5431,7 +5589,7 @@ FRESULT f_getlabel ( /* Get volume serial number */ if (res == FR_OK && vsn) { - res = move_window(fs, fs->volbase); + res = move_window(fs, fs->volbase); /* Load VBR */ if (res == FR_OK) { switch (fs->fs_type) { case FS_EXFAT: @@ -5442,10 +5600,10 @@ FRESULT f_getlabel ( di = BS_VolID32; break; - default: - di = BS_VolID; + default: /* FAT12/16 */ + di = fs->win[BS_BootSig] == 0x29 ? BS_VolID : 0; } - *vsn = ld_dword(fs->win + di); + *vsn = di ? ld_32(fs->win + di) : 0; /* Get VSN in the VBR */ } } @@ -5456,7 +5614,7 @@ FRESULT f_getlabel ( #if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ -/* Set Volume Label */ +/* API: Set Volume Label */ /*-----------------------------------------------------------------------*/ FRESULT f_setlabel ( @@ -5474,9 +5632,12 @@ FRESULT f_setlabel ( DWORD dc; #endif - /* Get logical drive */ + /* Get logical drive and mount the volume if needed */ res = mount_volume(&label, &fs, FA_WRITE); if (res != FR_OK) LEAVE_FF(fs, res); +#if FF_STR_VOLUME_ID == 2 + for ( ; *label == '/'; label++) ; /* Snip the separators off */ +#endif #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ @@ -5488,13 +5649,13 @@ FRESULT f_setlabel ( if (dc == 0xFFFFFFFF || di >= 10) { /* Wrong surrogate or buffer overflow */ dc = 0; } else { - st_word(dirvn + di * 2, (WCHAR)(dc >> 16)); di++; + st_16(dirvn + di * 2, (WCHAR)(dc >> 16)); di++; } } if (dc == 0 || strchr(&badchr[7], (int)dc) || di >= 11) { /* Check validity of the volume label */ LEAVE_FF(fs, FR_INVALID_NAME); } - st_word(dirvn + di * 2, (WCHAR)dc); di++; + st_16(dirvn + di * 2, (WCHAR)dc); di++; } } else #endif @@ -5576,7 +5737,7 @@ FRESULT f_setlabel ( #if FF_USE_EXPAND && !FF_FS_READONLY /*-----------------------------------------------------------------------*/ -/* Allocate a Contiguous Blocks to the File */ +/* API: Allocate a Contiguous Blocks to the File */ /*-----------------------------------------------------------------------*/ FRESULT f_expand ( @@ -5672,7 +5833,7 @@ FRESULT f_expand ( #if FF_USE_FORWARD /*-----------------------------------------------------------------------*/ -/* Forward Data to the Stream Directly */ +/* API: Forward Data to the Stream Directly */ /*-----------------------------------------------------------------------*/ FRESULT f_forward ( @@ -5743,12 +5904,12 @@ FRESULT f_forward ( #if !FF_FS_READONLY && FF_USE_MKFS /*-----------------------------------------------------------------------*/ -/* Create FAT/exFAT volume (with sub-functions) */ +/* API: Create FAT/exFAT volume (with a sub-function) */ /*-----------------------------------------------------------------------*/ #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) */ +#define GPT_ITEMS 128 /* Number of GPT table items (>=128, sector aligned) */ /* Create partitions on the physical drive in format of MBR or GPT */ @@ -5786,19 +5947,19 @@ static FRESULT create_partition ( rnd = (DWORD)sz_drv + GET_FATTIME(); /* Random seed */ align = GPT_ALIGN / ss; /* Partition alignment for GPT [sector] */ sz_ptbl = GPT_ITEMS * SZ_GPTE / ss; /* Size of partition table [sector] */ - top_bpt = sz_drv - sz_ptbl - 1; /* Backup partition table start sector */ - nxt_alloc = 2 + sz_ptbl; /* First allocatable sector */ - sz_pool = top_bpt - nxt_alloc; /* Size of allocatable area */ + top_bpt = sz_drv - sz_ptbl - 1; /* Backup partition table start LBA */ + nxt_alloc = 2 + sz_ptbl; /* First allocatable LBA */ + sz_pool = top_bpt - nxt_alloc; /* Size of allocatable area [sector] */ bcc = 0xFFFFFFFF; sz_part = 1; - pi = si = 0; /* partition table index, size table index */ + pi = si = 0; /* partition table index, map index */ do { if (pi * SZ_GPTE % ss == 0) memset(buf, 0, ss); /* Clean the buffer if needed */ if (sz_part != 0) { /* Is the size table not termintated? */ - nxt_alloc = (nxt_alloc + align - 1) & ((QWORD)0 - align); /* Align partition start */ + nxt_alloc = (nxt_alloc + align - 1) & ((QWORD)0 - align); /* Align partition start LBA */ sz_part = plst[si++]; /* Get a partition size */ if (sz_part <= 100) { /* Is the size in percentage? */ - sz_part = sz_pool * sz_part / 100; - sz_part = (sz_part + align - 1) & ((QWORD)0 - align); /* Align partition end (only if in percentage) */ + sz_part = sz_pool * sz_part / 100; /* Sectors in percentage */ + sz_part = (sz_part + align - 1) & ((QWORD)0 - align); /* Align partition end LBA (only if in percentage) */ } if (nxt_alloc + sz_part > top_bpt) { /* Clip the size at end of the pool */ sz_part = (nxt_alloc < top_bpt) ? top_bpt - nxt_alloc : 0; @@ -5808,11 +5969,11 @@ static FRESULT create_partition ( ofs = pi * SZ_GPTE % ss; memcpy(buf + ofs + GPTE_PtGuid, GUID_MS_Basic, 16); /* Set partition GUID (Microsoft Basic Data) */ rnd = make_rand(rnd, buf + ofs + GPTE_UpGuid, 16); /* Set unique partition GUID */ - st_qword(buf + ofs + GPTE_FstLba, nxt_alloc); /* Set partition start sector */ - st_qword(buf + ofs + GPTE_LstLba, nxt_alloc + sz_part - 1); /* Set partition end sector */ - nxt_alloc += sz_part; /* Next allocatable sector */ + st_64(buf + ofs + GPTE_FstLba, nxt_alloc); /* Set partition start LBA */ + st_64(buf + ofs + GPTE_LstLba, nxt_alloc + sz_part - 1); /* Set partition end LBA */ + nxt_alloc += sz_part; /* Next allocatable LBA */ } - if ((pi + 1) * SZ_GPTE % ss == 0) { /* Write the buffer if it is filled up */ + if ((pi + 1) * SZ_GPTE % ss == 0) { /* Write the sector 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; /* Write to primary table */ if (disk_write(drv, buf, top_bpt + pi * SZ_GPTE / ss, 1) != RES_OK) return FR_DISK_ERR; /* Write to secondary table */ @@ -5822,32 +5983,32 @@ static FRESULT create_partition ( /* Create primary GPT header */ memset(buf, 0, ss); memcpy(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 secondary header */ - st_qword(buf + GPTH_FstLba, 2 + sz_ptbl); /* LBA of first allocatable sector */ - st_qword(buf + GPTH_LstLba, top_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 */ + st_32(buf + GPTH_PtBcc, ~bcc); /* Table check sum */ + st_64(buf + GPTH_CurLba, 1); /* LBA of this header */ + st_64(buf + GPTH_BakLba, sz_drv - 1); /* LBA of secondary header */ + st_64(buf + GPTH_FstLba, 2 + sz_ptbl); /* LBA of first allocatable sector */ + st_64(buf + GPTH_LstLba, top_bpt - 1); /* LBA of last allocatable sector */ + st_32(buf + GPTH_PteSize, SZ_GPTE); /* Size of a table entry */ + st_32(buf + GPTH_PtNum, GPT_ITEMS); /* Number of table entries */ + st_32(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 */ + st_32(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 primary header */ - st_qword(buf + GPTH_PtOfs, top_bpt); /* LBA of this table */ - st_dword(buf + GPTH_Bcc, 0); + st_64(buf + GPTH_CurLba, sz_drv - 1); /* LBA of this header */ + st_64(buf + GPTH_BakLba, 1); /* LBA of primary header */ + st_64(buf + GPTH_PtOfs, top_bpt); /* LBA of this table */ + st_32(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 */ + st_32(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 */ memset(buf, 0, ss); - memcpy(buf + MBR_Table, gpt_mbr, 16); /* Create a GPT partition */ - st_word(buf + BS_55AA, 0xAA55); + memcpy(buf + MBR_Table, gpt_mbr, 16); /* Create a GPT partition */ + st_16(buf + BS_55AA, 0xAA55); if (disk_write(drv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; } else @@ -5866,20 +6027,20 @@ static FRESULT create_partition ( if (nxt_alloc32 + sz_part32 > sz_drv32 || nxt_alloc32 + sz_part32 < nxt_alloc32) sz_part32 = sz_drv32 - nxt_alloc32; /* Clip at drive size */ if (sz_part32 == 0) break; /* End of table or no sector to allocate? */ - st_dword(pte + PTE_StLba, nxt_alloc32); /* Start LBA */ - st_dword(pte + PTE_SizLba, sz_part32); /* Number of sectors */ + st_32(pte + PTE_StLba, nxt_alloc32); /* Partition start LBA sector */ + st_32(pte + PTE_SizLba, sz_part32); /* Size of partition [sector] */ pte[PTE_System] = sys; /* System type */ - cy = (UINT)(nxt_alloc32 / n_sc / n_hd); /* Start cylinder */ - hd = (BYTE)(nxt_alloc32 / n_sc % n_hd); /* Start head */ - sc = (BYTE)(nxt_alloc32 % n_sc + 1); /* Start sector */ + cy = (UINT)(nxt_alloc32 / n_sc / n_hd); /* Partitio start CHS cylinder */ + hd = (BYTE)(nxt_alloc32 / n_sc % n_hd); /* Partition start CHS head */ + sc = (BYTE)(nxt_alloc32 % n_sc + 1); /* Partition start CHS sector */ pte[PTE_StHead] = hd; pte[PTE_StSec] = (BYTE)((cy >> 2 & 0xC0) | sc); pte[PTE_StCyl] = (BYTE)cy; - cy = (UINT)((nxt_alloc32 + sz_part32 - 1) / n_sc / n_hd); /* End cylinder */ - hd = (BYTE)((nxt_alloc32 + sz_part32 - 1) / n_sc % n_hd); /* End head */ - sc = (BYTE)((nxt_alloc32 + sz_part32 - 1) % n_sc + 1); /* End sector */ + cy = (UINT)((nxt_alloc32 + sz_part32 - 1) / n_sc / n_hd); /* Partition end CHS cylinder */ + hd = (BYTE)((nxt_alloc32 + sz_part32 - 1) / n_sc % n_hd); /* Partition end CHS head */ + sc = (BYTE)((nxt_alloc32 + sz_part32 - 1) % n_sc + 1); /* Partition end CHS sector */ pte[PTE_EdHead] = hd; pte[PTE_EdSec] = (BYTE)((cy >> 2 & 0xC0) | sc); pte[PTE_EdCyl] = (BYTE)cy; @@ -5887,7 +6048,7 @@ static FRESULT create_partition ( pte += SZ_PTE; /* Next entry */ } - st_word(buf + BS_55AA, 0xAA55); /* MBR signature */ + st_16(buf + BS_55AA, 0xAA55); /* MBR signature */ if (disk_write(drv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; /* Write it to the MBR */ } @@ -5903,25 +6064,25 @@ FRESULT f_mkfs ( UINT len /* Size of working buffer [byte] */ ) { - 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) */ + static const WORD cst[] = {1, 4, 16, 64, 256, 512, 0}; /* Cluster size boundary for FAT volume (4K sector unit) */ + static const WORD cst32[] = {1, 2, 4, 8, 16, 32, 0}; /* Cluster size boundary for FAT32 volume (128K sector unit) */ static const MKFS_PARM defopt = {FM_ANY, 0, 0, 0, 0}; /* Default parameter */ BYTE fsopt, fsty, sys, pdrv, ipart; BYTE *buf; BYTE *pte; WORD ss; /* Sector size */ DWORD sz_buf, sz_blk, n_clst, pau, nsect, n, vsn; - LBA_t sz_vol, b_vol, b_fat, b_data; /* Size of volume, Base LBA of volume, fat, data */ + LBA_t sz_vol, b_vol, b_fat, b_data; /* Volume size, base LBA of volume, base LBA of FAT and base LBA of 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 */ + DWORD sz_rsv, sz_fat, sz_dir, sz_au; /* Size of reserved area, FAT area, directry area, data area and cluster */ + UINT n_fat, n_root, i; /* Number of FATs, number of roor directory entries and some index */ int vol; DSTATUS ds; FRESULT res; /* Check mounted drive and clear work area */ - vol = get_ldnumber(&path); /* Get target logical drive */ + vol = get_ldnumber(&path); /* Get logical drive number to be formatted */ if (vol < 0) return FR_INVALID_DRIVE; if (FatFs[vol]) FatFs[vol]->fs_type = 0; /* Clear the fs object if mounted */ pdrv = LD2PD(vol); /* Hosting physical drive */ @@ -5935,7 +6096,7 @@ FRESULT f_mkfs ( /* Get physical drive parameters (sz_drv, sz_blk and ss) */ if (!opt) opt = &defopt; /* Use default parameter if it is not given */ sz_blk = opt->align; - if (sz_blk == 0) disk_ioctl(pdrv, GET_BLOCK_SIZE, &sz_blk); /* Block size from the paramter or lower layer */ + if (sz_blk == 0) disk_ioctl(pdrv, GET_BLOCK_SIZE, &sz_blk); /* Block size from the parameter or lower layer */ if (sz_blk == 0 || sz_blk > 0x8000 || (sz_blk & (sz_blk - 1))) sz_blk = 1; /* Use default if the block size is invalid */ #if FF_MAX_SS != FF_MIN_SS if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &ss) != RES_OK) return FR_DISK_ERR; @@ -5965,7 +6126,7 @@ FRESULT f_mkfs ( 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 */ + if (ld_16(buf + BS_55AA) != 0xAA55) LEAVE_MKFS(FR_MKFS_ABORTED); /* Check if MBR is valid */ #if FF_LBA64 if (buf[MBR_Table + PTE_System] == 0xEE) { /* GPT protective MBR? */ DWORD n_ent, ofs; @@ -5974,14 +6135,14 @@ FRESULT f_mkfs ( /* 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 */ + n_ent = ld_32(buf + GPTH_PtNum); /* Number of entries */ + pt_lba = ld_64(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 (!memcmp(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; + b_vol = ld_64(buf + ofs + GPTE_FstLba); + sz_vol = ld_64(buf + ofs + GPTE_LstLba) - b_vol + 1; break; } n_ent--; ofs = (ofs + SZ_GPTE) % ss; /* Next entry */ @@ -5993,8 +6154,8 @@ FRESULT f_mkfs ( { /* 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 */ + b_vol = ld_32(pte + PTE_StLba); /* Get volume start sector */ + sz_vol = ld_32(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); @@ -6013,13 +6174,13 @@ FRESULT f_mkfs ( } } } - if (sz_vol < 128) LEAVE_MKFS(FR_MKFS_ABORTED); /* Check if volume size is >=128s */ + if (sz_vol < 128) LEAVE_MKFS(FR_MKFS_ABORTED); /* Check if volume size is >=128 sectors */ /* Now start to create an 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 ? */ + if ((fsopt & FM_ANY) == FM_EXFAT || sz_vol >= 0x4000000 || sz_au > 128) { /* exFAT only, vol >= 64M sectors or sz_au > 128 sectors? */ fsty = FS_EXFAT; break; } } @@ -6036,7 +6197,7 @@ FRESULT f_mkfs ( fsty = FS_FAT16; } while (0); - vsn = (DWORD)sz_vol + GET_FATTIME(); /* VSN generated from current time and partitiion size */ + vsn = (DWORD)sz_vol + GET_FATTIME(); /* VSN generated from current time and partition size */ #if FF_FS_EXFAT if (fsty == FS_EXFAT) { /* Create an exFAT volume */ @@ -6102,7 +6263,7 @@ FRESULT f_mkfs ( } } while (si); clen[1] = (szb_case + sz_au * ss - 1) / (sz_au * ss); /* Number of up-case table clusters */ - clen[2] = 1; /* Number of root dir clusters */ + clen[2] = 1; /* Number of root directory clusters */ /* Initialize the allocation bitmap */ sect = b_data; nsect = (szb_bit + ss - 1) / ss; /* Start of bitmap and number of bitmap sectors */ @@ -6121,12 +6282,13 @@ FRESULT f_mkfs ( do { memset(buf, 0, sz_buf * ss); i = 0; /* Clear work area and reset write offset */ if (clu == 0) { /* Initialize FAT [0] and FAT[1] */ - st_dword(buf + i, 0xFFFFFFF8); i += 4; clu++; - st_dword(buf + i, 0xFFFFFFFF); i += 4; clu++; + st_32(buf + i, 0xFFFFFFF8); i += 4; clu++; + st_32(buf + i, 0xFFFFFFFF); i += 4; clu++; } - do { /* Create chains of bitmap, up-case and root dir */ + + do { /* Create chains of bitmap, up-case and root directory */ while (nbit != 0 && i < sz_buf * ss) { /* Create a chain */ - st_dword(buf + i, (nbit > 1) ? clu + 1 : 0xFFFFFFFF); + st_32(buf + i, (nbit > 1) ? clu + 1 : 0xFFFFFFFF); i += 4; clu++; nbit--; } if (nbit == 0 && j < 3) nbit = clen[j++]; /* Get next chain length */ @@ -6138,14 +6300,14 @@ FRESULT f_mkfs ( /* Initialize the root directory */ memset(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 + clen[0]); /* cluster */ - st_dword(buf + SZDIRE * 2 + 24, szb_case); /* size */ + buf[SZDIRE * 0 + 0] = ET_VLABEL; /* Volume label entry (no label) */ + buf[SZDIRE * 1 + 0] = ET_BITMAP; /* Bitmap entry */ + st_32(buf + SZDIRE * 1 + 20, 2); /* cluster */ + st_32(buf + SZDIRE * 1 + 24, szb_bit); /* size */ + buf[SZDIRE * 2 + 0] = ET_UPCASE; /* Up-case table entry */ + st_32(buf + SZDIRE * 2 + 4, sum); /* sum */ + st_32(buf + SZDIRE * 2 + 20, 2 + clen[0]); /* cluster */ + st_32(buf + SZDIRE * 2 + 24, szb_case); /* size */ sect = b_data + sz_au * (clen[0] + clen[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; @@ -6160,28 +6322,28 @@ FRESULT f_mkfs ( /* Main record (+0) */ memset(buf, 0, ss); memcpy(buf + BS_JmpBoot, "\xEB\x76\x90" "EXFAT ", 11); /* Boot jump code (x86), OEM name */ - 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, (DWORD)(b_data - b_vol)); /* Data offset [sector] */ - st_dword(buf + BPB_NumClusEx, n_clst); /* Number of clusters */ - st_dword(buf + BPB_RootClusEx, 2 + clen[0] + clen[1]); /* Root dir cluster # */ - st_dword(buf + BPB_VolIDEx, vsn); /* 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] */ + st_64(buf + BPB_VolOfsEx, b_vol); /* Volume offset in the physical drive [sector] */ + st_64(buf + BPB_TotSecEx, sz_vol); /* Volume size [sector] */ + st_32(buf + BPB_FatOfsEx, (DWORD)(b_fat - b_vol)); /* FAT offset [sector] */ + st_32(buf + BPB_FatSzEx, sz_fat); /* FAT size [sector] */ + st_32(buf + BPB_DataOfsEx, (DWORD)(b_data - b_vol)); /* Data offset [sector] */ + st_32(buf + BPB_NumClusEx, n_clst); /* Number of clusters */ + st_32(buf + BPB_RootClusEx, 2 + clen[0] + clen[1]); /* Root directory cluster number */ + st_32(buf + BPB_VolIDEx, vsn); /* VSN */ + st_16(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 = 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) */ - st_word(buf + BS_55AA, 0xAA55); /* Signature (placed here regardless of sector size) */ + st_16(buf + BS_BootCodeEx, 0xFEEB); /* Boot code (x86) */ + st_16(buf + BS_55AA, 0xAA55); /* Signature (placed here regardless of sector size) */ for (i = sum = 0; i < ss; i++) { /* VBR checksum */ if (i != BPB_VolFlagEx && i != BPB_VolFlagEx + 1 && i != BPB_PercInUseEx) sum = xsum32(buf[i], sum); } if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Extended bootstrap record (+1..+8) */ memset(buf, 0, ss); - st_word(buf + ss - 2, 0xAA55); /* Signature (placed at end of sector) */ + st_16(buf + ss - 2, 0xAA55); /* Signature (placed at end of sector) */ for (j = 1; j < 9; j++) { for (i = 0; i < ss; sum = xsum32(buf[i++], sum)) ; /* VBR checksum */ if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); @@ -6193,7 +6355,7 @@ FRESULT f_mkfs ( if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); } /* Sum record (+11) */ - for (i = 0; i < ss; i += 4) st_dword(buf + i, sum); /* Fill with checksum value */ + for (i = 0; i < ss; i += 4) st_32(buf + i, sum); /* Fill with checksum value */ if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); } @@ -6227,7 +6389,7 @@ FRESULT f_mkfs ( } sz_fat = (n + ss - 1) / ss; /* FAT size [sector] */ sz_rsv = 1; /* Number of reserved sectors */ - sz_dir = (DWORD)n_root * SZDIRE / ss; /* Root dir size [sector] */ + sz_dir = (DWORD)n_root * SZDIRE / ss; /* Root directory size [sector] */ } b_fat = b_vol + sz_rsv; /* FAT base */ b_data = b_fat + sz_fat * n_fat + sz_dir; /* Data base */ @@ -6281,48 +6443,48 @@ FRESULT f_mkfs ( /* Create FAT VBR */ memset(buf, 0, ss); memcpy(buf + BS_JmpBoot, "\xEB\xFE\x90" "MSDOS5.0", 11); /* Boot jump code (x86), OEM name */ - st_word(buf + BPB_BytsPerSec, ss); /* Sector size [byte] */ + st_16(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 */ + st_16(buf + BPB_RsvdSecCnt, (WORD)sz_rsv); /* Size of reserved area */ 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 */ + st_16(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 */ + st_16(buf + BPB_TotSec16, (WORD)sz_vol); /* Volume size in 16-bit LBA */ } else { - st_dword(buf + BPB_TotSec32, (DWORD)sz_vol); /* Volume size in 32-bit LBA */ + st_32(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, (DWORD)b_vol); /* Volume offset in the physical drive [sector] */ + st_16(buf + BPB_SecPerTrk, 63); /* Number of sectors per track (for int13) */ + st_16(buf + BPB_NumHeads, 255); /* Number of heads (for int13) */ + st_32(buf + BPB_HiddSec, (DWORD)b_vol); /* Volume offset in the physical drive [sector] */ if (fsty == FS_FAT32) { - st_dword(buf + BS_VolID32, vsn); /* VSN */ - st_dword(buf + BPB_FATSz32, sz_fat); /* FAT size [sector] */ - st_dword(buf + BPB_RootClus32, 2); /* Root directory cluster # (2) */ - st_word(buf + BPB_FSInfo32, 1); /* Offset of FSINFO sector (VBR + 1) */ - st_word(buf + BPB_BkBootSec32, 6); /* Offset of backup VBR (VBR + 6) */ + st_32(buf + BS_VolID32, vsn); /* VSN */ + st_32(buf + BPB_FATSz32, sz_fat); /* FAT size [sector] */ + st_32(buf + BPB_RootClus32, 2); /* Root directory cluster # (2) */ + st_16(buf + BPB_FSInfo32, 1); /* Offset of FSINFO sector (VBR + 1) */ + st_16(buf + BPB_BkBootSec32, 6); /* Offset of backup VBR (VBR + 6) */ buf[BS_DrvNum32] = 0x80; /* Drive number (for int13) */ buf[BS_BootSig32] = 0x29; /* Extended boot signature */ memcpy(buf + BS_VolLab32, "NO NAME " "FAT32 ", 19); /* Volume label, FAT signature */ } else { - st_dword(buf + BS_VolID, vsn); /* VSN */ - st_word(buf + BPB_FATSz16, (WORD)sz_fat); /* FAT size [sector] */ + st_32(buf + BS_VolID, vsn); /* VSN */ + st_16(buf + BPB_FATSz16, (WORD)sz_fat); /* FAT size [sector] */ buf[BS_DrvNum] = 0x80; /* Drive number (for int13) */ buf[BS_BootSig] = 0x29; /* Extended boot signature */ memcpy(buf + BS_VolLab, "NO NAME " "FAT ", 19); /* Volume label, FAT signature */ } - st_word(buf + BS_55AA, 0xAA55); /* Signature (offset is fixed here regardless of sector size) */ + st_16(buf + BS_55AA, 0xAA55); /* Signature (offset is fixed here regardless of sector size) */ 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 (fsty == FS_FAT32) { disk_write(pdrv, buf, b_vol + 6, 1); /* Write backup VBR (VBR + 6) */ memset(buf, 0, ss); - st_dword(buf + FSI_LeadSig, 0x41615252); - st_dword(buf + FSI_StrucSig, 0x61417272); - st_dword(buf + FSI_Free_Count, n_clst - 1); /* Number of free clusters */ - st_dword(buf + FSI_Nxt_Free, 2); /* Last allocated cluster# */ - st_word(buf + BS_55AA, 0xAA55); + st_32(buf + FSI_LeadSig, 0x41615252); + st_32(buf + FSI_StrucSig, 0x61417272); + st_32(buf + FSI_Free_Count, n_clst - 1); /* Number of free clusters */ + st_32(buf + FSI_Nxt_Free, 2); /* Last allocated cluster# */ + st_16(buf + BS_55AA, 0xAA55); disk_write(pdrv, buf, b_vol + 7, 1); /* Write backup FSINFO (VBR + 7) */ disk_write(pdrv, buf, b_vol + 1, 1); /* Write original FSINFO (VBR + 1) */ } @@ -6332,17 +6494,17 @@ FRESULT f_mkfs ( sect = b_fat; /* FAT start sector */ 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) */ + st_32(buf + 0, 0xFFFFFFF8); /* FAT[0] */ + st_32(buf + 4, 0xFFFFFFFF); /* FAT[1] */ + st_32(buf + 8, 0x0FFFFFFF); /* FAT[2] (root directory at cluster# 2) */ } else { - st_dword(buf + 0, (fsty == FS_FAT12) ? 0xFFFFF8 : 0xFFFFFFF8); /* FAT[0] and FAT[1] */ + st_32(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); - memset(buf, 0, ss); /* Rest of FAT all are cleared */ + memset(buf, 0, ss); /* Rest of FAT area is initially zero */ sect += n; nsect -= n; } while (nsect); } @@ -6397,7 +6559,7 @@ FRESULT f_mkfs ( #if FF_MULTI_PARTITION /*-----------------------------------------------------------------------*/ -/* Create Partition Table on the Physical Drive */ +/* API: Create Partition Table on the Physical Drive */ /*-----------------------------------------------------------------------*/ FRESULT f_fdisk ( @@ -6437,7 +6599,7 @@ FRESULT f_fdisk ( #error Wrong FF_STRF_ENCODE setting #endif /*-----------------------------------------------------------------------*/ -/* Get a String from the File */ +/* API: Get a String from the File */ /*-----------------------------------------------------------------------*/ TCHAR* f_gets ( @@ -6478,12 +6640,12 @@ TCHAR* f_gets ( #elif FF_STRF_ENCODE == 1 || FF_STRF_ENCODE == 2 /* Read a character in UTF-16LE/BE */ 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]; + dc = (FF_STRF_ENCODE == 1) ? ld_16(s) : s[0] << 8 | s[1]; 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]; + wc = (FF_STRF_ENCODE == 1) ? ld_16(s) : s[0] << 8 | s[1]; if (!IsSurrogateL(wc)) continue; /* Broken surrogate pair? */ dc = ((dc & 0x3FF) + 0x40) << 10 | (wc & 0x3FF); /* Merge surrogate pair */ } @@ -6513,7 +6675,7 @@ TCHAR* f_gets ( if (rc != ct || dc < 0x80 || IsSurrogate(dc) || dc >= 0x110000) continue; /* Wrong encoding? */ } #endif - /* A code point is avaialble in dc to be output */ + /* A code point is available 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 */ @@ -6572,14 +6734,14 @@ TCHAR* f_gets ( #define SZ_NUM_BUF 32 /*-----------------------------------------------------------------------*/ -/* Put a Character to the File (with sub-functions) */ +/* API: Put a Character to the File (with sub-functions) */ /*-----------------------------------------------------------------------*/ /* 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 */ + FIL *fp; /* Pointer to the writing file */ + int idx, nchr; /* Write index of buf[] (-1:error), number of written encoding units */ #if FF_USE_LFN && FF_LFN_UNICODE == 1 WCHAR hs; #elif FF_USE_LFN && FF_LFN_UNICODE == 2 @@ -6619,23 +6781,23 @@ static void putc_bfd (putbuff* pb, TCHAR c) } hs = pb->hs; pb->hs = 0; if (hs != 0) { /* Is there a leading high-surrogate? */ - if (!IsSurrogateL(c)) hs = 0; /* Discard high-surrogate if not a surrogate pair */ + if (!IsSurrogateL(c)) hs = 0; /* Discard high-surrogate if a stray high-surrogate */ } else { 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? */ + if (pb->ct == 0) { /* Not in the multi-byte sequence? */ pb->bs[pb->wi = 0] = (BYTE)c; /* Save 1st byte */ if ((BYTE)c < 0x80) break; /* Single byte code? */ 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 & 0xF8) == 0xF0) pb->ct = 3; /* 4-byte sequence? */ - return; /* Wrong leading byte (discard it) */ + return; /* Invalid leading byte (discard it) */ } else { /* In the multi-byte sequence */ if (((BYTE)c & 0xC0) != 0x80) { /* Broken sequence? */ - pb->ct = 0; continue; /* Discard the sequense */ + pb->ct = 0; continue; /* Discard the sequence */ } pb->bs[++pb->wi] = (BYTE)c; /* Save the trailing byte */ if (--pb->ct == 0) break; /* End of the sequence? */ @@ -6661,11 +6823,11 @@ static void putc_bfd (putbuff* pb, TCHAR c) #if FF_STRF_ENCODE == 1 /* Write a code point in UTF-16LE */ if (hs != 0) { /* Surrogate pair? */ - st_word(&pb->buf[i], hs); + st_16(&pb->buf[i], hs); i += 2; nc++; } - st_word(&pb->buf[i], wc); + st_16(&pb->buf[i], wc); i += 2; #elif FF_STRF_ENCODE == 2 /* Write a code point in UTF-16BE */ if (hs != 0) { /* Surrogate pair? */ @@ -6721,7 +6883,7 @@ static void putc_bfd (putbuff* pb, TCHAR c) } -/* Flush remaining characters in the buffer */ +/* Flush characters left in the buffer and return number of characters written */ static int putc_flush (putbuff* pb) { @@ -6729,7 +6891,9 @@ static int putc_flush (putbuff* pb) if ( pb->idx >= 0 /* Flush buffered characters to the file */ && f_write(pb->fp, pb->buf, (UINT)pb->idx, &nw) == FR_OK - && (UINT)pb->idx == nw) return pb->nchr; + && (UINT)pb->idx == nw) { + return pb->nchr; + } return -1; } @@ -6761,7 +6925,7 @@ int f_putc ( /*-----------------------------------------------------------------------*/ -/* Put a String to the File */ +/* API: Put a String to the File */ /*-----------------------------------------------------------------------*/ int f_puts ( @@ -6781,7 +6945,7 @@ int f_puts ( /*-----------------------------------------------------------------------*/ -/* Put a Formatted String to the File (with sub-functions) */ +/* API: Put a Formatted String to the File (with sub-functions) */ /*-----------------------------------------------------------------------*/ #if FF_PRINT_FLOAT && FF_INTDEF == 2 #include @@ -6837,8 +7001,8 @@ static void ftoa ( TCHAR fmt /* Notation */ ) { - int d; - int e = 0, m = 0; + int digit; + int exp = 0, mag = 0; char sign = 0; double w; const char *er = 0; @@ -6859,18 +7023,18 @@ static void ftoa ( } else { if (fmt == 'f') { /* Decimal notation? */ val += i10x(0 - prec) / 2; /* Round (nearest) */ - m = ilog10(val); - if (m < 0) m = 0; - if (m + prec + 3 >= SZ_NUM_BUF) er = "OV"; /* Buffer overflow? */ + mag = ilog10(val); + if (mag < 0) mag = 0; + if (mag + prec + 3 >= SZ_NUM_BUF) er = "OV"; /* Buffer overflow? */ } else { /* E notation */ if (val != 0) { /* Not a true zero? */ val += i10x(ilog10(val) - prec) / 2; /* Round (nearest) */ - e = ilog10(val); - if (e > 99 || prec + 7 >= SZ_NUM_BUF) { /* Buffer overflow or E > +99? */ + exp = ilog10(val); + if (exp > 99 || prec + 7 >= SZ_NUM_BUF) { /* Buffer overflow or E > +99? */ er = "OV"; } else { - if (e < -99) e = -99; - val /= i10x(e); /* Normalize */ + if (exp < -99) exp = -99; + val /= i10x(exp); /* Normalize */ } } } @@ -6878,20 +7042,20 @@ static void ftoa ( if (!er) { /* Not error condition */ if (sign == '-') *buf++ = sign; /* Add a - if negative value */ do { /* Put decimal number */ - if (m == -1) *buf++ = ds; /* Insert a decimal separator when get into fractional part */ - w = i10x(m); /* Snip the highest digit d */ - d = (int)(val / w); val -= d * w; - *buf++ = (char)('0' + d); /* Put the digit */ - } while (--m >= -prec); /* Output all digits specified by prec */ + if (mag == -1) *buf++ = ds; /* Insert a decimal separator when get into fractional part */ + w = i10x(mag); /* Snip the highest digit d */ + digit = (int)(val / w); val -= digit * w; + *buf++ = (char)('0' + digit); /* Put the digit */ + } while (--mag >= -prec); /* Output all digits specified by prec */ if (fmt != 'f') { /* Put exponent if needed */ *buf++ = (char)fmt; - if (e < 0) { - e = 0 - e; *buf++ = '-'; + if (exp < 0) { + exp = 0 - exp; *buf++ = '-'; } else { *buf++ = '+'; } - *buf++ = (char)('0' + e / 10); - *buf++ = (char)('0' + e % 10); + *buf++ = (char)('0' + exp / 10); + *buf++ = (char)('0' + exp % 10); } } } @@ -6915,17 +7079,17 @@ int f_printf ( { va_list arp; putbuff pb; - UINT i, j, w, f, r; + UINT i, j, width, flag, radix; int prec; #if FF_PRINT_LLI && FF_INTDEF == 2 - QWORD v; + QWORD val; #else - DWORD v; + DWORD val; #endif TCHAR *tp; - TCHAR tc, pad; + TCHAR chr, pad; TCHAR nul = 0; - char d, str[SZ_NUM_BUF]; + char digit, str[SZ_NUM_BUF]; putc_init(&pb, fp); @@ -6933,64 +7097,64 @@ int f_printf ( va_start(arp, fmt); for (;;) { - tc = *fmt++; - if (tc == 0) break; /* End of format string */ - if (tc != '%') { /* Not an escape character (pass-through) */ - putc_bfd(&pb, tc); + chr = *fmt++; + if (chr == 0) break; /* End of format string */ + if (chr != '%') { /* Not an escape character (pass-through) */ + putc_bfd(&pb, chr); continue; } - f = w = 0; pad = ' '; prec = -1; /* Initialize parms */ - tc = *fmt++; - if (tc == '0') { /* Flag: '0' padded */ - pad = '0'; tc = *fmt++; - } else if (tc == '-') { /* Flag: Left aligned */ - f = 2; tc = *fmt++; + flag = width = 0; pad = ' '; prec = -1; /* Initialize the parameters */ + chr = *fmt++; + if (chr == '0') { /* Flag: '0' padded */ + pad = '0'; chr = *fmt++; + } else if (chr == '-') { /* Flag: Left aligned */ + flag = 2; chr = *fmt++; } - if (tc == '*') { /* Minimum width from an argument */ - w = va_arg(arp, int); - tc = *fmt++; + if (chr == '*') { /* Minimum width from an argument */ + width = (UINT)va_arg(arp, int); + chr = *fmt++; } else { - while (IsDigit(tc)) { /* Minimum width */ - w = w * 10 + tc - '0'; - tc = *fmt++; + while (IsDigit(chr)) { /* Minimum width */ + width = width * 10 + chr - '0'; + chr = *fmt++; } } - if (tc == '.') { /* Precision */ - tc = *fmt++; - if (tc == '*') { /* Precision from an argument */ + if (chr == '.') { /* Precision */ + chr = *fmt++; + if (chr == '*') { /* Precision from an argument */ prec = va_arg(arp, int); - tc = *fmt++; + chr = *fmt++; } else { prec = 0; - while (IsDigit(tc)) { /* Precision */ - prec = prec * 10 + tc - '0'; - tc = *fmt++; + while (IsDigit(chr)) { /* Precision */ + prec = prec * 10 + chr - '0'; + chr = *fmt++; } } } - if (tc == 'l') { /* Size: long int */ - f |= 4; tc = *fmt++; + if (chr == 'l') { /* Size: long int */ + flag |= 4; chr = *fmt++; #if FF_PRINT_LLI && FF_INTDEF == 2 - if (tc == 'l') { /* Size: long long int */ - f |= 8; tc = *fmt++; + if (chr == 'l') { /* Size: long long int */ + flag |= 8; chr = *fmt++; } #endif } - if (tc == 0) break; /* End of format string */ - switch (tc) { /* Atgument type is... */ + if (chr == 0) break; /* End of format string */ + switch (chr) { /* Atgument type is... */ case 'b': /* Unsigned binary */ - r = 2; break; + radix = 2; break; case 'o': /* Unsigned octal */ - r = 8; break; + radix = 8; break; case 'd': /* Signed decimal */ case 'u': /* Unsigned decimal */ - r = 10; break; + radix = 10; break; case 'x': /* Unsigned hexadecimal (lower case) */ case 'X': /* Unsigned hexadecimal (upper case) */ - r = 16; break; + radix = 16; break; case 'c': /* Character */ putc_bfd(&pb, (TCHAR)va_arg(arp, int)); @@ -6998,64 +7162,65 @@ int f_printf ( case 's': /* String */ tp = va_arg(arp, TCHAR*); /* Get a pointer argument */ - if (!tp) tp = &nul; /* Null ptr generates a null string */ + if (!tp) tp = &nul; /* Null pointer generates a null string */ for (j = 0; tp[j]; j++) ; /* j = tcslen(tp) */ - if (prec >= 0 && j > (UINT)prec) j = prec; /* Limited length of string body */ - for ( ; !(f & 2) && j < w; j++) putc_bfd(&pb, pad); /* Left pads */ - while (*tp && prec--) putc_bfd(&pb, *tp++); /* Body */ - while (j++ < w) putc_bfd(&pb, ' '); /* Right pads */ + if (prec >= 0 && j > (UINT)prec) j = (UINT)prec; /* Limited length of string body */ + for ( ; !(flag & 2) && j < width; j++) putc_bfd(&pb, pad); /* Left padding */ + while (*tp && prec--) putc_bfd(&pb, *tp++); /* Body */ + while (j++ < width) putc_bfd(&pb, ' '); /* Right padding */ continue; #if FF_PRINT_FLOAT && FF_INTDEF == 2 case 'f': /* Floating point (decimal) */ case 'e': /* Floating point (e) */ case 'E': /* Floating point (E) */ - ftoa(str, va_arg(arp, double), prec, tc); /* Make a floating point string */ - for (j = strlen(str); !(f & 2) && j < w; j++) putc_bfd(&pb, pad); /* Left pads */ + ftoa(str, va_arg(arp, double), prec, chr); /* Make a floating point string */ + for (j = strlen(str); !(flag & 2) && j < width; j++) putc_bfd(&pb, pad); /* Leading pads */ for (i = 0; str[i]; putc_bfd(&pb, str[i++])) ; /* Body */ - while (j++ < w) putc_bfd(&pb, ' '); /* Right pads */ + while (j++ < width) putc_bfd(&pb, ' '); /* Trailing pads */ continue; #endif default: /* Unknown type (pass-through) */ - putc_bfd(&pb, tc); continue; + putc_bfd(&pb, chr); + continue; } /* Get an integer argument and put it in numeral */ #if FF_PRINT_LLI && FF_INTDEF == 2 - if (f & 8) { /* long long argument? */ - v = (QWORD)va_arg(arp, long long); - } else if (f & 4) { /* long argument? */ - v = (tc == 'd') ? (QWORD)(long long)va_arg(arp, long) : (QWORD)va_arg(arp, unsigned long); + if (flag & 8) { /* long long argument? */ + val = (QWORD)va_arg(arp, long long); + } else if (flag & 4) { /* long argument? */ + val = (chr == 'd') ? (QWORD)(long long)va_arg(arp, long) : (QWORD)va_arg(arp, unsigned long); } else { /* int/short/char argument */ - v = (tc == 'd') ? (QWORD)(long long)va_arg(arp, int) : (QWORD)va_arg(arp, unsigned int); + val = (chr == 'd') ? (QWORD)(long long)va_arg(arp, int) : (QWORD)va_arg(arp, unsigned int); } - if (tc == 'd' && (v & 0x8000000000000000)) { /* Negative value? */ - v = 0 - v; f |= 1; + if (chr == 'd' && (val & 0x8000000000000000)) { /* Negative value? */ + val = 0 - val; flag |= 1; } #else - if (f & 4) { /* long argument? */ - v = (DWORD)va_arg(arp, long); + if (flag & 4) { /* long argument? */ + val = (DWORD)va_arg(arp, long); } else { /* int/short/char argument */ - v = (tc == 'd') ? (DWORD)(long)va_arg(arp, int) : (DWORD)va_arg(arp, unsigned int); + val = (chr == 'd') ? (DWORD)(long)va_arg(arp, int) : (DWORD)va_arg(arp, unsigned int); } - if (tc == 'd' && (v & 0x80000000)) { /* Negative value? */ - v = 0 - v; f |= 1; + if (chr == 'd' && (val & 0x80000000)) { /* Negative value? */ + val = 0 - val; flag |= 1; } #endif i = 0; do { /* Make an integer number string */ - d = (char)(v % r); v /= r; - if (d > 9) d += (tc == 'x') ? 0x27 : 0x07; - str[i++] = d + '0'; - } while (v && i < SZ_NUM_BUF); - if (f & 1) str[i++] = '-'; /* Sign */ + digit = (char)(val % radix) + '0'; val /= radix; + if (digit > '9') digit += (chr == 'x') ? 0x27 : 0x07; + str[i++] = digit; + } while (val && i < SZ_NUM_BUF); + if (flag & 1) str[i++] = '-'; /* Sign */ /* Write it */ - for (j = i; !(f & 2) && j < w; j++) { /* Left pads */ + for (j = i; !(flag & 2) && j < width; j++) { /* Leading pads */ putc_bfd(&pb, pad); } - do { /* Body */ + do { /* Body */ putc_bfd(&pb, (TCHAR)str[--i]); } while (i); - while (j++ < w) { /* Right pads */ + while (j++ < width) { /* Trailing pads */ putc_bfd(&pb, ' '); } } @@ -7072,7 +7237,7 @@ int f_printf ( #if FF_CODE_PAGE == 0 /*-----------------------------------------------------------------------*/ -/* Set Active Codepage for the Path Name */ +/* API: Set Active Codepage for the Path Name */ /*-----------------------------------------------------------------------*/ FRESULT f_setcp ( @@ -7114,3 +7279,4 @@ int elm_get_vol(FATFS *fat) } #endif + diff --git a/components/dfs/dfs_v2/filesystems/elmfat/ff.h b/components/dfs/dfs_v2/filesystems/elmfat/ff.h index b01385e9816..fed69af5d6f 100644 --- a/components/dfs/dfs_v2/filesystems/elmfat/ff.h +++ b/components/dfs/dfs_v2/filesystems/elmfat/ff.h @@ -1,8 +1,8 @@ /*----------------------------------------------------------------------------/ -/ FatFs - Generic FAT Filesystem module R0.15 / +/ FatFs - Generic FAT Filesystem module R0.16 / /-----------------------------------------------------------------------------/ / -/ Copyright (C) 2022, ChaN, all right reserved. +/ Copyright (C) 2025, 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,15 +20,16 @@ #ifndef FF_DEFINED -#define FF_DEFINED 80286 /* Revision ID */ +#define FF_DEFINED 80386 /* Revision ID */ #ifdef __cplusplus extern "C" { #endif #include +#if !defined(FFCONF_DEF) #include "ffconf.h" /* FatFs configuration options */ - +#endif #if FF_DEFINED != FFCONF_DEF #error Wrong configuration file (ffconf.h). #endif @@ -49,18 +50,18 @@ typedef unsigned __int64 QWORD; #include 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 uint32_t DWORD; /* 32-bit unsigned integer */ -typedef uint64_t QWORD; /* 64-bit unsigned integer */ -typedef WORD WCHAR; /* UTF-16 character type */ +typedef uint16_t WORD; /* 16-bit unsigned */ +typedef uint32_t DWORD; /* 32-bit unsigned */ +typedef uint64_t QWORD; /* 64-bit unsigned */ +typedef WORD WCHAR; /* UTF-16 code unit */ #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 long DWORD; /* 32-bit unsigned integer */ -typedef WORD WCHAR; /* UTF-16 character type */ +typedef unsigned short WORD; /* short must be 16-bit */ +typedef unsigned long DWORD; /* long must be 32-bit */ +typedef WORD WCHAR; /* UTF-16 code unit */ #endif @@ -114,64 +115,78 @@ typedef char TCHAR; #if FF_MULTI_PARTITION /* Multiple partition configuration */ typedef struct { - BYTE pd; /* Physical drive number */ - BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */ + BYTE pd; /* Associated physical drive */ + BYTE pt; /* Associated partition (0:Auto detect, 1-4:Forced partition) */ } PARTITION; -extern PARTITION VolToPart[]; /* Volume - Partition mapping table */ +extern PARTITION VolToPart[]; /* Volume to partition mapping table */ #endif #if FF_STR_VOLUME_ID #ifndef FF_VOLUME_STRS -extern const char* VolumeStr[FF_VOLUMES]; /* User defied volume ID */ +extern const char* VolumeStr[FF_VOLUMES]; /* User defined volume ID table */ #endif #endif +/* Current working directory structure (FFXCWDS) */ + +#if FF_FS_EXFAT && FF_FS_RPATH +#if FF_PATH_DEPTH < 1 +#error FF_PATH_DEPTH must not be zero +#endif +typedef struct { + DWORD d_scl; /* Directory start cluster (0:root dir) */ + DWORD d_size; /* Size of directory (b7-b0: cluster chain status) (invalid if d_scl == 0) */ + DWORD nxt_ofs; /* Offset of entry of next dir in this directory (invalid if last link) */ +} FFXCWDL; +typedef struct { + UINT depth; /* Current directory depth (0:root dir) */ + FFXCWDL tbl[FF_PATH_DEPTH + 1]; /* Directory chain of current working directory path */ +} FFXCWDS; +#endif + /* Filesystem object structure (FATFS) */ typedef struct { - BYTE fs_type; /* Filesystem type (0:not mounted) */ - BYTE pdrv; /* Volume hosting physical drive */ - BYTE ldrv; /* Logical drive number (used only when FF_FS_REENTRANT) */ - BYTE n_fats; /* Number of FATs (1 or 2) */ - BYTE wflag; /* win[] status (b0:dirty) */ - BYTE fsi_flag; /* FSINFO status (b7:disabled, b0:dirty) */ - WORD id; /* Volume mount ID */ - WORD n_rootdir; /* Number of root directory entries (FAT12/16) */ - WORD csize; /* Cluster size [sectors] */ + BYTE fs_type; /* Filesystem type (0:not mounted) */ + BYTE pdrv; /* Physical drive that holds this volume */ + BYTE ldrv; /* Logical drive number (used only when FF_FS_REENTRANT) */ + BYTE n_fats; /* Number of FATs (1 or 2) */ + BYTE wflag; /* win[] status (b0:dirty) */ + BYTE fsi_flag; /* Allocation information control (b7:disabled, b0:dirty) */ + WORD id; /* Volume mount ID */ + WORD n_rootdir; /* Number of root directory entries (FAT12/16) */ + WORD csize; /* Cluster size [sectors] */ #if FF_MAX_SS != FF_MIN_SS - WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */ + WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */ #endif #if FF_USE_LFN - WCHAR* lfnbuf; /* LFN working buffer */ -#endif -#if FF_FS_EXFAT - BYTE* dirbuf; /* Directory entry block scratchpad buffer for exFAT */ + WCHAR* lfnbuf; /* Pointer to LFN working buffer */ #endif #if !FF_FS_READONLY - DWORD last_clst; /* Last allocated cluster */ - DWORD free_clst; /* Number of free clusters */ + DWORD last_clst; /* Last allocated cluster (invalid if >=n_fatent) */ + DWORD free_clst; /* Number of free clusters (invalid if >=fs->n_fatent-2) */ #endif #if FF_FS_RPATH - DWORD cdir; /* Current directory start cluster (0:root) */ -#if FF_FS_EXFAT - DWORD cdc_scl; /* Containing directory start cluster (invalid when cdir is 0) */ - DWORD cdc_size; /* b31-b8:Size of containing directory, b7-b0: Chain status */ - DWORD cdc_ofs; /* Offset in the containing directory (invalid when cdir is 0) */ -#endif + DWORD cdir; /* Current directory start cluster (0:root) */ #endif - DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */ - DWORD fsize; /* Number of sectors per FAT */ - LBA_t volbase; /* Volume base sector */ - LBA_t fatbase; /* FAT base sector */ - LBA_t dirbase; /* Root directory base sector (FAT12/16) or cluster (FAT32/exFAT) */ - LBA_t database; /* Data base sector */ + DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */ + DWORD fsize; /* Number of sectors per FAT */ + LBA_t winsect; /* Current sector appearing in the win[] */ + LBA_t volbase; /* Volume base sector */ + LBA_t fatbase; /* FAT base sector */ + LBA_t dirbase; /* Root directory base sector (FAT12/16) or cluster (FAT32/exFAT) */ + LBA_t database; /* Data base sector */ #if FF_FS_EXFAT - LBA_t bitbase; /* Allocation bitmap base sector */ + LBA_t bitbase; /* Allocation bitmap base sector */ + BYTE* dirbuf; /* Pointer to directory entry block buffer */ +#if FF_FS_RPATH + FFXCWDS xcwds; /* Crrent working directory structure */ + FFXCWDS xcwds2; /* Working buffer to follow the path */ +#endif #endif - 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) */ + BYTE win[FF_MAX_SS]; /* Disk access window for directory, FAT (and file data in tiny cfg) */ } FATFS; @@ -179,21 +194,21 @@ typedef struct { /* Object ID and allocation information (FFOBJID) */ typedef struct { - FATFS* fs; /* Pointer to the hosting volume of this object */ - WORD id; /* Hosting volume's mount ID */ - BYTE attr; /* Object attribute */ - BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:fragmented in this session, b2:sub-directory stretched) */ - DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */ - FSIZE_t objsize; /* Object size (valid when sclust != 0) */ + FATFS* fs; /* Pointer to the volume holding this object */ + WORD id; /* Volume mount ID when this object was opened */ + BYTE attr; /* Object attribute */ + BYTE stat; /* Object chain status (exFAT: b1-0: =0:not contiguous, =2:contiguous, =3:fragmented in this session, b2:sub-directory stretched) */ + DWORD sclust; /* Object data cluster (0:no data or root directory) */ + FSIZE_t objsize; /* Object size (valid when sclust != 0) */ #if FF_FS_EXFAT - DWORD n_cont; /* Size of first fragment - 1 (valid when stat == 3) */ - DWORD n_frag; /* Size of last fragment needs to be written to FAT (valid when not zero) */ - DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */ - DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */ - DWORD c_ofs; /* Offset in the containing directory (valid when file object and sclust != 0) */ + DWORD n_cont; /* Size of first fragment - 1 (valid when stat == 3) */ + DWORD n_frag; /* Size of last fragment needs to be written to FAT (valid when not zero) */ + DWORD c_scl; /* Cluster of directory holding this object (valid when sclust != 0) */ + DWORD c_size; /* Size of directory holding this object (b7-b0: allocation status, valid when c_scl != 0) */ + DWORD c_ofs; /* Offset of entry in the holding directory */ #endif #if FF_FS_LOCK - UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */ + UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */ #endif } FFOBJID; @@ -202,18 +217,18 @@ typedef struct { /* File object structure (FIL) */ typedef struct { - FFOBJID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */ - BYTE flag; /* File status flags */ - 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) */ - LBA_t sect; /* Sector number appearing in buf[] (0:invalid) */ + FFOBJID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */ + BYTE flag; /* File status flags */ + BYTE err; /* Abort flag (error code) */ + FSIZE_t fptr; /* File read/write pointer (0 on open) */ + DWORD clust; /* Current cluster of fptr (invalid when fptr is 0) */ + LBA_t sect; /* Sector number appearing in buf[] (0:invalid) */ #if !FF_FS_READONLY - 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) */ + LBA_t dir_sect; /* Sector number containing the directory entry (not used in exFAT) */ + BYTE* dir_ptr; /* Pointer to the directory entry in the win[] (not used in exFAT) */ #endif #if FF_USE_FASTSEEK - DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */ + DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open; set by application) */ #endif #if !FF_FS_TINY BYTE buf[FF_MAX_SS]; /* File private data read/write window */ @@ -225,40 +240,44 @@ typedef struct { /* Directory object structure (DIR) */ typedef struct { - FFOBJID obj; /* Object identifier */ - DWORD dptr; /* Current read/write offset */ - DWORD clust; /* Current cluster */ - 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]} */ + FFOBJID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */ + DWORD dptr; /* Current read/write offset */ + DWORD clust; /* Current cluster */ + LBA_t sect; /* Current sector (0:no more item to read) */ + BYTE* dir; /* Pointer to the directory item in the win[] in filesystem object */ + BYTE fn[12]; /* SFN (in/out) {body[0-7],ext[8-10],status[11]} */ #if FF_USE_LFN - DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */ + DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:invalid) */ #endif #if FF_USE_FIND - const TCHAR* pat; /* Pointer to the name matching pattern */ + const TCHAR *pat; /* Pointer to the name matching pattern */ #endif } DIR; -/* File information structure (FILINFO) */ +/* File/directory information structure (FILINFO) */ typedef struct { - FSIZE_t fsize; /* File size */ - WORD fdate; /* Modified date */ - WORD ftime; /* Modified time */ - BYTE fattrib; /* File attribute */ + FSIZE_t fsize; /* File size (invalid for directory) */ + WORD fdate; /* Date of file modification or directory creation */ + WORD ftime; /* Time of file modification or directory creation */ +#if FF_FS_CRTIME + WORD crdate; /* Date of object createion */ + WORD crtime; /* Time of object createion */ +#endif + BYTE fattrib; /* Object attribute */ #if FF_USE_LFN - TCHAR altname[FF_SFN_BUF + 1];/* Alternative file name */ - TCHAR fname[FF_LFN_BUF + 1]; /* Primary file name */ + TCHAR altname[FF_SFN_BUF + 1];/* Alternative object name */ + TCHAR fname[FF_LFN_BUF + 1]; /* Primary object name */ #else - TCHAR fname[12 + 1]; /* File name */ + TCHAR fname[12 + 1]; /* Object name */ #endif } FILINFO; -/* Format parameter structure (MKFS_PARM) */ +/* Format parameter structure (MKFS_PARM) used for f_mkfs() */ typedef struct { BYTE fmt; /* Format option (FM_FAT, FM_FAT32, FM_EXFAT and FM_SFD) */ @@ -273,24 +292,24 @@ typedef struct { /* File function return code (FRESULT) */ typedef enum { - FR_OK = 0, /* (0) Succeeded */ + FR_OK = 0, /* (0) Function succeeded */ FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */ FR_INT_ERR, /* (2) Assertion failed */ - FR_NOT_READY, /* (3) The physical drive cannot work */ + FR_NOT_READY, /* (3) The physical drive does not work */ FR_NO_FILE, /* (4) Could not find the file */ FR_NO_PATH, /* (5) Could not find the path */ FR_INVALID_NAME, /* (6) The path name format is invalid */ - FR_DENIED, /* (7) Access denied due to prohibited access or directory full */ - FR_EXIST, /* (8) Access denied due to prohibited access */ + FR_DENIED, /* (7) Access denied due to a prohibited access or directory full */ + FR_EXIST, /* (8) Access denied due to a prohibited access */ FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */ FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */ FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */ FR_NOT_ENABLED, /* (12) The volume has no work area */ - FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */ - FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any problem */ - FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */ + FR_NO_FILESYSTEM, /* (13) Could not find a valid FAT volume */ + FR_MKFS_ABORTED, /* (14) The f_mkfs function aborted due to some problem */ + FR_TIMEOUT, /* (15) Could not take control of the volume within defined period */ FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */ - FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */ + FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated, given buffer size is insufficient or too deep path */ FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > FF_FS_LOCK */ FR_INVALID_PARAMETER /* (19) Given parameter is invalid */ } FRESULT; @@ -377,7 +396,7 @@ DWORD ff_wtoupper (DWORD uni); /* Unicode upper-case conversion */ void* ff_memalloc (UINT msize); /* Allocate memory block */ void ff_memfree (void* mblock); /* Free memory block */ #endif -#if FF_FS_REENTRANT /* Sync functions */ +#if FF_FS_REENTRANT /* Sync functions */ int ff_mutex_create (int vol); /* Create a sync object */ void ff_mutex_delete (int vol); /* Delete a sync object */ int ff_mutex_take (int vol); /* Lock sync object */ @@ -391,7 +410,7 @@ void ff_mutex_give (int vol); /* Unlock sync object */ /* Flags and Offset Address */ /*--------------------------------------------------------------*/ -/* File access mode and open method flags (3rd argument of f_open) */ +/* File access mode and open method flags (3rd argument of f_open function) */ #define FA_READ 0x01 #define FA_WRITE 0x02 #define FA_OPEN_EXISTING 0x00 @@ -400,10 +419,10 @@ void ff_mutex_give (int vol); /* Unlock sync object */ #define FA_OPEN_ALWAYS 0x10 #define FA_OPEN_APPEND 0x30 -/* Fast seek controls (2nd argument of f_lseek) */ +/* Fast seek controls (2nd argument of f_lseek function) */ #define CREATE_LINKMAP ((FSIZE_t)0 - 1) -/* Format options (2nd argument of f_mkfs) */ +/* Format options (2nd argument of f_mkfs function) */ #define FM_FAT 0x01 #define FM_FAT32 0x02 #define FM_EXFAT 0x04 diff --git a/components/dfs/dfs_v2/filesystems/elmfat/ffconf.h b/components/dfs/dfs_v2/filesystems/elmfat/ffconf.h index 409d97a6633..ff159e60bc1 100644 --- a/components/dfs/dfs_v2/filesystems/elmfat/ffconf.h +++ b/components/dfs/dfs_v2/filesystems/elmfat/ffconf.h @@ -2,7 +2,7 @@ / Configurations of FatFs Module /---------------------------------------------------------------------------*/ -#define FFCONF_DEF 80286 /* Revision ID */ +#define FFCONF_DEF 80386 /* Revision ID */ /*---------------------------------------------------------------------------/ / Function Configurations @@ -31,36 +31,36 @@ #define FF_USE_MKFS 1 -/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */ +/* This option switches f_mkfs(). (0:Disable or 1:Enable) */ #define FF_USE_FASTSEEK 1 -/* This option switches fast seek function. (0:Disable or 1:Enable) */ +/* This option switches fast seek feature. (0:Disable or 1:Enable) */ #define FF_USE_EXPAND 0 -/* This option switches f_expand function. (0:Disable or 1:Enable) */ +/* This option switches f_expand(). (0:Disable or 1:Enable) */ #define FF_USE_CHMOD 0 -/* This option switches attribute manipulation functions, f_chmod() and f_utime(). +/* This option switches attribute control API functions, f_chmod() and f_utime(). / (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */ #define FF_USE_LABEL 0 -/* This option switches volume label functions, f_getlabel() and f_setlabel(). +/* This option switches volume label API functions, f_getlabel() and f_setlabel(). / (0:Disable or 1:Enable) */ #define FF_USE_FORWARD 0 -/* This option switches f_forward() function. (0:Disable or 1:Enable) */ +/* This option switches f_forward(). (0:Disable or 1:Enable) */ #define FF_USE_STRFUNC 0 #define FF_PRINT_LLI 0 #define FF_PRINT_FLOAT 0 #define FF_STRF_ENCODE 3 -/* FF_USE_STRFUNC switches string functions, f_gets(), f_putc(), f_puts() and +/* FF_USE_STRFUNC switches string API functions, f_gets(), f_putc(), f_puts() and / f_printf(). / / 0: Disable. FF_PRINT_LLI, FF_PRINT_FLOAT and FF_STRF_ENCODE have no effect. @@ -69,7 +69,7 @@ / / FF_PRINT_LLI = 1 makes f_printf() support long long argument and FF_PRINT_FLOAT = 1/2 / makes f_printf() support floating point argument. These features want C99 or later. -/ When FF_LFN_UNICODE >= 1 with LFN enabled, string functions convert the character +/ When FF_LFN_UNICODE >= 1 with LFN enabled, string API functions convert the character / encoding in it. FF_STRF_ENCODE selects assumption of character encoding ON THE FILE / to be read/written via those functions. / @@ -127,15 +127,15 @@ /* 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. / -/ To enable the LFN, ffunicode.c needs to be added to the project. The LFN function +/ To enable the LFN, ffunicode.c needs to be added to the project. The LFN feature / 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 it 255 to fully support LFN +/ be in range of 12 to 255. It is recommended to be set 255 to fully support the 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 @@ -176,14 +176,26 @@ #define FF_FS_RPATH 0 -/* This option configures support for relative path. +/* This option configures support for relative path feature. / -/ 0: Disable relative path and remove related functions. -/ 1: Enable relative path. f_chdir() and f_chdrive() are available. -/ 2: f_getcwd() function is available in addition to 1. +/ 0: Disable relative path and remove related API functions. +/ 1: Enable relative path and dot names. f_chdir() and f_chdrive() are available. +/ 2: f_getcwd() is available in addition to 1. */ +#define FF_PATH_DEPTH 10 +/* This option defines maximum depth of directory in the exFAT volume. It is NOT +/ relevant to FAT/FAT32 volume. +/ For example, FF_PATH_DEPTH = 3 will able to follow a path "/dir1/dir2/dir3/file" +/ but a sub-directory in the dir3 will not able to be followed and set current +/ directory. +/ The size of filesystem object (FATFS) increases FF_PATH_DEPTH * 24 bytes. +/ When FF_FS_EXFAT == 0 or FF_FS_RPATH == 0, this option has no effect. +*/ + + + /*---------------------------------------------------------------------------/ / Drive/Volume Configurations /---------------------------------------------------------------------------*/ @@ -201,7 +213,7 @@ /* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings. / When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive / number in the path name. FF_VOLUME_STRS defines the volume ID strings for each -/ logical drives. Number of items must not be less than FF_VOLUMES. Valid +/ logical drive. Number of items must not be less than FF_VOLUMES. Valid / characters for the volume ID strings are A-Z, a-z and 0-9, however, they are / compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is / not defined, a user defined volume string table is needed as: @@ -214,9 +226,9 @@ /* This option switches support for multiple volumes on the physical drive. / By default (0), each logical drive number is bound to the same physical drive / number and only an FAT volume found on the physical drive will be mounted. -/ When this function is enabled (1), each logical drive number can be bound to +/ When this feature is enabled (1), each logical drive number can be bound to / arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk() -/ function will be available. */ +/ will be available. */ #define FF_MIN_SS 512 @@ -228,8 +240,8 @@ /* This set of options configures the range of sector size to be supported. (512, / 1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and / harddisk, but a larger value may be required for on-board flash memory and some -/ type of optical media. When FF_MAX_SS is larger than FF_MIN_SS, FatFs is configured -/ for variable sector size mode and disk_ioctl() function needs to implement +/ type of optical media. When FF_MAX_SS is larger than FF_MIN_SS, FatFs is +/ configured for variable sector size mode and disk_ioctl() needs to implement / GET_SECTOR_SIZE command. */ @@ -239,14 +251,14 @@ #define FF_MIN_GPT 0x10000000 -/* Minimum number of sectors to switch GPT as partitioning format in f_mkfs and -/ f_fdisk function. 0x100000000 max. This option has no effect when FF_LBA64 == 0. */ +/* Minimum number of sectors to switch GPT as partitioning format in f_mkfs() and +/ f_fdisk(). 2^32 sectors maximum. 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. */ +/ To enable this feature, also CTRL_TRIM command should be implemented to +/ the disk_ioctl(). */ @@ -256,7 +268,7 @@ #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. +/ At the tiny configuration, size of file object (FIL) is reduced FF_MAX_SS bytes. / Instead of private sector buffer eliminated from the file object, common sector / buffer in the filesystem object (FATFS) is used for the file data transfer. */ @@ -273,20 +285,25 @@ #define FF_FS_NORTC 0 #define FF_NORTC_MON 1 #define FF_NORTC_MDAY 1 -#define FF_NORTC_YEAR 2022 +#define FF_NORTC_YEAR 2025 /* The option FF_FS_NORTC switches timestamp feature. If the system does not have / an RTC or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable the / timestamp feature. Every object modified by FatFs will have a fixed timestamp / defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time. -/ 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, +/ To enable timestamp function (FF_FS_NORTC = 0), get_fattime() 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 in read-only configuration (FF_FS_READONLY = 1). */ +#define FF_FS_CRTIME 0 +/* This option enables(1)/disables(0) the timestamp of the file created. When +/ set 1, the file created time is available in FILINFO structure. */ + + #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 the first time after volume mount will force +/* If you need to know the correct free space on the FAT32 volume, set bit 0 of +/ this option, and f_getfree() on the 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. @@ -323,17 +340,17 @@ /* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs / module itself. Note that regardless of this option, file access to different / volume is always re-entrant and volume control functions, f_mount(), f_mkfs() -/ and f_fdisk() function, are always not re-entrant. Only file/directory access -/ to the same volume is under control of this featuer. +/ and f_fdisk(), are always not re-entrant. Only file/directory access to +/ the same volume is under control of this featuer. / / 0: Disable re-entrancy. FF_FS_TIMEOUT have no effect. / 1: Enable re-entrancy. Also user provided synchronization handlers, -/ ff_mutex_create(), ff_mutex_delete(), ff_mutex_take() and ff_mutex_give() -/ function, must be added to the project. Samples are available in ffsystem.c. +/ ff_mutex_create(), ff_mutex_delete(), ff_mutex_take() and ff_mutex_give(), +/ must be added to the project. Samples are available in ffsystem.c. / / The FF_FS_TIMEOUT defines timeout period in unit of O/S time tick. */ -/*--- End of configuration options ---*/ \ No newline at end of file +/*--- End of configuration options ---*/