summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwdfk-prog <[email protected]>2026-05-04 18:44:57 +0800
committerGitHub <[email protected]>2026-05-04 18:44:57 +0800
commitea5e1ca4933476374380c2d701ccc806209a7aba (patch)
tree776f68ff6916d4af773e9da3eb6d443846ed7168
parentea13820c2c1f22d3f22b39142c2ee3e0f5172efa (diff)
[dfs][elmfat] Update elm-fatfs to R0.16
-rw-r--r--components/dfs/dfs_v1/filesystems/elmfat/00history.txt30
-rw-r--r--components/dfs/dfs_v1/filesystems/elmfat/00readme.txt2
-rw-r--r--components/dfs/dfs_v1/filesystems/elmfat/dfs_elm.c24
-rw-r--r--components/dfs/dfs_v1/filesystems/elmfat/diskio.h6
-rw-r--r--components/dfs/dfs_v1/filesystems/elmfat/ff.c2466
-rw-r--r--components/dfs/dfs_v1/filesystems/elmfat/ff.h256
-rw-r--r--components/dfs/dfs_v1/filesystems/elmfat/ffconf.h108
-rw-r--r--components/dfs/dfs_v1/filesystems/elmfat/ffunicode.c44
-rw-r--r--components/dfs/dfs_v2/filesystems/elmfat/00history.txt20
-rw-r--r--components/dfs/dfs_v2/filesystems/elmfat/00readme.txt2
-rw-r--r--components/dfs/dfs_v2/filesystems/elmfat/diskio.h6
-rw-r--r--components/dfs/dfs_v2/filesystems/elmfat/ff.c1974
-rw-r--r--components/dfs/dfs_v2/filesystems/elmfat/ff.h211
-rw-r--r--components/dfs/dfs_v2/filesystems/elmfat/ffconf.h89
14 files changed, 2899 insertions, 2339 deletions
diff --git a/components/dfs/dfs_v1/filesystems/elmfat/00history.txt b/components/dfs/dfs_v1/filesystems/elmfat/00history.txt
index 8a0169b1ff..11982e0410 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 4960997b30..2dae010cc7 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 8b25005423..effd1bcd7c 100644
--- a/components/dfs/dfs_v1/filesystems/elmfat/dfs_elm.c
+++ b/components/dfs/dfs_v1/filesystems/elmfat/dfs_elm.c
@@ -997,41 +997,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 e4ead78380..195f432547 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 80e194d6e9..c4df986434 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 <string.h>
-#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 <<<If this memory write operation is not in atomic, FF_FS_REENTRANT == 1 and FF_VOLUMES > 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);
+ st_16(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 */
+ 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;
- /* Store the direcotry entry block to the directory */
- res = dir_sdi(dp, dp->blk_ofs);
+ st_16(dirb + XDIR_SetSum, xdir_sum(dirb)); /* Create check sum */
+
+ /* 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;
+ 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 is found */
-#if FF_FS_RPATH != 0
- vol = CurrVol; /* Default drive is current drive */
+ /* 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;
- fasize = ld_word(fs->win + BPB_FATSz16); /* Number of sectors per FAT */
- if (fasize == 0) fasize = ld_dword(fs->win + BPB_FATSz32);
+ 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_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
#endif
-#if FF_FS_LOCK != 0 /* Clear file lock semaphores */
- clear_lock(fs);
+
+#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;
- /* 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) */
+#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 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
+
+ /* 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) {
@@ -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 <math.h>
@@ -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 7db1c4d4a2..fed69af5d6 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 <rtthread.h>
+#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 <stdint.h>
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) */
-#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; /* 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 */
+ 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
- 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) */
+#endif
+ 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 be6cf442db..a99c908782 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 a69b24c830..e6bcacae6b 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 7a153a2292..11982e0410 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 3de3aeaa2d..2dae010cc7 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 e4ead78380..195f432547 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 9fd16c6deb..c4df986434 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 <string.h>
-#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);
+ st_16(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 */
+ 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;
+ 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 is found */
-#if FF_FS_RPATH != 0
- vol = CurrVol; /* Default drive is current drive */
+ /* 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 != 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
+#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;
- /* 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) */
+#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 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
+
+ /* 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) {
#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 <math.h>
@@ -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 b01385e981..fed69af5d6 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 <rtthread.h>
+#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 <stdint.h>
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 409d97a663..ff159e60bc 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 ---*/