Prusa MINI Firmware overview
ff.c File Reference
#include "ff.h"
#include "diskio.h"

Macros

#define IsUpper(c)   (((c)>='A')&&((c)<='Z'))
 
#define IsLower(c)   (((c)>='a')&&((c)<='z'))
 
#define IsDigit(c)   (((c)>='0')&&((c)<='9'))
 
#define IsDBCS1(c)   0
 
#define IsDBCS2(c)   0
 
#define AM_VOL   0x08 /* Volume label */
 
#define AM_LFN   0x0F /* LFN entry */
 
#define AM_MASK   0x3F /* Mask of defined bits */
 
#define FA_SEEKEND   0x20 /* Seek to end of the file on file open */
 
#define FA_MODIFIED   0x40 /* File has been modified */
 
#define FA_DIRTY   0x80 /* FIL.buf[] needs to be written-back */
 
#define NSFLAG   11 /* Index of the name status byte */
 
#define NS_LOSS   0x01 /* Out of 8.3 format */
 
#define NS_LFN   0x02 /* Force to create LFN entry */
 
#define NS_LAST   0x04 /* Last segment */
 
#define NS_BODY   0x08 /* Lower case flag (body) */
 
#define NS_EXT   0x10 /* Lower case flag (ext) */
 
#define NS_DOT   0x20 /* Dot entry */
 
#define NS_NOLFN   0x40 /* Do not find LFN */
 
#define NS_NONAME   0x80 /* Not followed */
 
#define MAX_DIR   0x200000 /* Max size of FAT directory */
 
#define MAX_DIR_EX   0x10000000 /* Max size of exFAT directory */
 
#define MAX_FAT12   0xFF5 /* Max FAT12 clusters (differs from specs, but correct for real DOS/Windows behavior) */
 
#define MAX_FAT16   0xFFF5 /* Max FAT16 clusters (differs from specs, but correct for real DOS/Windows behavior) */
 
#define MAX_FAT32   0x0FFFFFF5 /* Max FAT32 clusters (not specified, practical limit) */
 
#define MAX_EXFAT   0x7FFFFFFD /* Max exFAT clusters (differs from specs, implementation limit) */
 
#define BS_JmpBoot   0 /* x86 jump instruction (3-byte) */
 
#define BS_OEMName   3 /* OEM name (8-byte) */
 
#define BPB_BytsPerSec   11 /* Sector size [byte] (WORD) */
 
#define BPB_SecPerClus   13 /* Cluster size [sector] (BYTE) */
 
#define BPB_RsvdSecCnt   14 /* Size of reserved area [sector] (WORD) */
 
#define BPB_NumFATs   16 /* Number of FATs (BYTE) */
 
#define BPB_RootEntCnt   17 /* Size of root directory area for FAT12/16 [entry] (WORD) */
 
#define BPB_TotSec16   19 /* Volume size (16-bit) [sector] (WORD) */
 
#define BPB_Media   21 /* Media descriptor byte (BYTE) */
 
#define BPB_FATSz16   22 /* FAT size (16-bit) [sector] (WORD) */
 
#define BPB_SecPerTrk   24 /* Track size for int13h [sector] (WORD) */
 
#define BPB_NumHeads   26 /* Number of heads for int13h (WORD) */
 
#define BPB_HiddSec   28 /* Volume offset from top of the drive (DWORD) */
 
#define BPB_TotSec32   32 /* Volume size (32-bit) [sector] (DWORD) */
 
#define BS_DrvNum   36 /* Physical drive number for int13h (BYTE) */
 
#define BS_NTres   37 /* Error flag (BYTE) */
 
#define BS_BootSig   38 /* Extended boot signature (BYTE) */
 
#define BS_VolID   39 /* Volume serial number (DWORD) */
 
#define BS_VolLab   43 /* Volume label string (8-byte) */
 
#define BS_FilSysType   54 /* File system type string (8-byte) */
 
#define BS_BootCode   62 /* Boot code (448-byte) */
 
#define BS_55AA   510 /* Signature word (WORD) */
 
#define BPB_FATSz32   36 /* FAT32: FAT size [sector] (DWORD) */
 
#define BPB_ExtFlags32   40 /* FAT32: Extended flags (WORD) */
 
#define BPB_FSVer32   42 /* FAT32: File system version (WORD) */
 
#define BPB_RootClus32   44 /* FAT32: Root directory cluster (DWORD) */
 
#define BPB_FSInfo32   48 /* FAT32: Offset of FSINFO sector (WORD) */
 
#define BPB_BkBootSec32   50 /* FAT32: Offset of backup boot sector (WORD) */
 
#define BS_DrvNum32   64 /* FAT32: Physical drive number for int13h (BYTE) */
 
#define BS_NTres32   65 /* FAT32: Error flag (BYTE) */
 
#define BS_BootSig32   66 /* FAT32: Extended boot signature (BYTE) */
 
#define BS_VolID32   67 /* FAT32: Volume serial number (DWORD) */
 
#define BS_VolLab32   71 /* FAT32: Volume label string (8-byte) */
 
#define BS_FilSysType32   82 /* FAT32: File system type string (8-byte) */
 
#define BS_BootCode32   90 /* FAT32: Boot code (420-byte) */
 
#define BPB_ZeroedEx   11 /* exFAT: MBZ field (53-byte) */
 
#define BPB_VolOfsEx   64 /* exFAT: Volume offset from top of the drive [sector] (QWORD) */
 
#define BPB_TotSecEx   72 /* exFAT: Volume size [sector] (QWORD) */
 
#define BPB_FatOfsEx   80 /* exFAT: FAT offset from top of the volume [sector] (DWORD) */
 
#define BPB_FatSzEx   84 /* exFAT: FAT size [sector] (DWORD) */
 
#define BPB_DataOfsEx   88 /* exFAT: Data offset from top of the volume [sector] (DWORD) */
 
#define BPB_NumClusEx   92 /* exFAT: Number of clusters (DWORD) */
 
#define BPB_RootClusEx   96 /* exFAT: Root directory start cluster (DWORD) */
 
#define BPB_VolIDEx   100 /* exFAT: Volume serial number (DWORD) */
 
#define BPB_FSVerEx   104 /* exFAT: File system version (WORD) */
 
#define BPB_VolFlagEx   106 /* exFAT: Volume flags (BYTE) */
 
#define BPB_ActFatEx   107 /* exFAT: Active FAT flags (BYTE) */
 
#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_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_CrtTime10   13 /* Created time sub-second (BYTE) */
 
#define DIR_CrtTime   14 /* Created time (DWORD) */
 
#define DIR_LstAccDate   18 /* Last accessed date (WORD) */
 
#define DIR_FstClusHI   20 /* Higher 16-bit of first cluster (WORD) */
 
#define DIR_ModTime   22 /* Modified time (DWORD) */
 
#define DIR_FstClusLO   26 /* Lower 16-bit of first cluster (WORD) */
 
#define DIR_FileSize   28 /* File size (DWORD) */
 
#define LDIR_Ord   0 /* LFN: LFN order and LLE flag (BYTE) */
 
#define LDIR_Attr   11 /* LFN: LFN attribute (BYTE) */
 
#define LDIR_Type   12 /* LFN: Entry type (BYTE) */
 
#define LDIR_Chksum   13 /* LFN: Checksum of the SFN (BYTE) */
 
#define LDIR_FstClusLO   26 /* LFN: MBZ field (WORD) */
 
#define XDIR_Type   0 /* exFAT: Type of exFAT directory entry (BYTE) */
 
#define XDIR_NumLabel   1 /* exFAT: Number of volume label characters (BYTE) */
 
#define XDIR_Label   2 /* exFAT: Volume label (11-WORD) */
 
#define XDIR_CaseSum   4 /* exFAT: Sum of case conversion table (DWORD) */
 
#define XDIR_NumSec   1 /* exFAT: Number of secondary entries (BYTE) */
 
#define XDIR_SetSum   2 /* exFAT: Sum of the set of directory entries (WORD) */
 
#define XDIR_Attr   4 /* exFAT: File attribute (WORD) */
 
#define XDIR_CrtTime   8 /* exFAT: Created time (DWORD) */
 
#define XDIR_ModTime   12 /* exFAT: Modified time (DWORD) */
 
#define XDIR_AccTime   16 /* exFAT: Last accessed time (DWORD) */
 
#define XDIR_CrtTime10   20 /* exFAT: Created time subsecond (BYTE) */
 
#define XDIR_ModTime10   21 /* exFAT: Modified time subsecond (BYTE) */
 
#define XDIR_CrtTZ   22 /* exFAT: Created timezone (BYTE) */
 
#define XDIR_ModTZ   23 /* exFAT: Modified timezone (BYTE) */
 
#define XDIR_AccTZ   24 /* exFAT: Last accessed timezone (BYTE) */
 
#define XDIR_GenFlags   33 /* exFAT: General secondary flags (WORD) */
 
#define XDIR_NumName   35 /* exFAT: Number of file name characters (BYTE) */
 
#define XDIR_NameHash   36 /* exFAT: Hash of file name (WORD) */
 
#define XDIR_ValidFileSize   40 /* exFAT: Valid file size (QWORD) */
 
#define XDIR_FstClus   52 /* exFAT: First cluster of the file data (DWORD) */
 
#define XDIR_FileSize   56 /* exFAT: File/Directory size (QWORD) */
 
#define SZDIRE   32 /* Size of a directory entry */
 
#define DDEM   0xE5 /* Deleted directory entry mark set to DIR_Name[0] */
 
#define RDDEM   0x05 /* Replacement of the character collides with DDEM */
 
#define LLEF   0x40 /* Last long entry flag in LDIR_Ord */
 
#define FSI_LeadSig   0 /* FAT32 FSI: Leading signature (DWORD) */
 
#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 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_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_StLba   8 /* MBR PTE: Start in LBA */
 
#define PTE_SizLba   12 /* MBR PTE: Size in LBA */
 
#define ABORT(fs, res)   { fp->err = (BYTE)(res); LEAVE_FF(fs, res); }
 
#define ENTER_FF(fs)
 
#define LEAVE_FF(fs, res)   return res
 
#define LD2PD(vol)   (BYTE)(vol) /* Each logical drive is bound to the same physical drive number */
 
#define LD2PT(vol)   0 /* Find first valid partition or in SFD */
 
#define SS(fs)   ((UINT)_MAX_SS) /* Fixed sector size */
 
#define GET_FATTIME()   get_fattime()
 
#define DEF_NAMBUF
 
#define INIT_NAMBUF(fs)
 
#define FREE_NAMBUF()
 

Functions

static WORD ld_word (const BYTE *ptr)
 
static DWORD ld_dword (const BYTE *ptr)
 
static void st_word (BYTE *ptr, WORD val)
 
static void st_dword (BYTE *ptr, DWORD val)
 
static void mem_cpy (void *dst, const void *src, UINT cnt)
 
static void mem_set (void *dst, int val, UINT cnt)
 
static int mem_cmp (const void *dst, const void *src, UINT cnt)
 
static int chk_chr (const char *str, int chr)
 
static FRESULT sync_window (FATFS *fs)
 
static FRESULT move_window (FATFS *fs, DWORD sector)
 
static FRESULT sync_fs (FATFS *fs)
 
static DWORD clust2sect (FATFS *fs, DWORD clst)
 
static DWORD get_fat (_FDID *obj, DWORD clst)
 
static FRESULT put_fat (FATFS *fs, DWORD clst, DWORD val)
 
static FRESULT remove_chain (_FDID *obj, DWORD clst, DWORD pclst)
 
static DWORD create_chain (_FDID *obj, DWORD clst)
 
static FRESULT dir_sdi (DIR *dp, DWORD ofs)
 
static FRESULT dir_next (DIR *dp, int stretch)
 
static FRESULT dir_alloc (DIR *dp, UINT nent)
 
static DWORD ld_clust (FATFS *fs, const BYTE *dir)
 
static void st_clust (FATFS *fs, BYTE *dir, DWORD cl)
 
static FRESULT dir_read (DIR *dp, int vol)
 
static FRESULT dir_find (DIR *dp)
 
static FRESULT dir_register (DIR *dp)
 
static FRESULT dir_remove (DIR *dp)
 
static void get_fileinfo (DIR *dp, FILINFO *fno)
 
static FRESULT create_name (DIR *dp, const TCHAR **path)
 
static FRESULT follow_path (DIR *dp, const TCHAR *path)
 
static int get_ldnumber (const TCHAR **path)
 
static BYTE check_fs (FATFS *fs, DWORD sect)
 
static FRESULT find_volume (const TCHAR **path, FATFS **rfs, BYTE mode)
 
static FRESULT validate (_FDID *obj, FATFS **fs)
 
FRESULT f_mount (FATFS *fs, const TCHAR *path, BYTE opt)
 
FRESULT f_open (FIL *fp, const TCHAR *path, BYTE mode)
 
FRESULT f_read (FIL *fp, void *buff, UINT btr, UINT *br)
 
FRESULT f_write (FIL *fp, const void *buff, UINT btw, UINT *bw)
 
FRESULT f_sync (FIL *fp)
 
FRESULT f_close (FIL *fp)
 
FRESULT f_lseek (FIL *fp, FSIZE_t ofs)
 
FRESULT f_opendir (DIR *dp, const TCHAR *path)
 
FRESULT f_closedir (DIR *dp)
 
FRESULT f_readdir (DIR *dp, FILINFO *fno)
 
FRESULT f_stat (const TCHAR *path, FILINFO *fno)
 
FRESULT f_getfree (const TCHAR *path, DWORD *nclst, FATFS **fatfs)
 
FRESULT f_truncate (FIL *fp)
 
FRESULT f_unlink (const TCHAR *path)
 
FRESULT f_mkdir (const TCHAR *path)
 
FRESULT f_rename (const TCHAR *path_old, const TCHAR *path_new)
 

Variables

static FATFSFatFs [_VOLUMES]
 
static WORD Fsid
 

Macro Definition Documentation

◆ IsUpper

#define IsUpper (   c)    (((c)>='A')&&((c)<='Z'))

◆ IsLower

#define IsLower (   c)    (((c)>='a')&&((c)<='z'))

◆ IsDigit

#define IsDigit (   c)    (((c)>='0')&&((c)<='9'))

◆ IsDBCS1

#define IsDBCS1 (   c)    0

◆ IsDBCS2

#define IsDBCS2 (   c)    0

◆ AM_VOL

#define AM_VOL   0x08 /* Volume label */

◆ AM_LFN

#define AM_LFN   0x0F /* LFN entry */

◆ AM_MASK

#define AM_MASK   0x3F /* Mask of defined bits */

◆ FA_SEEKEND

#define FA_SEEKEND   0x20 /* Seek to end of the file on file open */

◆ FA_MODIFIED

#define FA_MODIFIED   0x40 /* File has been modified */

◆ FA_DIRTY

#define FA_DIRTY   0x80 /* FIL.buf[] needs to be written-back */

◆ NSFLAG

#define NSFLAG   11 /* Index of the name status byte */

◆ NS_LOSS

#define NS_LOSS   0x01 /* Out of 8.3 format */

◆ NS_LFN

#define NS_LFN   0x02 /* Force to create LFN entry */

◆ NS_LAST

#define NS_LAST   0x04 /* Last segment */

◆ NS_BODY

#define NS_BODY   0x08 /* Lower case flag (body) */

◆ NS_EXT

#define NS_EXT   0x10 /* Lower case flag (ext) */

◆ NS_DOT

#define NS_DOT   0x20 /* Dot entry */

◆ NS_NOLFN

#define NS_NOLFN   0x40 /* Do not find LFN */

◆ NS_NONAME

#define NS_NONAME   0x80 /* Not followed */

◆ MAX_DIR

#define MAX_DIR   0x200000 /* Max size of FAT directory */

◆ MAX_DIR_EX

#define MAX_DIR_EX   0x10000000 /* Max size of exFAT directory */

◆ MAX_FAT12

#define MAX_FAT12   0xFF5 /* Max FAT12 clusters (differs from specs, but correct for real DOS/Windows behavior) */

◆ MAX_FAT16

#define MAX_FAT16   0xFFF5 /* Max FAT16 clusters (differs from specs, but correct for real DOS/Windows behavior) */

◆ MAX_FAT32

#define MAX_FAT32   0x0FFFFFF5 /* Max FAT32 clusters (not specified, practical limit) */

◆ MAX_EXFAT

#define MAX_EXFAT   0x7FFFFFFD /* Max exFAT clusters (differs from specs, implementation limit) */

◆ BS_JmpBoot

#define BS_JmpBoot   0 /* x86 jump instruction (3-byte) */

◆ BS_OEMName

#define BS_OEMName   3 /* OEM name (8-byte) */

◆ BPB_BytsPerSec

#define BPB_BytsPerSec   11 /* Sector size [byte] (WORD) */

◆ BPB_SecPerClus

#define BPB_SecPerClus   13 /* Cluster size [sector] (BYTE) */

◆ BPB_RsvdSecCnt

#define BPB_RsvdSecCnt   14 /* Size of reserved area [sector] (WORD) */

◆ BPB_NumFATs

#define BPB_NumFATs   16 /* Number of FATs (BYTE) */

◆ BPB_RootEntCnt

#define BPB_RootEntCnt   17 /* Size of root directory area for FAT12/16 [entry] (WORD) */

◆ BPB_TotSec16

#define BPB_TotSec16   19 /* Volume size (16-bit) [sector] (WORD) */

◆ BPB_Media

#define BPB_Media   21 /* Media descriptor byte (BYTE) */

◆ BPB_FATSz16

#define BPB_FATSz16   22 /* FAT size (16-bit) [sector] (WORD) */

◆ BPB_SecPerTrk

#define BPB_SecPerTrk   24 /* Track size for int13h [sector] (WORD) */

◆ BPB_NumHeads

#define BPB_NumHeads   26 /* Number of heads for int13h (WORD) */

◆ BPB_HiddSec

#define BPB_HiddSec   28 /* Volume offset from top of the drive (DWORD) */

◆ BPB_TotSec32

#define BPB_TotSec32   32 /* Volume size (32-bit) [sector] (DWORD) */

◆ BS_DrvNum

#define BS_DrvNum   36 /* Physical drive number for int13h (BYTE) */

◆ BS_NTres

#define BS_NTres   37 /* Error flag (BYTE) */

◆ BS_BootSig

#define BS_BootSig   38 /* Extended boot signature (BYTE) */

◆ BS_VolID

#define BS_VolID   39 /* Volume serial number (DWORD) */

◆ BS_VolLab

#define BS_VolLab   43 /* Volume label string (8-byte) */

◆ BS_FilSysType

#define BS_FilSysType   54 /* File system type string (8-byte) */

◆ BS_BootCode

#define BS_BootCode   62 /* Boot code (448-byte) */

◆ BS_55AA

#define BS_55AA   510 /* Signature word (WORD) */

◆ BPB_FATSz32

#define BPB_FATSz32   36 /* FAT32: FAT size [sector] (DWORD) */

◆ BPB_ExtFlags32

#define BPB_ExtFlags32   40 /* FAT32: Extended flags (WORD) */

◆ BPB_FSVer32

#define BPB_FSVer32   42 /* FAT32: File system version (WORD) */

◆ BPB_RootClus32

#define BPB_RootClus32   44 /* FAT32: Root directory cluster (DWORD) */

◆ BPB_FSInfo32

#define BPB_FSInfo32   48 /* FAT32: Offset of FSINFO sector (WORD) */

◆ BPB_BkBootSec32

#define BPB_BkBootSec32   50 /* FAT32: Offset of backup boot sector (WORD) */

◆ BS_DrvNum32

#define BS_DrvNum32   64 /* FAT32: Physical drive number for int13h (BYTE) */

◆ BS_NTres32

#define BS_NTres32   65 /* FAT32: Error flag (BYTE) */

◆ BS_BootSig32

#define BS_BootSig32   66 /* FAT32: Extended boot signature (BYTE) */

◆ BS_VolID32

#define BS_VolID32   67 /* FAT32: Volume serial number (DWORD) */

◆ BS_VolLab32

#define BS_VolLab32   71 /* FAT32: Volume label string (8-byte) */

◆ BS_FilSysType32

#define BS_FilSysType32   82 /* FAT32: File system type string (8-byte) */

◆ BS_BootCode32

#define BS_BootCode32   90 /* FAT32: Boot code (420-byte) */

◆ BPB_ZeroedEx

#define BPB_ZeroedEx   11 /* exFAT: MBZ field (53-byte) */

◆ BPB_VolOfsEx

#define BPB_VolOfsEx   64 /* exFAT: Volume offset from top of the drive [sector] (QWORD) */

◆ BPB_TotSecEx

#define BPB_TotSecEx   72 /* exFAT: Volume size [sector] (QWORD) */

◆ BPB_FatOfsEx

#define BPB_FatOfsEx   80 /* exFAT: FAT offset from top of the volume [sector] (DWORD) */

◆ BPB_FatSzEx

#define BPB_FatSzEx   84 /* exFAT: FAT size [sector] (DWORD) */

◆ BPB_DataOfsEx

#define BPB_DataOfsEx   88 /* exFAT: Data offset from top of the volume [sector] (DWORD) */

◆ BPB_NumClusEx

#define BPB_NumClusEx   92 /* exFAT: Number of clusters (DWORD) */

◆ BPB_RootClusEx

#define BPB_RootClusEx   96 /* exFAT: Root directory start cluster (DWORD) */

◆ BPB_VolIDEx

#define BPB_VolIDEx   100 /* exFAT: Volume serial number (DWORD) */

◆ BPB_FSVerEx

#define BPB_FSVerEx   104 /* exFAT: File system version (WORD) */

◆ BPB_VolFlagEx

#define BPB_VolFlagEx   106 /* exFAT: Volume flags (BYTE) */

◆ BPB_ActFatEx

#define BPB_ActFatEx   107 /* exFAT: Active FAT flags (BYTE) */

◆ BPB_BytsPerSecEx

#define BPB_BytsPerSecEx   108 /* exFAT: Log2 of sector size in unit of byte (BYTE) */

◆ BPB_SecPerClusEx

#define BPB_SecPerClusEx   109 /* exFAT: Log2 of cluster size in unit of sector (BYTE) */

◆ BPB_NumFATsEx

#define BPB_NumFATsEx   110 /* exFAT: Number of FATs (BYTE) */

◆ BPB_DrvNumEx

#define BPB_DrvNumEx   111 /* exFAT: Physical drive number for int13h (BYTE) */

◆ BPB_PercInUseEx

#define BPB_PercInUseEx   112 /* exFAT: Percent in use (BYTE) */

◆ BPB_RsvdEx

#define BPB_RsvdEx   113 /* exFAT: Reserved (7-byte) */

◆ BS_BootCodeEx

#define BS_BootCodeEx   120 /* exFAT: Boot code (390-byte) */

◆ DIR_Name

#define DIR_Name   0 /* Short file name (11-byte) */

◆ DIR_Attr

#define DIR_Attr   11 /* Attribute (BYTE) */

◆ DIR_NTres

#define DIR_NTres   12 /* Lower case flag (BYTE) */

◆ DIR_CrtTime10

#define DIR_CrtTime10   13 /* Created time sub-second (BYTE) */

◆ DIR_CrtTime

#define DIR_CrtTime   14 /* Created time (DWORD) */

◆ DIR_LstAccDate

#define DIR_LstAccDate   18 /* Last accessed date (WORD) */

◆ DIR_FstClusHI

#define DIR_FstClusHI   20 /* Higher 16-bit of first cluster (WORD) */

◆ DIR_ModTime

#define DIR_ModTime   22 /* Modified time (DWORD) */

◆ DIR_FstClusLO

#define DIR_FstClusLO   26 /* Lower 16-bit of first cluster (WORD) */

◆ DIR_FileSize

#define DIR_FileSize   28 /* File size (DWORD) */

◆ LDIR_Ord

#define LDIR_Ord   0 /* LFN: LFN order and LLE flag (BYTE) */

◆ LDIR_Attr

#define LDIR_Attr   11 /* LFN: LFN attribute (BYTE) */

◆ LDIR_Type

#define LDIR_Type   12 /* LFN: Entry type (BYTE) */

◆ LDIR_Chksum

#define LDIR_Chksum   13 /* LFN: Checksum of the SFN (BYTE) */

◆ LDIR_FstClusLO

#define LDIR_FstClusLO   26 /* LFN: MBZ field (WORD) */

◆ XDIR_Type

#define XDIR_Type   0 /* exFAT: Type of exFAT directory entry (BYTE) */

◆ XDIR_NumLabel

#define XDIR_NumLabel   1 /* exFAT: Number of volume label characters (BYTE) */

◆ XDIR_Label

#define XDIR_Label   2 /* exFAT: Volume label (11-WORD) */

◆ XDIR_CaseSum

#define XDIR_CaseSum   4 /* exFAT: Sum of case conversion table (DWORD) */

◆ XDIR_NumSec

#define XDIR_NumSec   1 /* exFAT: Number of secondary entries (BYTE) */

◆ XDIR_SetSum

#define XDIR_SetSum   2 /* exFAT: Sum of the set of directory entries (WORD) */

◆ XDIR_Attr

#define XDIR_Attr   4 /* exFAT: File attribute (WORD) */

◆ XDIR_CrtTime

#define XDIR_CrtTime   8 /* exFAT: Created time (DWORD) */

◆ XDIR_ModTime

#define XDIR_ModTime   12 /* exFAT: Modified time (DWORD) */

◆ XDIR_AccTime

#define XDIR_AccTime   16 /* exFAT: Last accessed time (DWORD) */

◆ XDIR_CrtTime10

#define XDIR_CrtTime10   20 /* exFAT: Created time subsecond (BYTE) */

◆ XDIR_ModTime10

#define XDIR_ModTime10   21 /* exFAT: Modified time subsecond (BYTE) */

◆ XDIR_CrtTZ

#define XDIR_CrtTZ   22 /* exFAT: Created timezone (BYTE) */

◆ XDIR_ModTZ

#define XDIR_ModTZ   23 /* exFAT: Modified timezone (BYTE) */

◆ XDIR_AccTZ

#define XDIR_AccTZ   24 /* exFAT: Last accessed timezone (BYTE) */

◆ XDIR_GenFlags

#define XDIR_GenFlags   33 /* exFAT: General secondary flags (WORD) */

◆ XDIR_NumName

#define XDIR_NumName   35 /* exFAT: Number of file name characters (BYTE) */

◆ XDIR_NameHash

#define XDIR_NameHash   36 /* exFAT: Hash of file name (WORD) */

◆ XDIR_ValidFileSize

#define XDIR_ValidFileSize   40 /* exFAT: Valid file size (QWORD) */

◆ XDIR_FstClus

#define XDIR_FstClus   52 /* exFAT: First cluster of the file data (DWORD) */

◆ XDIR_FileSize

#define XDIR_FileSize   56 /* exFAT: File/Directory size (QWORD) */

◆ SZDIRE

#define SZDIRE   32 /* Size of a directory entry */

◆ DDEM

#define DDEM   0xE5 /* Deleted directory entry mark set to DIR_Name[0] */

◆ RDDEM

#define RDDEM   0x05 /* Replacement of the character collides with DDEM */

◆ LLEF

#define LLEF   0x40 /* Last long entry flag in LDIR_Ord */

◆ FSI_LeadSig

#define FSI_LeadSig   0 /* FAT32 FSI: Leading signature (DWORD) */

◆ FSI_StrucSig

#define FSI_StrucSig   484 /* FAT32 FSI: Structure signature (DWORD) */

◆ FSI_Free_Count

#define FSI_Free_Count   488 /* FAT32 FSI: Number of free clusters (DWORD) */

◆ FSI_Nxt_Free

#define FSI_Nxt_Free   492 /* FAT32 FSI: Last allocated cluster (DWORD) */

◆ MBR_Table

#define MBR_Table   446 /* MBR: Offset of partition table in the MBR */

◆ SZ_PTE

#define SZ_PTE   16 /* MBR: Size of a partition table entry */

◆ PTE_Boot

#define PTE_Boot   0 /* MBR PTE: Boot indicator */

◆ PTE_StHead

#define PTE_StHead   1 /* MBR PTE: Start head */

◆ PTE_StSec

#define PTE_StSec   2 /* MBR PTE: Start sector */

◆ PTE_StCyl

#define PTE_StCyl   3 /* MBR PTE: Start cylinder */

◆ PTE_System

#define PTE_System   4 /* MBR PTE: System ID */

◆ PTE_EdHead

#define PTE_EdHead   5 /* MBR PTE: End head */

◆ PTE_EdSec

#define PTE_EdSec   6 /* MBR PTE: End sector */

◆ PTE_EdCyl

#define PTE_EdCyl   7 /* MBR PTE: End cylinder */

◆ PTE_StLba

#define PTE_StLba   8 /* MBR PTE: Start in LBA */

◆ PTE_SizLba

#define PTE_SizLba   12 /* MBR PTE: Size in LBA */

◆ ABORT

#define ABORT (   fs,
  res 
)    { fp->err = (BYTE)(res); LEAVE_FF(fs, res); }

◆ ENTER_FF

#define ENTER_FF (   fs)

◆ LEAVE_FF

#define LEAVE_FF (   fs,
  res 
)    return res

◆ LD2PD

#define LD2PD (   vol)    (BYTE)(vol) /* Each logical drive is bound to the same physical drive number */

◆ LD2PT

#define LD2PT (   vol)    0 /* Find first valid partition or in SFD */

◆ SS

#define SS (   fs)    ((UINT)_MAX_SS) /* Fixed sector size */

◆ GET_FATTIME

#define GET_FATTIME ( )    get_fattime()

◆ DEF_NAMBUF

#define DEF_NAMBUF

◆ INIT_NAMBUF

#define INIT_NAMBUF (   fs)

◆ FREE_NAMBUF

#define FREE_NAMBUF ( )

Function Documentation

◆ ld_word()

static WORD ld_word ( const BYTE ptr)
static
614 {
615  WORD rv;
616 
617  rv = ptr[1];
618  rv = rv << 8 | ptr[0];
619  return rv;
620 }
Here is the caller graph for this function:

◆ ld_dword()

static DWORD ld_dword ( const BYTE ptr)
static
624 {
625  DWORD rv;
626 
627  rv = ptr[3];
628  rv = rv << 8 | ptr[2];
629  rv = rv << 8 | ptr[1];
630  rv = rv << 8 | ptr[0];
631  return rv;
632 }
Here is the caller graph for this function:

◆ st_word()

static void st_word ( BYTE ptr,
WORD  val 
)
static
655 {
656  *ptr++ = (BYTE)val; val >>= 8;
657  *ptr++ = (BYTE)val;
658 }
Here is the caller graph for this function:

◆ st_dword()

static void st_dword ( BYTE ptr,
DWORD  val 
)
static
662 {
663  *ptr++ = (BYTE)val; val >>= 8;
664  *ptr++ = (BYTE)val; val >>= 8;
665  *ptr++ = (BYTE)val; val >>= 8;
666  *ptr++ = (BYTE)val;
667 }
Here is the caller graph for this function:

◆ mem_cpy()

static void mem_cpy ( void dst,
const void src,
UINT  cnt 
)
static
693  {
694  BYTE *d = (BYTE*)dst;
695  const BYTE *s = (const BYTE*)src;
696 
697  if (cnt) {
698  do {
699  *d++ = *s++;
700  } while (--cnt);
701  }
702 }
Here is the caller graph for this function:

◆ mem_set()

static void mem_set ( void dst,
int  val,
UINT  cnt 
)
static
706  {
707  BYTE *d = (BYTE*)dst;
708 
709  do {
710  *d++ = (BYTE)val;
711  } while (--cnt);
712 }
Here is the caller graph for this function:

◆ mem_cmp()

static int mem_cmp ( const void dst,
const void src,
UINT  cnt 
)
static
716  { /* ZR:same, NZ:different */
717  const BYTE *d = (const BYTE *)dst, *s = (const BYTE *)src;
718  int r = 0;
719 
720  do {
721  r = *d++ - *s++;
722  } while (--cnt && r == 0);
723 
724  return r;
725 }
Here is the caller graph for this function:

◆ chk_chr()

static int chk_chr ( const char *  str,
int  chr 
)
static
729  { /* NZ:contained, ZR:not contained */
730  while (*str && *str != chr) str++;
731  return *str;
732 }
Here is the caller graph for this function:

◆ sync_window()

static FRESULT sync_window ( FATFS fs)
static
886 {
887  DWORD wsect;
888  UINT nf;
889  FRESULT res = FR_OK;
890 
891 
892  if (fs->wflag) { /* Write back the sector if it is dirty */
893  wsect = fs->winsect; /* Current sector number */
894  if (disk_write(fs->drv, fs->win, wsect, 1) != RES_OK) {
895  res = FR_DISK_ERR;
896  } else {
897  fs->wflag = 0;
898  if (wsect - fs->fatbase < fs->fsize) { /* Is it in the FAT area? */
899  for (nf = fs->n_fats; nf >= 2; nf--) { /* Reflect the change to all FAT copies */
900  wsect += fs->fsize;
901  disk_write(fs->drv, fs->win, wsect, 1);
902  }
903  }
904  }
905  }
906  return res;
907 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ move_window()

static FRESULT move_window ( FATFS fs,
DWORD  sector 
)
static
916 {
917  FRESULT res = FR_OK;
918 
919 
920  if (sector != fs->winsect) { /* Window offset changed? */
921 #if !_FS_READONLY
922  res = sync_window(fs); /* Write-back changes */
923 #endif
924  if (res == FR_OK) { /* Fill sector window with new data */
925  if (disk_read(fs->drv, fs->win, sector, 1) != RES_OK) {
926  sector = 0xFFFFFFFF; /* Invalidate window if data is not reliable */
927  res = FR_DISK_ERR;
928  }
929  fs->winsect = sector;
930  }
931  }
932  return res;
933 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ sync_fs()

static FRESULT sync_fs ( FATFS fs)
static
947 {
948  FRESULT res;
949 
950 
951  res = sync_window(fs);
952  if (res == FR_OK) {
953  /* Update FSInfo sector if needed */
954  if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) {
955  /* Create FSInfo structure */
956  mem_set(fs->win, 0, SS(fs));
957  st_word(fs->win + BS_55AA, 0xAA55);
958  st_dword(fs->win + FSI_LeadSig, 0x41615252);
959  st_dword(fs->win + FSI_StrucSig, 0x61417272);
960  st_dword(fs->win + FSI_Free_Count, fs->free_clst);
961  st_dword(fs->win + FSI_Nxt_Free, fs->last_clst);
962  /* Write it into the FSInfo sector */
963  fs->winsect = fs->volbase + 1;
964  disk_write(fs->drv, fs->win, fs->winsect, 1);
965  fs->fsi_flag = 0;
966  }
967  /* Make sure that no pending write process in the physical drive */
968  if (disk_ioctl(fs->drv, CTRL_SYNC, 0) != RES_OK) res = FR_DISK_ERR;
969  }
970 
971  return res;
972 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ clust2sect()

static DWORD clust2sect ( FATFS fs,
DWORD  clst 
)
static
987 {
988  clst -= 2;
989  if (clst >= fs->n_fatent - 2) return 0; /* Invalid cluster# */
990  return clst * fs->csize + fs->database;
991 }
Here is the caller graph for this function:

◆ get_fat()

static DWORD get_fat ( _FDID obj,
DWORD  clst 
)
static
1005 {
1006  UINT wc, bc;
1007  DWORD val;
1008  FATFS *fs = obj->fs;
1009 
1010 
1011  if (clst < 2 || clst >= fs->n_fatent) { /* Check if in valid range */
1012  val = 1; /* Internal error */
1013 
1014  } else {
1015  val = 0xFFFFFFFF; /* Default value falls on disk error */
1016 
1017  switch (fs->fs_type) {
1018  case FS_FAT12 :
1019  bc = (UINT)clst; bc += bc / 2;
1020  if (move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK) break;
1021  wc = fs->win[bc++ % SS(fs)];
1022  if (move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK) break;
1023  wc |= fs->win[bc % SS(fs)] << 8;
1024  val = (clst & 1) ? (wc >> 4) : (wc & 0xFFF);
1025  break;
1026 
1027  case FS_FAT16 :
1028  if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))) != FR_OK) break;
1029  val = ld_word(fs->win + clst * 2 % SS(fs));
1030  break;
1031 
1032  case FS_FAT32 :
1033  if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break;
1034  val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x0FFFFFFF;
1035  break;
1036 #if _FS_EXFAT
1037  case FS_EXFAT :
1038  if (obj->objsize) {
1039  DWORD cofs = clst - obj->sclust; /* Offset from start cluster */
1040  DWORD clen = (DWORD)((obj->objsize - 1) / SS(fs)) / fs->csize; /* Number of clusters - 1 */
1041 
1042  if (obj->stat == 2) { /* Is there no valid chain on the FAT? */
1043  if (cofs <= clen) {
1044  val = (cofs == clen) ? 0x7FFFFFFF : clst + 1; /* Generate the value */
1045  break;
1046  }
1047  }
1048  if (obj->stat == 3 && cofs < obj->n_cont) { /* Is it in the 1st fragment? */
1049  val = clst + 1; /* Generate the value */
1050  break;
1051  }
1052  if (obj->stat != 2) { /* Get value from FAT if FAT chain is valid */
1053  if (obj->n_frag != 0) { /* Is it on the growing edge? */
1054  val = 0x7FFFFFFF; /* Generate EOC */
1055  } else {
1056  if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break;
1057  val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x7FFFFFFF;
1058  }
1059  break;
1060  }
1061  }
1062  /* go to default */
1063 #endif
1064  default:
1065  val = 1; /* Internal error */
1066  }
1067  }
1068 
1069  return val;
1070 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ put_fat()

static FRESULT put_fat ( FATFS fs,
DWORD  clst,
DWORD  val 
)
static
1086 {
1087  UINT bc;
1088  BYTE *p;
1089  FRESULT res = FR_INT_ERR;
1090 
1091  if (clst >= 2 && clst < fs->n_fatent) { /* Check if in valid range */
1092  switch (fs->fs_type) {
1093  case FS_FAT12 : /* Bitfield items */
1094  bc = (UINT)clst; bc += bc / 2;
1095  res = move_window(fs, fs->fatbase + (bc / SS(fs)));
1096  if (res != FR_OK) break;
1097  p = fs->win + bc++ % SS(fs);
1098  *p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val;
1099  fs->wflag = 1;
1100  res = move_window(fs, fs->fatbase + (bc / SS(fs)));
1101  if (res != FR_OK) break;
1102  p = fs->win + bc % SS(fs);
1103  *p = (clst & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F));
1104  fs->wflag = 1;
1105  break;
1106 
1107  case FS_FAT16 : /* WORD aligned items */
1108  res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 2)));
1109  if (res != FR_OK) break;
1110  st_word(fs->win + clst * 2 % SS(fs), (WORD)val);
1111  fs->wflag = 1;
1112  break;
1113 
1114  case FS_FAT32 : /* DWORD aligned items */
1115 #if _FS_EXFAT
1116  case FS_EXFAT :
1117 #endif
1118  res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 4)));
1119  if (res != FR_OK) break;
1120  if (!_FS_EXFAT || fs->fs_type != FS_EXFAT) {
1121  val = (val & 0x0FFFFFFF) | (ld_dword(fs->win + clst * 4 % SS(fs)) & 0xF0000000);
1122  }
1123  st_dword(fs->win + clst * 4 % SS(fs), val);
1124  fs->wflag = 1;
1125  break;
1126  }
1127  }
1128  return res;
1129 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ remove_chain()

static FRESULT remove_chain ( _FDID obj,
DWORD  clst,
DWORD  pclst 
)
static
1276 {
1277  FRESULT res = FR_OK;
1278  DWORD nxt;
1279  FATFS *fs = obj->fs;
1280 #if _FS_EXFAT || _USE_TRIM
1281  DWORD scl = clst, ecl = clst;
1282 #endif
1283 #if _USE_TRIM
1284  DWORD rt[2];
1285 #endif
1286 
1287  if (clst < 2 || clst >= fs->n_fatent) return FR_INT_ERR; /* Check if in valid range */
1288 
1289  /* Mark the previous cluster 'EOC' on the FAT if it exists */
1290  if (pclst && (!_FS_EXFAT || fs->fs_type != FS_EXFAT || obj->stat != 2)) {
1291  res = put_fat(fs, pclst, 0xFFFFFFFF);
1292  if (res != FR_OK) return res;
1293  }
1294 
1295  /* Remove the chain */
1296  do {
1297  nxt = get_fat(obj, clst); /* Get cluster status */
1298  if (nxt == 0) break; /* Empty cluster? */
1299  if (nxt == 1) return FR_INT_ERR; /* Internal error? */
1300  if (nxt == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error? */
1301  if (!_FS_EXFAT || fs->fs_type != FS_EXFAT) {
1302  res = put_fat(fs, clst, 0); /* Mark the cluster 'free' on the FAT */
1303  if (res != FR_OK) return res;
1304  }
1305  if (fs->free_clst < fs->n_fatent - 2) { /* Update FSINFO */
1306  fs->free_clst++;
1307  fs->fsi_flag |= 1;
1308  }
1309 #if _FS_EXFAT || _USE_TRIM
1310  if (ecl + 1 == nxt) { /* Is next cluster contiguous? */
1311  ecl = nxt;
1312  } else { /* End of contiguous cluster block */
1313 #if _FS_EXFAT
1314  if (fs->fs_type == FS_EXFAT) {
1315  res = change_bitmap(fs, scl, ecl - scl + 1, 0); /* Mark the cluster block 'free' on the bitmap */
1316  if (res != FR_OK) return res;
1317  }
1318 #endif
1319 #if _USE_TRIM
1320  rt[0] = clust2sect(fs, scl); /* Start sector */
1321  rt[1] = clust2sect(fs, ecl) + fs->csize - 1; /* End sector */
1322  disk_ioctl(fs->drv, CTRL_TRIM, rt); /* Inform device the block can be erased */
1323 #endif
1324  scl = ecl = nxt;
1325  }
1326 #endif
1327  clst = nxt; /* Next cluster */
1328  } while (clst < fs->n_fatent); /* Repeat while not the last link */
1329 
1330 #if _FS_EXFAT
1331  if (fs->fs_type == FS_EXFAT) {
1332  if (pclst == 0) { /* Does the object have no chain? */
1333  obj->stat = 0; /* Change the object status 'initial' */
1334  } else {
1335  if (obj->stat == 3 && pclst >= obj->sclust && pclst <= obj->sclust + obj->n_cont) { /* Did the chain get contiguous? */
1336  obj->stat = 2; /* Change the object status 'contiguous' */
1337  }
1338  }
1339  }
1340 #endif
1341  return FR_OK;
1342 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ create_chain()

static DWORD create_chain ( _FDID obj,
DWORD  clst 
)
static
1355 {
1356  DWORD cs, ncl, scl;
1357  FRESULT res;
1358  FATFS *fs = obj->fs;
1359 
1360 
1361  if (clst == 0) { /* Create a new chain */
1362  scl = fs->last_clst; /* Get suggested cluster to start from */
1363  if (scl == 0 || scl >= fs->n_fatent) scl = 1;
1364  }
1365  else { /* Stretch current chain */
1366  cs = get_fat(obj, clst); /* Check the cluster status */
1367  if (cs < 2) return 1; /* Invalid FAT value */
1368  if (cs == 0xFFFFFFFF) return cs; /* A disk error occurred */
1369  if (cs < fs->n_fatent) return cs; /* It is already followed by next cluster */
1370  scl = clst;
1371  }
1372 
1373 #if _FS_EXFAT
1374  if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */
1375  ncl = find_bitmap(fs, scl, 1); /* Find a free cluster */
1376  if (ncl == 0 || ncl == 0xFFFFFFFF) return ncl; /* No free cluster or hard error? */
1377  res = change_bitmap(fs, ncl, 1, 1); /* Mark the cluster 'in use' */
1378  if (res == FR_INT_ERR) return 1;
1379  if (res == FR_DISK_ERR) return 0xFFFFFFFF;
1380  if (clst == 0) { /* Is it a new chain? */
1381  obj->stat = 2; /* Set status 'contiguous' */
1382  } else { /* It is a stretched chain */
1383  if (obj->stat == 2 && ncl != scl + 1) { /* Is the chain got fragmented? */
1384  obj->n_cont = scl - obj->sclust; /* Set size of the contiguous part */
1385  obj->stat = 3; /* Change status 'just fragmented' */
1386  }
1387  }
1388  if (obj->stat != 2) { /* Is the file non-contiguous? */
1389  if (ncl == clst + 1) { /* Is the cluster next to previous one? */
1390  obj->n_frag = obj->n_frag ? obj->n_frag + 1 : 2; /* Increment size of last framgent */
1391  } else { /* New fragment */
1392  if (obj->n_frag == 0) obj->n_frag = 1;
1393  res = fill_last_frag(obj, clst, ncl); /* Fill last fragment on the FAT and link it to new one */
1394  if (res == FR_OK) obj->n_frag = 1;
1395  }
1396  }
1397  } else
1398 #endif
1399  { /* On the FAT12/16/32 volume */
1400  ncl = scl; /* Start cluster */
1401  for (;;) {
1402  ncl++; /* Next cluster */
1403  if (ncl >= fs->n_fatent) { /* Check wrap-around */
1404  ncl = 2;
1405  if (ncl > scl) return 0; /* No free cluster */
1406  }
1407  cs = get_fat(obj, ncl); /* Get the cluster status */
1408  if (cs == 0) break; /* Found a free cluster */
1409  if (cs == 1 || cs == 0xFFFFFFFF) return cs; /* An error occurred */
1410  if (ncl == scl) return 0; /* No free cluster */
1411  }
1412  res = put_fat(fs, ncl, 0xFFFFFFFF); /* Mark the new cluster 'EOC' */
1413  if (res == FR_OK && clst != 0) {
1414  res = put_fat(fs, clst, ncl); /* Link it from the previous one if needed */
1415  }
1416  }
1417 
1418  if (res == FR_OK) { /* Update FSINFO if function succeeded. */
1419  fs->last_clst = ncl;
1420  if (fs->free_clst <= fs->n_fatent - 2) fs->free_clst--;
1421  fs->fsi_flag |= 1;
1422  } else {
1423  ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1; /* Failed. Generate error status */
1424  }
1425 
1426  return ncl; /* Return new cluster number or error status */
1427 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ dir_sdi()

static FRESULT dir_sdi ( DIR dp,
DWORD  ofs 
)
static
1474 {
1475  DWORD csz, clst;
1476  FATFS *fs = dp->obj.fs;
1477 
1478 
1479  if (ofs >= (DWORD)((_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR) || ofs % SZDIRE) { /* Check range of offset and alignment */
1480  return FR_INT_ERR;
1481  }
1482  dp->dptr = ofs; /* Set current offset */
1483  clst = dp->obj.sclust; /* Table start cluster (0:root) */
1484  if (clst == 0 && fs->fs_type >= FS_FAT32) { /* Replace cluster# 0 with root cluster# */
1485  clst = fs->dirbase;
1486  if (_FS_EXFAT) dp->obj.stat = 0; /* exFAT: Root dir has an FAT chain */
1487  }
1488 
1489  if (clst == 0) { /* Static table (root-directory in FAT12/16) */
1490  if (ofs / SZDIRE >= fs->n_rootdir) return FR_INT_ERR; /* Is index out of range? */
1491  dp->sect = fs->dirbase;
1492 
1493  } else { /* Dynamic table (sub-directory or root-directory in FAT32+) */
1494  csz = (DWORD)fs->csize * SS(fs); /* Bytes per cluster */
1495  while (ofs >= csz) { /* Follow cluster chain */
1496  clst = get_fat(&dp->obj, clst); /* Get next cluster */
1497  if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */
1498  if (clst < 2 || clst >= fs->n_fatent) return FR_INT_ERR; /* Reached to end of table or internal error */
1499  ofs -= csz;
1500  }
1501  dp->sect = clust2sect(fs, clst);
1502  }
1503  dp->clust = clst; /* Current cluster# */
1504  if (!dp->sect) return FR_INT_ERR;
1505  dp->sect += ofs / SS(fs); /* Sector# of the directory entry */
1506  dp->dir = fs->win + (ofs % SS(fs)); /* Pointer to the entry in the win[] */
1507 
1508  return FR_OK;
1509 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ dir_next()

static FRESULT dir_next ( DIR dp,
int  stretch 
)
static
1523 {
1524  DWORD ofs, clst;
1525  FATFS *fs = dp->obj.fs;
1526 #if !_FS_READONLY
1527  UINT n;
1528 #endif
1529 
1530  ofs = dp->dptr + SZDIRE; /* Next entry */
1531  if (!dp->sect || ofs >= (DWORD)((_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR)) return FR_NO_FILE; /* Report EOT when offset has reached max value */
1532 
1533  if (ofs % SS(fs) == 0) { /* Sector changed? */
1534  dp->sect++; /* Next sector */
1535 
1536  if (!dp->clust) { /* Static table */
1537  if (ofs / SZDIRE >= fs->n_rootdir) { /* Report EOT if it reached end of static table */
1538  dp->sect = 0; return FR_NO_FILE;
1539  }
1540  }
1541  else { /* Dynamic table */
1542  if ((ofs / SS(fs) & (fs->csize - 1)) == 0) { /* Cluster changed? */
1543  clst = get_fat(&dp->obj, dp->clust); /* Get next cluster */
1544  if (clst <= 1) return FR_INT_ERR; /* Internal error */
1545  if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */
1546  if (clst >= fs->n_fatent) { /* Reached end of dynamic table */
1547 #if !_FS_READONLY
1548  if (!stretch) { /* If no stretch, report EOT */
1549  dp->sect = 0; return FR_NO_FILE;
1550  }
1551  clst = create_chain(&dp->obj, dp->clust); /* Allocate a cluster */
1552  if (clst == 0) return FR_DENIED; /* No free cluster */
1553  if (clst == 1) return FR_INT_ERR; /* Internal error */
1554  if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */
1555  /* Clean-up the stretched table */
1556  if (_FS_EXFAT) dp->obj.stat |= 4; /* The directory needs to be updated */
1557  if (sync_window(fs) != FR_OK) return FR_DISK_ERR; /* Flush disk access window */
1558  mem_set(fs->win, 0, SS(fs)); /* Clear window buffer */
1559  for (n = 0, fs->winsect = clust2sect(fs, clst); n < fs->csize; n++, fs->winsect++) { /* Fill the new cluster with 0 */
1560  fs->wflag = 1;
1561  if (sync_window(fs) != FR_OK) return FR_DISK_ERR;
1562  }
1563  fs->winsect -= n; /* Restore window offset */
1564 #else
1565  if (!stretch) dp->sect = 0; /* (this line is to suppress compiler warning) */
1566  dp->sect = 0; return FR_NO_FILE; /* Report EOT */
1567 #endif
1568  }
1569  dp->clust = clst; /* Initialize data for new cluster */
1570  dp->sect = clust2sect(fs, clst);
1571  }
1572  }
1573  }
1574  dp->dptr = ofs; /* Current entry */
1575  dp->dir = fs->win + ofs % SS(fs); /* Pointer to the entry in the win[] */
1576 
1577  return FR_OK;
1578 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ dir_alloc()

static FRESULT dir_alloc ( DIR dp,
UINT  nent 
)
static
1593 {
1594  FRESULT res;
1595  UINT n;
1596  FATFS *fs = dp->obj.fs;
1597 
1598 
1599  res = dir_sdi(dp, 0);
1600  if (res == FR_OK) {
1601  n = 0;
1602  do {
1603  res = move_window(fs, dp->sect);
1604  if (res != FR_OK) break;
1605 #if _FS_EXFAT
1606  if ((fs->fs_type == FS_EXFAT) ? (int)((dp->dir[XDIR_Type] & 0x80) == 0) : (int)(dp->dir[DIR_Name] == DDEM || dp->dir[DIR_Name] == 0)) {
1607 #else
1608  if (dp->dir[DIR_Name] == DDEM || dp->dir[DIR_Name] == 0) {
1609 #endif
1610  if (++n == nent) break; /* A block of contiguous free entries is found */
1611  } else {
1612  n = 0; /* Not a blank entry. Restart to search */
1613  }
1614  res = dir_next(dp, 1);
1615  } while (res == FR_OK); /* Next entry with table stretch enabled */
1616  }
1617 
1618  if (res == FR_NO_FILE) res = FR_DENIED; /* No directory entry to allocate */
1619  return res;
1620 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ld_clust()

static DWORD ld_clust ( FATFS fs,
const BYTE dir 
)
static
1636 {
1637  DWORD cl;
1638 
1639  cl = ld_word(dir + DIR_FstClusLO);
1640  if (fs->fs_type == FS_FAT32) {
1641  cl |= (DWORD)ld_word(dir + DIR_FstClusHI) << 16;
1642  }
1643 
1644  return cl;
1645 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ st_clust()

static void st_clust ( FATFS fs,
BYTE dir,
DWORD  cl 
)
static
1655 {
1656  st_word(dir + DIR_FstClusLO, (WORD)cl);
1657  if (fs->fs_type == FS_FAT32) {
1658  st_word(dir + DIR_FstClusHI, (WORD)(cl >> 16));
1659  }
1660 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ dir_read()

static FRESULT dir_read ( DIR dp,
int  vol 
)
static
2135 {
2136  FRESULT res = FR_NO_FILE;
2137  FATFS *fs = dp->obj.fs;
2138  BYTE a, c;
2139 #if _USE_LFN != 0
2140  BYTE ord = 0xFF, sum = 0xFF;
2141 #endif
2142 
2143  while (dp->sect) {
2144  res = move_window(fs, dp->sect);
2145  if (res != FR_OK) break;
2146  c = dp->dir[DIR_Name]; /* Test for the entry type */
2147  if (c == 0) {
2148  res = FR_NO_FILE; break; /* Reached to end of the directory */
2149  }
2150 #if _FS_EXFAT
2151  if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */
2152  if (_USE_LABEL && vol) {
2153  if (c == 0x83) break; /* Volume label entry? */
2154  } else {
2155  if (c == 0x85) { /* Start of the file entry block? */
2156  dp->blk_ofs = dp->dptr; /* Get location of the block */
2157  res = load_xdir(dp); /* Load the entry block */
2158  if (res == FR_OK) {
2159  dp->obj.attr = fs->dirbuf[XDIR_Attr] & AM_MASK; /* Get attribute */
2160  }
2161  break;
2162  }
2163  }
2164  } else
2165 #endif
2166  { /* On the FAT12/16/32 volume */
2167  dp->obj.attr = a = dp->dir[DIR_Attr] & AM_MASK; /* Get attribute */
2168 #if _USE_LFN != 0 /* LFN configuration */
2169  if (c == DDEM || c == '.' || (int)((a & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */
2170  ord = 0xFF;
2171  } else {
2172  if (a == AM_LFN) { /* An LFN entry is found */
2173  if (c & LLEF) { /* Is it start of an LFN sequence? */
2174  sum = dp->dir[LDIR_Chksum];
2175  c &= (BYTE)~LLEF; ord = c;
2176  dp->blk_ofs = dp->dptr;
2177  }
2178  /* Check LFN validity and capture it */
2179  ord = (c == ord && sum == dp->dir[LDIR_Chksum] && pick_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF;
2180  } else { /* An SFN entry is found */
2181  if (ord || sum != sum_sfn(dp->dir)) { /* Is there a valid LFN? */
2182  dp->blk_ofs = 0xFFFFFFFF; /* It has no LFN. */
2183  }
2184  break;
2185  }
2186  }
2187 #else /* Non LFN configuration */
2188  if (c != DDEM && c != '.' && a != AM_LFN && (int)((a & ~AM_ARC) == AM_VOL) == vol) { /* Is it a valid entry? */
2189  break;
2190  }
2191 #endif
2192  }
2193  res = dir_next(dp, 0); /* Next entry */
2194  if (res != FR_OK) break;
2195  }
2196 
2197  if (res != FR_OK) dp->sect = 0; /* Terminate the read operation on error or EOT */
2198  return res;
2199 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ dir_find()

static FRESULT dir_find ( DIR dp)
static
2213 {
2214  FRESULT res;
2215  FATFS *fs = dp->obj.fs;
2216  BYTE c;
2217 #if _USE_LFN != 0
2218  BYTE a, ord, sum;
2219 #endif
2220 
2221  res = dir_sdi(dp, 0); /* Rewind directory object */
2222  if (res != FR_OK) return res;
2223 #if _FS_EXFAT
2224  if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */
2225  BYTE nc;
2226  UINT di, ni;
2227  WORD hash = xname_sum(fs->lfnbuf); /* Hash value of the name to find */
2228 
2229  while ((res = dir_read(dp, 0)) == FR_OK) { /* Read an item */
2230 #if _MAX_LFN < 255
2231  if (fs->dirbuf[XDIR_NumName] > _MAX_LFN) continue; /* Skip comparison if inaccessible object name */
2232 #endif
2233  if (ld_word(fs->dirbuf + XDIR_NameHash) != hash) continue; /* Skip comparison if hash mismatched */
2234  for (nc = fs->dirbuf[XDIR_NumName], di = SZDIRE * 2, ni = 0; nc; nc--, di += 2, ni++) { /* Compare the name */
2235  if ((di % SZDIRE) == 0) di += 2;
2236  if (ff_wtoupper(ld_word(fs->dirbuf + di)) != ff_wtoupper(fs->lfnbuf[ni])) break;
2237  }
2238  if (nc == 0 && !fs->lfnbuf[ni]) break; /* Name matched? */
2239  }
2240  return res;
2241  }
2242 #endif
2243  /* On the FAT12/16/32 volume */
2244 #if _USE_LFN != 0
2245  ord = sum = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */
2246 #endif
2247  do {
2248  res = move_window(fs, dp->sect);
2249  if (res != FR_OK) break;
2250  c = dp->dir[DIR_Name];
2251  if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */
2252 #if _USE_LFN != 0 /* LFN configuration */
2253  dp->obj.attr = a = dp->dir[DIR_Attr] & AM_MASK;
2254  if (c == DDEM || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */
2255  ord = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */
2256  } else {
2257  if (a == AM_LFN) { /* An LFN entry is found */
2258  if (!(dp->fn[NSFLAG] & NS_NOLFN)) {
2259  if (c & LLEF) { /* Is it start of LFN sequence? */
2260  sum = dp->dir[LDIR_Chksum];
2261  c &= (BYTE)~LLEF; ord = c; /* LFN start order */
2262  dp->blk_ofs = dp->dptr; /* Start offset of LFN */
2263  }
2264  /* Check validity of the LFN entry and compare it with given name */
2265  ord = (c == ord && sum == dp->dir[LDIR_Chksum] && cmp_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF;
2266  }
2267  } else { /* An SFN entry is found */
2268  if (!ord && sum == sum_sfn(dp->dir)) break; /* LFN matched? */
2269  if (!(dp->fn[NSFLAG] & NS_LOSS) && !mem_cmp(dp->dir, dp->fn, 11)) break; /* SFN matched? */
2270  ord = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */
2271  }
2272  }
2273 #else /* Non LFN configuration */
2274  dp->obj.attr = dp->dir[DIR_Attr] & AM_MASK;
2275  if (!(dp->dir[DIR_Attr] & AM_VOL) && !mem_cmp(dp->dir, dp->fn, 11)) break; /* Is it a valid entry? */
2276 #endif
2277  res = dir_next(dp, 0); /* Next entry */
2278  } while (res == FR_OK);
2279 
2280  return res;
2281 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ dir_register()

static FRESULT dir_register ( DIR dp)
static
2295 {
2296  FRESULT res;
2297  FATFS *fs = dp->obj.fs;
2298 #if _USE_LFN != 0 /* LFN configuration */
2299  UINT n, nlen, nent;
2300  BYTE sn[12], sum;
2301 
2302 
2303  if (dp->fn[NSFLAG] & (NS_DOT | NS_NONAME)) return FR_INVALID_NAME; /* Check name validity */
2304  for (nlen = 0; fs->lfnbuf[nlen]; nlen++) ; /* Get lfn length */
2305 
2306 #if _FS_EXFAT
2307  if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */
2308  DIR dj;
2309 
2310  nent = (nlen + 14) / 15 + 2; /* Number of entries to allocate (85+C0+C1s) */
2311  res = dir_alloc(dp, nent); /* Allocate entries */
2312  if (res != FR_OK) return res;
2313  dp->blk_ofs = dp->dptr - SZDIRE * (nent - 1); /* Set the allocated entry block offset */
2314 
2315  if (dp->obj.sclust != 0 && (dp->obj.stat & 4)) { /* Has the sub-directory been stretched? */
2316  dp->obj.objsize += (DWORD)fs->csize * SS(fs); /* Increase the directory size by cluster size */
2317  res = fill_first_frag(&dp->obj); /* Fill first fragment on the FAT if needed */
2318  if (res != FR_OK) return res;
2319  res = fill_last_frag(&dp->obj, dp->clust, 0xFFFFFFFF); /* Fill last fragment on the FAT if needed */
2320  if (res != FR_OK) return res;
2321  res = load_obj_dir(&dj, &dp->obj); /* Load the object status */
2322  if (res != FR_OK) return res;
2323  st_qword(fs->dirbuf + XDIR_FileSize, dp->obj.objsize); /* Update the allocation status */
2324  st_qword(fs->dirbuf + XDIR_ValidFileSize, dp->obj.objsize);
2325  fs->dirbuf[XDIR_GenFlags] = dp->obj.stat | 1;
2326  res = store_xdir(&dj); /* Store the object status */
2327  if (res != FR_OK) return res;
2328  }
2329 
2330  create_xdir(fs->dirbuf, fs->lfnbuf); /* Create on-memory directory block to be written later */
2331  return FR_OK;
2332  }
2333 #endif
2334  /* On the FAT12/16/32 volume */
2335  mem_cpy(sn, dp->fn, 12);
2336  if (sn[NSFLAG] & NS_LOSS) { /* When LFN is out of 8.3 format, generate a numbered name */
2337  dp->fn[NSFLAG] = NS_NOLFN; /* Find only SFN */
2338  for (n = 1; n < 100; n++) {
2339  gen_numname(dp->fn, sn, fs->lfnbuf, n); /* Generate a numbered name */
2340  res = dir_find(dp); /* Check if the name collides with existing SFN */
2341  if (res != FR_OK) break;
2342  }
2343  if (n == 100) return FR_DENIED; /* Abort if too many collisions */
2344  if (res != FR_NO_FILE) return res; /* Abort if the result is other than 'not collided' */
2345  dp->fn[NSFLAG] = sn[NSFLAG];
2346  }
2347 
2348  /* Create an SFN with/without LFNs. */
2349  nent = (sn[NSFLAG] & NS_LFN) ? (nlen + 12) / 13 + 1 : 1; /* Number of entries to allocate */
2350  res = dir_alloc(dp, nent); /* Allocate entries */
2351  if (res == FR_OK && --nent) { /* Set LFN entry if needed */
2352  res = dir_sdi(dp, dp->dptr - nent * SZDIRE);
2353  if (res == FR_OK) {
2354  sum = sum_sfn(dp->fn); /* Checksum value of the SFN tied to the LFN */
2355  do { /* Store LFN entries in bottom first */
2356  res = move_window(fs, dp->sect);
2357  if (res != FR_OK) break;
2358  put_lfn(fs->lfnbuf, dp->dir, (BYTE)nent, sum);
2359  fs->wflag = 1;
2360  res = dir_next(dp, 0); /* Next entry */
2361  } while (res == FR_OK && --nent);
2362  }
2363  }
2364 
2365 #else /* Non LFN configuration */
2366  res = dir_alloc(dp, 1); /* Allocate an entry for SFN */
2367 
2368 #endif
2369 
2370  /* Set SFN entry */
2371  if (res == FR_OK) {
2372  res = move_window(fs, dp->sect);
2373  if (res == FR_OK) {
2374  mem_set(dp->dir, 0, SZDIRE); /* Clean the entry */
2375  mem_cpy(dp->dir + DIR_Name, dp->fn, 11); /* Put SFN */
2376 #if _USE_LFN != 0
2377  dp->dir[DIR_NTres] = dp->fn[NSFLAG] & (NS_BODY | NS_EXT); /* Put NT flag */
2378 #endif
2379  fs->wflag = 1;
2380  }
2381  }
2382 
2383  return res;
2384 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ dir_remove()

static FRESULT dir_remove ( DIR dp)
static
2399 {
2400  FRESULT res;
2401  FATFS *fs = dp->obj.fs;
2402 #if _USE_LFN != 0 /* LFN configuration */
2403  DWORD last = dp->dptr;
2404 
2405  res = (dp->blk_ofs == 0xFFFFFFFF) ? FR_OK : dir_sdi(dp, dp->blk_ofs); /* Goto top of the entry block if LFN is exist */
2406  if (res == FR_OK) {
2407  do {
2408  res = move_window(fs, dp->sect);
2409  if (res != FR_OK) break;
2410  /* Mark an entry 'deleted' */
2411  if (_FS_EXFAT && fs->fs_type == FS_EXFAT) { /* On the exFAT volume */
2412  dp->dir[XDIR_Type] &= 0x7F;
2413  } else { /* On the FAT12/16/32 volume */
2414  dp->dir[DIR_Name] = DDEM;
2415  }
2416  fs->wflag = 1;
2417  if (dp->dptr >= last) break; /* If reached last entry then all entries of the object has been deleted. */
2418  res = dir_next(dp, 0); /* Next entry */
2419  } while (res == FR_OK);
2420  if (res == FR_NO_FILE) res = FR_INT_ERR;
2421  }
2422 #else /* Non LFN configuration */
2423 
2424  res = move_window(fs, dp->sect);
2425  if (res == FR_OK) {
2426  dp->dir[DIR_Name] = DDEM;
2427  fs->wflag = 1;
2428  }
2429 #endif
2430 
2431  return res;
2432 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_fileinfo()

static void get_fileinfo ( DIR dp,
FILINFO fno 
)
static
2448 {
2449  UINT i, j;
2450  TCHAR c;
2451  DWORD tm;
2452 #if _USE_LFN != 0
2453  WCHAR w, lfv;
2454  FATFS *fs = dp->obj.fs;
2455 #endif
2456 
2457 
2458  fno->fname[0] = 0; /* Invaidate file info */
2459  if (!dp->sect) return; /* Exit if read pointer has reached end of directory */
2460 
2461 #if _USE_LFN != 0 /* LFN configuration */
2462 #if _FS_EXFAT
2463  if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */
2464  get_xdir_info(fs->dirbuf, fno);
2465  return;
2466  } else
2467 #endif
2468  { /* On the FAT12/16/32 volume */
2469  if (dp->blk_ofs != 0xFFFFFFFF) { /* Get LFN if available */
2470  i = j = 0;
2471  while ((w = fs->lfnbuf[j++]) != 0) { /* Get an LFN character */
2472 #if !_LFN_UNICODE
2473  w = ff_convert(w, 0); /* Unicode -> OEM */
2474  if (w == 0) { i = 0; break; } /* No LFN if it could not be converted */
2475  if (_DF1S && w >= 0x100) { /* Put 1st byte if it is a DBC (always false at SBCS cfg) */
2476  fno->fname[i++] = (char)(w >> 8);
2477  }
2478 #endif
2479  if (i >= _MAX_LFN) { i = 0; break; } /* No LFN if buffer overflow */
2480  fno->fname[i++] = (TCHAR)w;
2481  }
2482  fno->fname[i] = 0; /* Terminate the LFN */
2483  }
2484  }
2485 
2486  i = j = 0;
2487  lfv = fno->fname[i]; /* LFN is exist if non-zero */
2488  while (i < 11) { /* Copy name body and extension */
2489  c = (TCHAR)dp->dir[i++];
2490  if (c == ' ') continue; /* Skip padding spaces */
2491  if (c == RDDEM) c = (TCHAR)DDEM; /* Restore replaced DDEM character */
2492  if (i == 9) { /* Insert a . if extension is exist */
2493  if (!lfv) fno->fname[j] = '.';
2494  fno->altname[j++] = '.';
2495  }
2496 #if _LFN_UNICODE
2497  if (IsDBCS1(c) && i != 8 && i != 11 && IsDBCS2(dp->dir[i])) {
2498  c = c << 8 | dp->dir[i++];
2499  }
2500  c = ff_convert(c, 1); /* OEM -> Unicode */
2501  if (!c) c = '?';
2502 #endif
2503  fno->altname[j] = c;
2504  if (!lfv) {
2505  if (IsUpper(c) && (dp->dir[DIR_NTres] & ((i >= 9) ? NS_EXT : NS_BODY))) {
2506  c += 0x20; /* To lower */
2507  }
2508  fno->fname[j] = c;
2509  }
2510  j++;
2511  }
2512  if (!lfv) {
2513  fno->fname[j] = 0;
2514  if (!dp->dir[DIR_NTres]) j = 0; /* Altname is no longer needed if neither LFN nor case info is exist. */
2515  }
2516  fno->altname[j] = 0; /* Terminate the SFN */
2517 
2518 #else /* Non-LFN configuration */
2519  i = j = 0;
2520  while (i < 11) { /* Copy name body and extension */
2521  c = (TCHAR)dp->dir[i++];
2522  if (c == ' ') continue; /* Skip padding spaces */
2523  if (c == RDDEM) c = (TCHAR)DDEM; /* Restore replaced DDEM character */
2524  if (i == 9) fno->fname[j++] = '.'; /* Insert a . if extension is exist */
2525  fno->fname[j++] = c;
2526  }
2527  fno->fname[j] = 0;
2528 #endif
2529 
2530  fno->fattrib = dp->dir[DIR_Attr]; /* Attribute */
2531  fno->fsize = ld_dword(dp->dir + DIR_FileSize); /* Size */
2532  tm = ld_dword(dp->dir + DIR_ModTime); /* Timestamp */
2533  fno->ftime = (WORD)tm; fno->fdate = (WORD)(tm >> 16);
2534 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ create_name()

static FRESULT create_name ( DIR dp,
const TCHAR **  path 
)
static
2621 {
2622 #if _USE_LFN != 0 /* LFN configuration */
2623  BYTE b, cf;
2624  WCHAR w, *lfn;
2625  UINT i, ni, si, di;
2626  const TCHAR *p;
2627 
2628  /* Create LFN in Unicode */
2629  p = *path; lfn = dp->obj.fs->lfnbuf; si = di = 0;
2630  for (;;) {
2631  w = p[si++]; /* Get a character */
2632  if (w < ' ') break; /* Break if end of the path name */
2633  if (w == '/' || w == '\\') { /* Break if a separator is found */
2634  while (p[si] == '/' || p[si] == '\\') si++; /* Skip duplicated separator if exist */
2635  break;
2636  }
2637  if (di >= _MAX_LFN) return FR_INVALID_NAME; /* Reject too long name */
2638 #if !_LFN_UNICODE
2639  w &= 0xFF;
2640  if (IsDBCS1(w)) { /* Check if it is a DBC 1st byte (always false on SBCS cfg) */
2641  b = (BYTE)p[si++]; /* Get 2nd byte */
2642  w = (w << 8) + b; /* Create a DBC */
2643  if (!IsDBCS2(b)) return FR_INVALID_NAME; /* Reject invalid sequence */
2644  }
2645  w = ff_convert(w, 1); /* Convert ANSI/OEM to Unicode */
2646  if (!w) return FR_INVALID_NAME; /* Reject invalid code */
2647 #endif
2648  if (w < 0x80 && chk_chr("\"*:<>\?|\x7F", w)) return FR_INVALID_NAME; /* Reject illegal characters for LFN */
2649  lfn[di++] = w; /* Store the Unicode character */
2650  }
2651  *path = &p[si]; /* Return pointer to the next segment */
2652  cf = (w < ' ') ? NS_LAST : 0; /* Set last segment flag if end of the path */
2653 #if _FS_RPATH != 0
2654  if ((di == 1 && lfn[di - 1] == '.') ||
2655  (di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) { /* Is this segment a dot name? */
2656  lfn[di] = 0;
2657  for (i = 0; i < 11; i++) /* Create dot name for SFN entry */
2658  dp->fn[i] = (i < di) ? '.' : ' ';
2659  dp->fn[i] = cf | NS_DOT; /* This is a dot entry */
2660  return FR_OK;
2661  }
2662 #endif
2663  while (di) { /* Snip off trailing spaces and dots if exist */
2664  w = lfn[di - 1];
2665  if (w != ' ' && w != '.') break;
2666  di--;
2667  }
2668  lfn[di] = 0; /* LFN is created */
2669  if (di == 0) return FR_INVALID_NAME; /* Reject nul name */
2670 
2671  /* Create SFN in directory form */
2672  mem_set(dp->fn, ' ', 11);
2673  for (si = 0; lfn[si] == ' ' || lfn[si] == '.'; si++) ; /* Strip leading spaces and dots */
2674  if (si) cf |= NS_LOSS | NS_LFN;
2675  while (di && lfn[di - 1] != '.') di--; /* Find extension (di<=si: no extension) */
2676 
2677  i = b = 0; ni = 8;
2678  for (;;) {
2679  w = lfn[si++]; /* Get an LFN character */
2680  if (!w) break; /* Break on end of the LFN */
2681  if (w == ' ' || (w == '.' && si != di)) { /* Remove spaces and dots */
2682  cf |= NS_LOSS | NS_LFN; continue;
2683  }
2684 
2685  if (i >= ni || si == di) { /* Extension or end of SFN */
2686  if (ni == 11) { /* Long extension */
2687  cf |= NS_LOSS | NS_LFN; break;
2688  }
2689  if (si != di) cf |= NS_LOSS | NS_LFN; /* Out of 8.3 format */
2690  if (si > di) break; /* No extension */
2691  si = di; i = 8; ni = 11; /* Enter extension section */
2692  b <<= 2; continue;
2693  }
2694 
2695  if (w >= 0x80) { /* Non ASCII character */
2696 #ifdef _EXCVT
2697  w = ff_convert(w, 0); /* Unicode -> OEM code */
2698  if (w) w = ExCvt[w - 0x80]; /* Convert extended character to upper (SBCS) */
2699 #else
2700  w = ff_convert(ff_wtoupper(w), 0); /* Upper converted Unicode -> OEM code */
2701 #endif
2702  cf |= NS_LFN; /* Force create LFN entry */
2703  }
2704 
2705  if (_DF1S && w >= 0x100) { /* Is this DBC? (always false at SBCS cfg) */
2706  if (i >= ni - 1) {
2707  cf |= NS_LOSS | NS_LFN; i = ni; continue;
2708  }
2709  dp->fn[i++] = (BYTE)(w >> 8);
2710  } else { /* SBC */
2711  if (!w || chk_chr("+,;=[]", w)) { /* Replace illegal characters for SFN */
2712  w = '_'; cf |= NS_LOSS | NS_LFN;/* Lossy conversion */
2713  } else {
2714  if (IsUpper(w)) { /* ASCII large capital */
2715  b |= 2;
2716  } else {
2717  if (IsLower(w)) { /* ASCII small capital */
2718  b |= 1; w -= 0x20;
2719  }
2720  }
2721  }
2722  }
2723  dp->fn[i++] = (BYTE)w;
2724  }
2725 
2726  if (dp->fn[0] == DDEM) dp->fn[0] = RDDEM; /* If the first character collides with DDEM, replace it with RDDEM */
2727 
2728  if (ni == 8) b <<= 2;
2729  if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03) cf |= NS_LFN; /* Create LFN entry when there are composite capitals */
2730  if (!(cf & NS_LFN)) { /* When LFN is in 8.3 format without extended character, NT flags are created */
2731  if ((b & 0x03) == 0x01) cf |= NS_EXT; /* NT flag (Extension has only small capital) */
2732  if ((b & 0x0C) == 0x04) cf |= NS_BODY; /* NT flag (Filename has only small capital) */
2733  }
2734 
2735  dp->fn[NSFLAG] = cf; /* SFN is created */
2736 
2737  return FR_OK;
2738 
2739 
2740 #else /* _USE_LFN != 0 : Non-LFN configuration */
2741  BYTE c, d, *sfn;
2742  UINT ni, si, i;
2743  const char *p;
2744 
2745  /* Create file name in directory form */
2746  p = *path; sfn = dp->fn;
2747  mem_set(sfn, ' ', 11);
2748  si = i = 0; ni = 8;
2749 #if _FS_RPATH != 0
2750  if (p[si] == '.') { /* Is this a dot entry? */
2751  for (;;) {
2752  c = (BYTE)p[si++];
2753  if (c != '.' || si >= 3) break;
2754  sfn[i++] = c;
2755  }
2756  if (c != '/' && c != '\\' && c > ' ') return FR_INVALID_NAME;
2757  *path = p + si; /* Return pointer to the next segment */
2758  sfn[NSFLAG] = (c <= ' ') ? NS_LAST | NS_DOT : NS_DOT; /* Set last segment flag if end of the path */
2759  return FR_OK;
2760  }
2761 #endif
2762  for (;;) {
2763  c = (BYTE)p[si++];
2764  if (c <= ' ') break; /* Break if end of the path name */
2765  if (c == '/' || c == '\\') { /* Break if a separator is found */
2766  while (p[si] == '/' || p[si] == '\\') si++; /* Skip duplicated separator if exist */
2767  break;
2768  }
2769  if (c == '.' || i >= ni) { /* End of body or over size? */
2770  if (ni == 11 || c != '.') return FR_INVALID_NAME; /* Over size or invalid dot */
2771  i = 8; ni = 11; /* Goto extension */
2772  continue;
2773  }
2774  if (c >= 0x80) { /* Extended character? */
2775 #ifdef _EXCVT
2776  c = ExCvt[c - 0x80]; /* To upper extended characters (SBCS cfg) */
2777 #else
2778 #if !_DF1S
2779  return FR_INVALID_NAME; /* Reject extended characters (ASCII only cfg) */
2780 #endif
2781 #endif
2782  }
2783  if (IsDBCS1(c)) { /* Check if it is a DBC 1st byte (always false at SBCS cfg.) */
2784  d = (BYTE)p[si++]; /* Get 2nd byte */
2785  if (!IsDBCS2(d) || i >= ni - 1) return FR_INVALID_NAME; /* Reject invalid DBC */
2786  sfn[i++] = c;
2787  sfn[i++] = d;
2788  } else { /* SBC */
2789  if (chk_chr("\"*+,:;<=>\?[]|\x7F", c)) return FR_INVALID_NAME; /* Reject illegal chrs for SFN */
2790  if (IsLower(c)) c -= 0x20; /* To upper */
2791  sfn[i++] = c;
2792  }
2793  }
2794  *path = p + si; /* Return pointer to the next segment */
2795  if (i == 0) return FR_INVALID_NAME; /* Reject nul string */
2796 
2797  if (sfn[0] == DDEM) sfn[0] = RDDEM; /* If the first character collides with DDEM, replace it with RDDEM */
2798  sfn[NSFLAG] = (c <= ' ') ? NS_LAST : 0; /* Set last segment flag if end of the path */
2799 
2800  return FR_OK;
2801 #endif /* _USE_LFN != 0 */
2802 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ follow_path()

static FRESULT follow_path ( DIR dp,
const TCHAR path 
)
static
2816 {
2817  FRESULT res;
2818  BYTE ns;
2819  _FDID *obj = &dp->obj;
2820  FATFS *fs = obj->fs;
2821 
2822 
2823 #if _FS_RPATH != 0
2824  if (*path != '/' && *path != '\\') { /* Without heading separator */
2825  obj->sclust = fs->cdir; /* Start from current directory */
2826  } else
2827 #endif
2828  { /* With heading separator */
2829  while (*path == '/' || *path == '\\') path++; /* Strip heading separator */
2830  obj->sclust = 0; /* Start from root directory */
2831  }
2832 #if _FS_EXFAT
2833  obj->n_frag = 0; /* Invalidate last fragment counter of the object */
2834 #if _FS_RPATH != 0
2835  if (fs->fs_type == FS_EXFAT && obj->sclust) { /* Retrieve the sub-directory status if needed */
2836  DIR dj;
2837 
2838  obj->c_scl = fs->cdc_scl;
2839  obj->c_size = fs->cdc_size;
2840  obj->c_ofs = fs->cdc_ofs;
2841  res = load_obj_dir(&dj, obj);
2842  if (res != FR_OK) return res;
2843  obj->objsize = ld_dword(fs->dirbuf + XDIR_FileSize);
2844  obj->stat = fs->dirbuf[XDIR_GenFlags] & 2;
2845  }
2846 #endif
2847 #endif
2848 
2849  if ((UINT)*path < ' ') { /* Null path name is the origin directory itself */
2850  dp->fn[NSFLAG] = NS_NONAME;
2851  res = dir_sdi(dp, 0);
2852 
2853  } else { /* Follow path */
2854  for (;;) {
2855  res = create_name(dp, &path); /* Get a segment name of the path */
2856  if (res != FR_OK) break;
2857  res = dir_find(dp); /* Find an object with the segment name */
2858  ns = dp->fn[NSFLAG];
2859  if (res != FR_OK) { /* Failed to find the object */
2860  if (res == FR_NO_FILE) { /* Object is not found */
2861  if (_FS_RPATH && (ns & NS_DOT)) { /* If dot entry is not exist, stay there */
2862  if (!(ns & NS_LAST)) continue; /* Continue to follow if not last segment */
2863  dp->fn[NSFLAG] = NS_NONAME;
2864  res = FR_OK;
2865  } else { /* Could not find the object */
2866  if (!(ns & NS_LAST)) res = FR_NO_PATH; /* Adjust error code if not last segment */
2867  }
2868  }
2869  break;
2870  }
2871  if (ns & NS_LAST) break; /* Last segment matched. Function completed. */
2872  /* Get into the sub-directory */
2873  if (!(obj->attr & AM_DIR)) { /* It is not a sub-directory and cannot follow */
2874  res = FR_NO_PATH; break;
2875  }
2876 #if _FS_EXFAT
2877  if (fs->fs_type == FS_EXFAT) { /* Save containing directory information for next dir */
2878  obj->c_scl = obj->sclust;
2879  obj->c_size = ((DWORD)obj->objsize & 0xFFFFFF00) | obj->stat;
2880  obj->c_ofs = dp->blk_ofs;
2881  obj->sclust = ld_dword(fs->dirbuf + XDIR_FstClus); /* Open next directory */
2882  obj->stat = fs->dirbuf[XDIR_GenFlags] & 2;
2883  obj->objsize = ld_qword(fs->dirbuf + XDIR_FileSize);
2884  } else
2885 #endif
2886  {
2887  obj->sclust = ld_clust(fs, fs->win + dp->dptr % SS(fs)); /* Open next directory */
2888  }
2889  }
2890  }
2891 
2892  return res;
2893 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_ldnumber()

static int get_ldnumber ( const TCHAR **  path)
static
2906 {
2907  const TCHAR *tp, *tt;
2908  UINT i;
2909  int vol = -1;
2910 #if _STR_VOLUME_ID /* Find string drive id */
2911  static const char* const volid[] = {_VOLUME_STRS};
2912  const char *sp;
2913  char c;
2914  TCHAR tc;
2915 #endif
2916 
2917 
2918  if (*path) { /* If the pointer is not a null */
2919  for (tt = *path; (UINT)*tt >= (_USE_LFN ? ' ' : '!') && *tt != ':'; tt++) ; /* Find ':' in the path */
2920  if (*tt == ':') { /* If a ':' is exist in the path name */
2921  tp = *path;
2922  i = *tp++ - '0';
2923  if (i < 10 && tp == tt) { /* Is there a numeric drive id? */
2924  if (i < _VOLUMES) { /* If a drive id is found, get the value and strip it */
2925  vol = (int)i;
2926  *path = ++tt;
2927  }
2928  }
2929 #if _STR_VOLUME_ID
2930  else { /* No numeric drive number, find string drive id */
2931  i = 0; tt++;
2932  do {
2933  sp = volid[i]; tp = *path;
2934  do { /* Compare a string drive id with path name */
2935  c = *sp++; tc = *tp++;
2936  if (IsLower(tc)) tc -= 0x20;
2937  } while (c && (TCHAR)c == tc);
2938  } while ((c || tp != tt) && ++i < _VOLUMES); /* Repeat for each id until pattern match */
2939  if (i < _VOLUMES) { /* If a drive id is found, get the value and strip it */
2940  vol = (int)i;
2941  *path = tt;
2942  }
2943  }
2944 #endif
2945  return vol;
2946  }
2947 #if _FS_RPATH != 0 && _VOLUMES >= 2
2948  vol = CurrVol; /* Current drive */
2949 #else
2950  vol = 0; /* Drive 0 */
2951 #endif
2952  }
2953  return vol;
2954 }
Here is the caller graph for this function:

◆ check_fs()

static BYTE check_fs ( FATFS fs,
DWORD  sect 
)
static
2968 {
2969  fs->wflag = 0; fs->winsect = 0xFFFFFFFF; /* Invaidate window */
2970  if (move_window(fs, sect) != FR_OK) return 4; /* Load boot record */
2971 
2972  if (ld_word(fs->win + BS_55AA) != 0xAA55) return 3; /* Check boot record signature (always placed here even if the sector size is >512) */
2973 
2974  if (fs->win[BS_JmpBoot] == 0xE9 || (fs->win[BS_JmpBoot] == 0xEB && fs->win[BS_JmpBoot + 2] == 0x90)) {
2975  if ((ld_dword(fs->win + BS_FilSysType) & 0xFFFFFF) == 0x544146) return 0; /* Check "FAT" string */
2976  if (ld_dword(fs->win + BS_FilSysType32) == 0x33544146) return 0; /* Check "FAT3" string */
2977  }
2978 #if _FS_EXFAT
2979  if (!mem_cmp(fs->win + BS_JmpBoot, "\xEB\x76\x90" "EXFAT ", 11)) return 1;
2980 #endif
2981  return 2;
2982 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ find_volume()

static FRESULT find_volume ( const TCHAR **  path,
FATFS **  rfs,
BYTE  mode 
)
static
2997 {
2998  BYTE fmt, *pt;
2999  int vol;
3000  DSTATUS stat;
3001  DWORD bsect, fasize, tsect, sysect, nclst, szbfat, br[4];
3002  WORD nrsv;
3003  FATFS *fs;
3004  UINT i;
3005 
3006 
3007  /* Get logical drive number */
3008  *rfs = 0;
3009  vol = get_ldnumber(path);
3010  if (vol < 0) return FR_INVALID_DRIVE;
3011 
3012  /* Check if the file system object is valid or not */
3013  fs = FatFs[vol]; /* Get pointer to the file system object */
3014  if (!fs) return FR_NOT_ENABLED; /* Is the file system object available? */
3015 
3016  ENTER_FF(fs); /* Lock the volume */
3017  *rfs = fs; /* Return pointer to the file system object */
3018 
3019  mode &= (BYTE)~FA_READ; /* Desired access mode, write access or not */
3020  if (fs->fs_type) { /* If the volume has been mounted */
3021  stat = disk_status(fs->drv);
3022  if (!(stat & STA_NOINIT)) { /* and the physical drive is kept initialized */
3023  if (!_FS_READONLY && mode && (stat & STA_PROTECT)) { /* Check write protection if needed */
3024  return FR_WRITE_PROTECTED;
3025  }
3026  return FR_OK; /* The file system object is valid */
3027  }
3028  }
3029 
3030  /* The file system object is not valid. */
3031  /* Following code attempts to mount the volume. (analyze BPB and initialize the fs object) */
3032 
3033  fs->fs_type = 0; /* Clear the file system object */
3034  fs->drv = LD2PD(vol); /* Bind the logical drive and a physical drive */
3035  stat = disk_initialize(fs->drv); /* Initialize the physical drive */
3036  if (stat & STA_NOINIT) { /* Check if the initialization succeeded */
3037  return FR_NOT_READY; /* Failed to initialize due to no medium or hard error */
3038  }
3039  if (!_FS_READONLY && mode && (stat & STA_PROTECT)) { /* Check disk write protection if needed */
3040  return FR_WRITE_PROTECTED;
3041  }
3042 #if _MAX_SS != _MIN_SS /* Get sector size (multiple sector size cfg only) */
3043  if (disk_ioctl(fs->drv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK) return FR_DISK_ERR;
3044  if (SS(fs) > _MAX_SS || SS(fs) < _MIN_SS || (SS(fs) & (SS(fs) - 1))) return FR_DISK_ERR;
3045 #endif
3046 
3047  /* Find an FAT partition on the drive. Supports only generic partitioning rules, FDISK and SFD. */
3048  bsect = 0;
3049  fmt = check_fs(fs, bsect); /* Load sector 0 and check if it is an FAT-VBR as SFD */
3050  if (fmt == 2 || (fmt < 2 && LD2PT(vol) != 0)) { /* Not an FAT-VBR or forced partition number */
3051  for (i = 0; i < 4; i++) { /* Get partition offset */
3052  pt = fs->win + (MBR_Table + i * SZ_PTE);
3053  br[i] = pt[PTE_System] ? ld_dword(pt + PTE_StLba) : 0;
3054  }
3055  i = LD2PT(vol); /* Partition number: 0:auto, 1-4:forced */
3056  if (i) i--;
3057  do { /* Find an FAT volume */
3058  bsect = br[i];
3059  fmt = bsect ? check_fs(fs, bsect) : 3; /* Check the partition */
3060  } while (LD2PT(vol) == 0 && fmt >= 2 && ++i < 4);
3061  }
3062  if (fmt == 4) return FR_DISK_ERR; /* An error occured in the disk I/O layer */
3063  if (fmt >= 2) return FR_NO_FILESYSTEM; /* No FAT volume is found */
3064 
3065  /* An FAT volume is found (bsect). Following code initializes the file system object */
3066 
3067 #if _FS_EXFAT
3068  if (fmt == 1) {
3069  QWORD maxlba;
3070 
3071  for (i = BPB_ZeroedEx; i < BPB_ZeroedEx + 53 && fs->win[i] == 0; i++) ; /* Check zero filler */
3072  if (i < BPB_ZeroedEx + 53) return FR_NO_FILESYSTEM;
3073 
3074  if (ld_word(fs->win + BPB_FSVerEx) != 0x100) return FR_NO_FILESYSTEM; /* Check exFAT revision (Must be 1.0) */
3075 
3076  if (1 << fs->win[BPB_BytsPerSecEx] != SS(fs)) { /* (BPB_BytsPerSecEx must be equal to the physical sector size) */
3077  return FR_NO_FILESYSTEM;
3078  }
3079 
3080  maxlba = ld_qword(fs->win + BPB_TotSecEx) + bsect; /* Last LBA + 1 of the volume */
3081  if (maxlba >= 0x100000000) return FR_NO_FILESYSTEM; /* (It cannot be handled in 32-bit LBA) */
3082 
3083  fs->fsize = ld_dword(fs->win + BPB_FatSzEx); /* Number of sectors per FAT */
3084 
3085  fs->n_fats = fs->win[BPB_NumFATsEx]; /* Number of FATs */
3086  if (fs->n_fats != 1) return FR_NO_FILESYSTEM; /* (Supports only 1 FAT) */
3087 
3088  fs->csize = 1 << fs->win[BPB_SecPerClusEx]; /* Cluster size */
3089  if (fs->csize == 0) return FR_NO_FILESYSTEM; /* (Must be 1..32768) */
3090 
3091  nclst = ld_dword(fs->win + BPB_NumClusEx); /* Number of clusters */
3092  if (nclst > MAX_EXFAT) return FR_NO_FILESYSTEM; /* (Too many clusters) */
3093  fs->n_fatent = nclst + 2;
3094 
3095  /* Boundaries and Limits */
3096  fs->volbase = bsect;
3097  fs->database = bsect + ld_dword(fs->win + BPB_DataOfsEx);
3098  fs->fatbase = bsect + ld_dword(fs->win + BPB_FatOfsEx);
3099  if (maxlba < (QWORD)fs->database + nclst * fs->csize) return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size requiered) */
3100  fs->dirbase = ld_dword(fs->win + BPB_RootClusEx);
3101 
3102  /* Check if bitmap location is in assumption (at the first cluster) */
3103  if (move_window(fs, clust2sect(fs, fs->dirbase)) != FR_OK) return FR_DISK_ERR;
3104  for (i = 0; i < SS(fs); i += SZDIRE) {
3105  if (fs->win[i] == 0x81 && ld_dword(fs->win + i + 20) == 2) break; /* 81 entry with cluster #2? */
3106  }
3107  if (i == SS(fs)) return FR_NO_FILESYSTEM;
3108 #if !_FS_READONLY
3109  fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */
3110 #endif
3111  fmt = FS_EXFAT; /* FAT sub-type */
3112  } else
3113 #endif /* _FS_EXFAT */
3114  {
3115  if (ld_word(fs->win + BPB_BytsPerSec) != SS(fs)) return FR_NO_FILESYSTEM; /* (BPB_BytsPerSec must be equal to the physical sector size) */
3116 
3117  fasize = ld_word(fs->win + BPB_FATSz16); /* Number of sectors per FAT */
3118  if (fasize == 0) fasize = ld_dword(fs->win + BPB_FATSz32);
3119  fs->fsize = fasize;
3120 
3121  fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FATs */
3122  if (fs->n_fats != 1 && fs->n_fats != 2) return FR_NO_FILESYSTEM; /* (Must be 1 or 2) */
3123  fasize *= fs->n_fats; /* Number of sectors for FAT area */
3124 
3125  fs->csize = fs->win[BPB_SecPerClus]; /* Cluster size */
3126  if (fs->csize == 0 || (fs->csize & (fs->csize - 1))) return FR_NO_FILESYSTEM; /* (Must be power of 2) */
3127 
3128  fs->n_rootdir = ld_word(fs->win + BPB_RootEntCnt); /* Number of root directory entries */
3129  if (fs->n_rootdir % (SS(fs) / SZDIRE)) return FR_NO_FILESYSTEM; /* (Must be sector aligned) */
3130 
3131  tsect = ld_word(fs->win + BPB_TotSec16); /* Number of sectors on the volume */
3132  if (tsect == 0) tsect = ld_dword(fs->win + BPB_TotSec32);
3133 
3134  nrsv = ld_word(fs->win + BPB_RsvdSecCnt); /* Number of reserved sectors */
3135  if (nrsv == 0) return FR_NO_FILESYSTEM; /* (Must not be 0) */
3136 
3137  /* Determine the FAT sub type */
3138  sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZDIRE); /* RSV + FAT + DIR */
3139  if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */
3140  nclst = (tsect - sysect) / fs->csize; /* Number of clusters */
3141  if (nclst == 0) return FR_NO_FILESYSTEM; /* (Invalid volume size) */
3142  fmt = FS_FAT32;
3143  if (nclst <= MAX_FAT16) fmt = FS_FAT16;
3144  if (nclst <= MAX_FAT12) fmt = FS_FAT12;
3145 
3146  /* Boundaries and Limits */
3147  fs->n_fatent = nclst + 2; /* Number of FAT entries */
3148  fs->volbase = bsect; /* Volume start sector */
3149  fs->fatbase = bsect + nrsv; /* FAT start sector */
3150  fs->database = bsect + sysect; /* Data start sector */
3151  if (fmt == FS_FAT32) {
3152  if (ld_word(fs->win + BPB_FSVer32) != 0) return FR_NO_FILESYSTEM; /* (Must be FAT32 revision 0.0) */
3153  if (fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */
3154  fs->dirbase = ld_dword(fs->win + BPB_RootClus32); /* Root directory start cluster */
3155  szbfat = fs->n_fatent * 4; /* (Needed FAT size) */
3156  } else {
3157  if (fs->n_rootdir == 0) return FR_NO_FILESYSTEM;/* (BPB_RootEntCnt must not be 0) */
3158  fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */
3159  szbfat = (fmt == FS_FAT16) ? /* (Needed FAT size) */
3160  fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1);
3161  }
3162  if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) return FR_NO_FILESYSTEM; /* (BPB_FATSz must not be less than the size needed) */
3163 
3164 #if !_FS_READONLY
3165  /* Get FSINFO if available */
3166  fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */
3167  fs->fsi_flag = 0x80;
3168 #if (_FS_NOFSINFO & 3) != 3
3169  if (fmt == FS_FAT32 /* Enable FSINFO only if FAT32 and BPB_FSInfo32 == 1 */
3170  && ld_word(fs->win + BPB_FSInfo32) == 1
3171  && move_window(fs, bsect + 1) == FR_OK)
3172  {
3173  fs->fsi_flag = 0;
3174  if (ld_word(fs->win + BS_55AA) == 0xAA55 /* Load FSINFO data if available */
3175  && ld_dword(fs->win + FSI_LeadSig) == 0x41615252
3176  && ld_dword(fs->win + FSI_StrucSig) == 0x61417272)
3177  {
3178 #if (_FS_NOFSINFO & 1) == 0
3179  fs->free_clst = ld_dword(fs->win + FSI_Free_Count);
3180 #endif
3181 #if (_FS_NOFSINFO & 2) == 0
3182  fs->last_clst = ld_dword(fs->win + FSI_Nxt_Free);
3183 #endif
3184  }
3185  }
3186 #endif /* (_FS_NOFSINFO & 3) != 3 */
3187 #endif /* !_FS_READONLY */
3188  }
3189 
3190  fs->fs_type = fmt; /* FAT sub-type */
3191  fs->id = ++Fsid; /* File system mount ID */
3192 #if _USE_LFN == 1
3193  fs->lfnbuf = LfnBuf; /* Static LFN working buffer */
3194 #if _FS_EXFAT
3195  fs->dirbuf = DirBuf; /* Static directory block scratchpad buuffer */
3196 #endif
3197 #endif
3198 #if _FS_RPATH != 0
3199  fs->cdir = 0; /* Initialize current directory */
3200 #endif
3201 #if _FS_LOCK != 0 /* Clear file lock semaphores */
3202  clear_lock(fs);
3203 #endif
3204  return FR_OK;
3205 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ validate()

static FRESULT validate ( _FDID obj,
FATFS **  fs 
)
static
3219 {
3220  FRESULT res;
3221 
3222  if (!obj || !obj->fs || !obj->fs->fs_type || obj->fs->id != obj->id || (disk_status(obj->fs->drv) & STA_NOINIT)) {
3223  *fs = 0;
3224  res = FR_INVALID_OBJECT; /* The object is invalid */
3225  } else {
3226  *fs = obj->fs; /* Owner file sytem object */
3227  ENTER_FF(obj->fs); /* Lock file system */
3228  res = FR_OK; /* Valid object */
3229  }
3230  return res;
3231 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ f_mount()

FRESULT f_mount ( FATFS fs,
const TCHAR path,
BYTE  opt 
)
3253 {
3254  FATFS *cfs;
3255  int vol;
3256  FRESULT res;
3257  const TCHAR *rp = path;
3258 
3259 
3260  /* Get logical drive number */
3261  vol = get_ldnumber(&rp);
3262  if (vol < 0) return FR_INVALID_DRIVE;
3263  cfs = FatFs[vol]; /* Pointer to fs object */
3264 
3265  if (cfs) {
3266 #if _FS_LOCK != 0
3267  clear_lock(cfs);
3268 #endif
3269 #if _FS_REENTRANT /* Discard sync object of the current volume */
3270  if (!ff_del_syncobj(cfs->sobj)) return FR_INT_ERR;
3271 #endif
3272  cfs->fs_type = 0; /* Clear old fs object */
3273  }
3274 
3275  if (fs) {
3276  fs->fs_type = 0; /* Clear new fs object */
3277 #if _FS_REENTRANT /* Create sync object for the new volume */
3278  if (!ff_cre_syncobj((BYTE)vol, &fs->sobj)) return FR_INT_ERR;
3279 #endif
3280  }
3281  FatFs[vol] = fs; /* Register new fs object */
3282 
3283  if (!fs || opt != 1) return FR_OK; /* Do not mount now, it will be mounted later */
3284 
3285  res = find_volume(&path, &fs, 0); /* Force mounted the volume */
3286  LEAVE_FF(fs, res);
3287 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ f_open()

FRESULT f_open ( FIL fp,
const TCHAR path,
BYTE  mode 
)
3301 {
3302  FRESULT res;
3303  DIR dj;
3304  FATFS *fs;
3305 #if !_FS_READONLY
3306  DWORD dw, cl, bcs, clst, sc;
3307  FSIZE_t ofs;
3308 #endif
3309  DEF_NAMBUF
3310 
3311 
3312  if (!fp) return FR_INVALID_OBJECT;
3313 
3314  /* Get logical drive */
3316  res = find_volume(&path, &fs, mode);
3317  if (res == FR_OK) {
3318  dj.obj.fs = fs;
3319  INIT_NAMBUF(fs);
3320  res = follow_path(&dj, path); /* Follow the file path */
3321 #if !_FS_READONLY /* R/W configuration */
3322  if (res == FR_OK) {
3323  if (dj.fn[NSFLAG] & NS_NONAME) { /* Origin directory itself? */
3324  res = FR_INVALID_NAME;
3325  }
3326 #if _FS_LOCK != 0
3327  else {
3328  res = chk_lock(&dj, (mode & ~FA_READ) ? 1 : 0);
3329  }
3330 #endif
3331  }
3332  /* Create or Open a file */
3334  if (res != FR_OK) { /* No file, create new */
3335  if (res == FR_NO_FILE) { /* There is no file to open, create a new entry */
3336 #if _FS_LOCK != 0
3337  res = enq_lock() ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES;
3338 #else
3339  res = dir_register(&dj);
3340 #endif
3341  }
3342  mode |= FA_CREATE_ALWAYS; /* File is created */
3343  }
3344  else { /* Any object is already existing */
3345  if (dj.obj.attr & (AM_RDO | AM_DIR)) { /* Cannot overwrite it (R/O or DIR) */
3346  res = FR_DENIED;
3347  } else {
3348  if (mode & FA_CREATE_NEW) res = FR_EXIST; /* Cannot create as new file */
3349  }
3350  }
3351  if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) { /* Truncate it if overwrite mode */
3352  dw = GET_FATTIME();
3353 #if _FS_EXFAT
3354  if (fs->fs_type == FS_EXFAT) {
3355  /* Get current allocation info */
3356  fp->obj.fs = fs;
3357  fp->obj.sclust = ld_dword(fs->dirbuf + XDIR_FstClus);
3358  fp->obj.objsize = ld_qword(fs->dirbuf + XDIR_FileSize);
3359  fp->obj.stat = fs->dirbuf[XDIR_GenFlags] & 2;
3360  fp->obj.n_frag = 0;
3361  /* Initialize directory entry block */
3362  st_dword(fs->dirbuf + XDIR_CrtTime, dw); /* Set created time */
3363  fs->dirbuf[XDIR_CrtTime10] = 0;
3364  st_dword(fs->dirbuf + XDIR_ModTime, dw); /* Set modified time */
3365  fs->dirbuf[XDIR_ModTime10] = 0;
3366  fs->dirbuf[XDIR_Attr] = AM_ARC; /* Reset attribute */
3367  st_dword(fs->dirbuf + XDIR_FstClus, 0); /* Reset file allocation info */
3368  st_qword(fs->dirbuf + XDIR_FileSize, 0);
3369  st_qword(fs->dirbuf + XDIR_ValidFileSize, 0);
3370  fs->dirbuf[XDIR_GenFlags] = 1;
3371  res = store_xdir(&dj);
3372  if (res == FR_OK && fp->obj.sclust) { /* Remove the cluster chain if exist */
3373  res = remove_chain(&fp->obj, fp->obj.sclust, 0);
3374  fs->last_clst = fp->obj.sclust - 1; /* Reuse the cluster hole */
3375  }
3376  } else
3377 #endif
3378  {
3379  /* Clean directory info */
3380  st_dword(dj.dir + DIR_CrtTime, dw); /* Set created time */
3381  st_dword(dj.dir + DIR_ModTime, dw); /* Set modified time */
3382  dj.dir[DIR_Attr] = AM_ARC; /* Reset attribute */
3383  cl = ld_clust(fs, dj.dir); /* Get cluster chain */
3384  st_clust(fs, dj.dir, 0); /* Reset file allocation info */
3385  st_dword(dj.dir + DIR_FileSize, 0);
3386  fs->wflag = 1;
3387 
3388  if (cl) { /* Remove the cluster chain if exist */
3389  dw = fs->winsect;
3390  res = remove_chain(&dj.obj, cl, 0);
3391  if (res == FR_OK) {
3392  res = move_window(fs, dw);
3393  fs->last_clst = cl - 1; /* Reuse the cluster hole */
3394  }
3395  }
3396  }
3397  }
3398  }
3399  else { /* Open an existing file */
3400  if (res == FR_OK) { /* Following succeeded */
3401  if (dj.obj.attr & AM_DIR) { /* It is a directory */
3402  res = FR_NO_FILE;
3403  } else {
3404  if ((mode & FA_WRITE) && (dj.obj.attr & AM_RDO)) { /* R/O violation */
3405  res = FR_DENIED;
3406  }
3407  }
3408  }
3409  }
3410  if (res == FR_OK) {
3411  if (mode & FA_CREATE_ALWAYS) /* Set file change flag if created or overwritten */
3412  mode |= FA_MODIFIED;
3413  fp->dir_sect = fs->winsect; /* Pointer to the directory entry */
3414  fp->dir_ptr = dj.dir;
3415 #if _FS_LOCK != 0
3416  fp->obj.lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0);
3417  if (!fp->obj.lockid) res = FR_INT_ERR;
3418 #endif
3419  }
3420 #else /* R/O configuration */
3421  if (res == FR_OK) {
3422  if (dj.fn[NSFLAG] & NS_NONAME) { /* Origin directory itself? */
3423  res = FR_INVALID_NAME;
3424  } else {
3425  if (dj.obj.attr & AM_DIR) { /* It is a directory */
3426  res = FR_NO_FILE;
3427  }
3428  }
3429  }
3430 #endif
3431 
3432  if (res == FR_OK) {
3433 #if _FS_EXFAT
3434  if (fs->fs_type == FS_EXFAT) {
3435  fp->obj.c_scl = dj.obj.sclust; /* Get containing directory info */
3436  fp->obj.c_size = ((DWORD)dj.obj.objsize & 0xFFFFFF00) | dj.obj.stat;
3437  fp->obj.c_ofs = dj.blk_ofs;
3438  fp->obj.sclust = ld_dword(fs->dirbuf + XDIR_FstClus); /* Get object allocation info */
3439  fp->obj.objsize = ld_qword(fs->dirbuf + XDIR_FileSize);
3440  fp->obj.stat = fs->dirbuf[XDIR_GenFlags] & 2;
3441  } else
3442 #endif
3443  {
3444  fp->obj.sclust = ld_clust(fs, dj.dir); /* Get object allocation info */
3445  fp->obj.objsize = ld_dword(dj.dir + DIR_FileSize);
3446  }
3447 #if _USE_FASTSEEK
3448  fp->cltbl = 0; /* Disable fast seek mode */
3449 #endif
3450  fp->obj.fs = fs; /* Validate the file object */
3451  fp->obj.id = fs->id;
3452  fp->flag = mode; /* Set file access mode */
3453  fp->err = 0; /* Clear error flag */
3454  fp->sect = 0; /* Invalidate current data sector */
3455  fp->fptr = 0; /* Set file pointer top of the file */
3456 #if !_FS_READONLY
3457 #if !_FS_TINY
3458  mem_set(fp->buf, 0, _MAX_SS); /* Clear sector buffer */
3459 #endif
3460  if ((mode & FA_SEEKEND) && fp->obj.objsize > 0) { /* Seek to end of file if FA_OPEN_APPEND is specified */
3461  fp->fptr = fp->obj.objsize; /* Offset to seek */
3462  bcs = (DWORD)fs->csize * SS(fs); /* Cluster size in byte */
3463  clst = fp->obj.sclust; /* Follow the cluster chain */
3464  for (ofs = fp->obj.objsize; res == FR_OK && ofs > bcs; ofs -= bcs) {
3465  clst = get_fat(&fp->obj, clst);
3466  if (clst <= 1) res = FR_INT_ERR;
3467  if (clst == 0xFFFFFFFF) res = FR_DISK_ERR;
3468  }
3469  fp->clust = clst;
3470  if (res == FR_OK && ofs % SS(fs)) { /* Fill sector buffer if not on the sector boundary */
3471  if ((sc = clust2sect(fs, clst)) == 0) {
3472  res = FR_INT_ERR;
3473  } else {
3474  fp->sect = sc + (DWORD)(ofs / SS(fs));
3475 #if !_FS_TINY
3476  if (disk_read(fs->drv, fp->buf, fp->sect, 1) != RES_OK) res = FR_DISK_ERR;
3477 #endif
3478  }
3479  }
3480  }
3481 #endif
3482  }
3483 
3484  FREE_NAMBUF();
3485  }
3486 
3487  if (res != FR_OK) fp->obj.fs = 0; /* Invalidate file object on error */
3488 
3489  LEAVE_FF(fs, res);
3490 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ f_read()

FRESULT f_read ( FIL fp,
void buff,
UINT  btr,
UINT br 
)
3505 {
3506  FRESULT res;
3507  FATFS *fs;
3508  DWORD clst, sect;
3509  FSIZE_t remain;
3510  UINT rcnt, cc, csect;
3511  BYTE *rbuff = (BYTE*)buff;
3512 
3513 
3514  *br = 0; /* Clear read byte counter */
3515  res = validate(&fp->obj, &fs); /* Check validity of the file object */
3516  if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */
3517  if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */
3518  remain = fp->obj.objsize - fp->fptr;
3519  if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */
3520 
3521  for ( ; btr; /* Repeat until all data read */
3522  rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) {
3523  if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */
3524  csect = (UINT)(fp->fptr / SS(fs) & (fs->csize - 1)); /* Sector offset in the cluster */
3525  if (csect == 0) { /* On the cluster boundary? */
3526  if (fp->fptr == 0) { /* On the top of the file? */
3527  clst = fp->obj.sclust; /* Follow cluster chain from the origin */
3528  } else { /* Middle or end of the file */
3529 #if _USE_FASTSEEK
3530  if (fp->cltbl) {
3531  clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */
3532  } else
3533 #endif
3534  {
3535  clst = get_fat(&fp->obj, fp->clust); /* Follow cluster chain on the FAT */
3536  }
3537  }
3538  if (clst < 2) ABORT(fs, FR_INT_ERR);
3539  if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR);
3540  fp->clust = clst; /* Update current cluster */
3541  }
3542  sect = clust2sect(fs, fp->clust); /* Get current sector */
3543  if (!sect) ABORT(fs, FR_INT_ERR);
3544  sect += csect;
3545  cc = btr / SS(fs); /* When remaining bytes >= sector size, */
3546  if (cc) { /* Read maximum contiguous sectors directly */
3547  if (csect + cc > fs->csize) { /* Clip at cluster boundary */
3548  cc = fs->csize - csect;
3549  }
3550  if (disk_read(fs->drv, rbuff, sect, cc) != RES_OK) ABORT(fs, FR_DISK_ERR);
3551 #if !_FS_READONLY && _FS_MINIMIZE <= 2 /* Replace one of the read sectors with cached data if it contains a dirty sector */
3552 #if _FS_TINY
3553  if (fs->wflag && fs->winsect - sect < cc) {
3554  mem_cpy(rbuff + ((fs->winsect - sect) * SS(fs)), fs->win, SS(fs));
3555  }
3556 #else
3557  if ((fp->flag & FA_DIRTY) && fp->sect - sect < cc) {
3558  mem_cpy(rbuff + ((fp->sect - sect) * SS(fs)), fp->buf, SS(fs));
3559  }
3560 #endif
3561 #endif
3562  rcnt = SS(fs) * cc; /* Number of bytes transferred */
3563  continue;
3564  }
3565 #if !_FS_TINY
3566  if (fp->sect != sect) { /* Load data sector if not in cache */
3567 #if !_FS_READONLY
3568  if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */
3569  if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);
3570  fp->flag &= (BYTE)~FA_DIRTY;
3571  }
3572 #endif
3573  if (disk_read(fs->drv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */
3574  }
3575 #endif
3576  fp->sect = sect;
3577  }
3578  rcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes left in the sector */
3579  if (rcnt > btr) rcnt = btr; /* Clip it by btr if needed */
3580 #if _FS_TINY
3581  if (move_window(fs, fp->sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window */
3582  mem_cpy(rbuff, fs->win + fp->fptr % SS(fs), rcnt); /* Extract partial sector */
3583 #else
3584  mem_cpy(rbuff, fp->buf + fp->fptr % SS(fs), rcnt); /* Extract partial sector */
3585 #endif
3586  }
3587 
3588  LEAVE_FF(fs, FR_OK);
3589 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ f_write()

FRESULT f_write ( FIL fp,
const void buff,
UINT  btw,
UINT bw 
)
3605 {
3606  FRESULT res;
3607  FATFS *fs;
3608  DWORD clst, sect;
3609  UINT wcnt, cc, csect;
3610  const BYTE *wbuff = (const BYTE*)buff;
3611 
3612 
3613  *bw = 0; /* Clear write byte counter */
3614  res = validate(&fp->obj, &fs); /* Check validity of the file object */
3615  if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */
3616  if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */
3617 
3618  /* Check fptr wrap-around (file size cannot reach 4GiB on FATxx) */
3619  if ((!_FS_EXFAT || fs->fs_type != FS_EXFAT) && (DWORD)(fp->fptr + btw) < (DWORD)fp->fptr) {
3620  btw = (UINT)(0xFFFFFFFF - (DWORD)fp->fptr);
3621  }
3622 
3623  for ( ; btw; /* Repeat until all data written */
3624  wbuff += wcnt, fp->fptr += wcnt, fp->obj.objsize = (fp->fptr > fp->obj.objsize) ? fp->fptr : fp->obj.objsize, *bw += wcnt, btw -= wcnt) {
3625  if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */
3626  csect = (UINT)(fp->fptr / SS(fs)) & (fs->csize - 1); /* Sector offset in the cluster */
3627  if (csect == 0) { /* On the cluster boundary? */
3628  if (fp->fptr == 0) { /* On the top of the file? */
3629  clst = fp->obj.sclust; /* Follow from the origin */
3630  if (clst == 0) { /* If no cluster is allocated, */
3631  clst = create_chain(&fp->obj, 0); /* create a new cluster chain */
3632  }
3633  } else { /* On the middle or end of the file */
3634 #if _USE_FASTSEEK
3635  if (fp->cltbl) {
3636  clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */
3637  } else
3638 #endif
3639  {
3640  clst = create_chain(&fp->obj, fp->clust); /* Follow or stretch cluster chain on the FAT */
3641  }
3642  }
3643  if (clst == 0) break; /* Could not allocate a new cluster (disk full) */
3644  if (clst == 1) ABORT(fs, FR_INT_ERR);
3645  if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR);
3646  fp->clust = clst; /* Update current cluster */
3647  if (fp->obj.sclust == 0) fp->obj.sclust = clst; /* Set start cluster if the first write */
3648  }
3649 #if _FS_TINY
3650  if (fs->winsect == fp->sect && sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Write-back sector cache */
3651 #else
3652  if (fp->flag & FA_DIRTY) { /* Write-back sector cache */
3653  if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);
3654  fp->flag &= (BYTE)~FA_DIRTY;
3655  }
3656 #endif
3657  sect = clust2sect(fs, fp->clust); /* Get current sector */
3658  if (!sect) ABORT(fs, FR_INT_ERR);
3659  sect += csect;
3660  cc = btw / SS(fs); /* When remaining bytes >= sector size, */
3661  if (cc) { /* Write maximum contiguous sectors directly */
3662  if (csect + cc > fs->csize) { /* Clip at cluster boundary */
3663  cc = fs->csize - csect;
3664  }
3665  if (disk_write(fs->drv, wbuff, sect, cc) != RES_OK) ABORT(fs, FR_DISK_ERR);
3666 #if _FS_MINIMIZE <= 2
3667 #if _FS_TINY
3668  if (fs->winsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */
3669  mem_cpy(fs->win, wbuff + ((fs->winsect - sect) * SS(fs)), SS(fs));
3670  fs->wflag = 0;
3671  }
3672 #else
3673  if (fp->sect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */
3674  mem_cpy(fp->buf, wbuff + ((fp->sect - sect) * SS(fs)), SS(fs));
3675  fp->flag &= (BYTE)~FA_DIRTY;
3676  }
3677 #endif
3678 #endif
3679  wcnt = SS(fs) * cc; /* Number of bytes transferred */
3680  continue;
3681  }
3682 #if _FS_TINY
3683  if (fp->fptr >= fp->obj.objsize) { /* Avoid silly cache filling on the growing edge */
3684  if (sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR);
3685  fs->winsect = sect;
3686  }
3687 #else
3688  if (fp->sect != sect && /* Fill sector cache with file data */
3689  fp->fptr < fp->obj.objsize &&
3690  disk_read(fs->drv, fp->buf, sect, 1) != RES_OK) {
3691  ABORT(fs, FR_DISK_ERR);
3692  }
3693 #endif
3694  fp->sect = sect;
3695  }
3696  wcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes left in the sector */
3697  if (wcnt > btw) wcnt = btw; /* Clip it by btw if needed */
3698 #if _FS_TINY
3699  if (move_window(fs, fp->sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window */
3700  mem_cpy(fs->win + fp->fptr % SS(fs), wbuff, wcnt); /* Fit data to the sector */
3701  fs->wflag = 1;
3702 #else
3703  mem_cpy(fp->buf + fp->fptr % SS(fs), wbuff, wcnt); /* Fit data to the sector */
3704  fp->flag |= FA_DIRTY;
3705 #endif
3706  }
3707 
3708  fp->flag |= FA_MODIFIED; /* Set file change flag */
3709 
3710  LEAVE_FF(fs, FR_OK);
3711 }
Here is the call graph for this function:

◆ f_sync()

FRESULT f_sync ( FIL fp)
3723 {
3724  FRESULT res;
3725  FATFS *fs;
3726  DWORD tm;
3727  BYTE *dir;
3728 #if _FS_EXFAT
3729  DIR dj;
3730  DEF_NAMBUF
3731 #endif
3732 
3733  res = validate(&fp->obj, &fs); /* Check validity of the file object */
3734  if (res == FR_OK) {
3735  if (fp->flag & FA_MODIFIED) { /* Is there any change to the file? */
3736 #if !_FS_TINY
3737  if (fp->flag & FA_DIRTY) { /* Write-back cached data if needed */
3738  if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) LEAVE_FF(fs, FR_DISK_ERR);
3739  fp->flag &= (BYTE)~FA_DIRTY;
3740  }
3741 #endif
3742  /* Update the directory entry */
3743  tm = GET_FATTIME(); /* Modified time */
3744 #if _FS_EXFAT
3745  if (fs->fs_type == FS_EXFAT) {
3746  res = fill_first_frag(&fp->obj); /* Fill first fragment on the FAT if needed */
3747  if (res == FR_OK) {
3748  res = fill_last_frag(&fp->obj, fp->clust, 0xFFFFFFFF); /* Fill last fragment on the FAT if needed */
3749  }
3750  if (res == FR_OK) {
3751  INIT_NAMBUF(fs);
3752  res = load_obj_dir(&dj, &fp->obj); /* Load directory entry block */
3753  if (res == FR_OK) {
3754  fs->dirbuf[XDIR_Attr] |= AM_ARC; /* Set archive bit */
3755  fs->dirbuf[XDIR_GenFlags] = fp->obj.stat | 1; /* Update file allocation info */
3756  st_dword(fs->dirbuf + XDIR_FstClus, fp->obj.sclust);
3757  st_qword(fs->dirbuf + XDIR_FileSize, fp->obj.objsize);
3758  st_qword(fs->dirbuf + XDIR_ValidFileSize, fp->obj.objsize);
3759  st_dword(fs->dirbuf + XDIR_ModTime, tm); /* Update modified time */
3760  fs->dirbuf[XDIR_ModTime10] = 0;
3761  st_dword(fs->dirbuf + XDIR_AccTime, 0);
3762  res = store_xdir(&dj); /* Restore it to the directory */
3763  if (res == FR_OK) {
3764  res = sync_fs(fs);
3765  fp->flag &= (BYTE)~FA_MODIFIED;
3766  }
3767  }
3768  FREE_NAMBUF();
3769  }
3770  } else
3771 #endif
3772  {
3773  res = move_window(fs, fp->dir_sect);
3774  if (res == FR_OK) {
3775  dir = fp->dir_ptr;
3776  dir[DIR_Attr] |= AM_ARC; /* Set archive bit */
3777  st_clust(fp->obj.fs, dir, fp->obj.sclust); /* Update file allocation info */
3778  st_dword(dir + DIR_FileSize, (DWORD)fp->obj.objsize); /* Update file size */
3779  st_dword(dir + DIR_ModTime, tm); /* Update modified time */
3780  st_word(dir + DIR_LstAccDate, 0);
3781  fs->wflag = 1;
3782  res = sync_fs(fs); /* Restore it to the directory */
3783  fp->flag &= (BYTE)~FA_MODIFIED;
3784  }
3785  }
3786  }
3787  }
3788 
3789  LEAVE_FF(fs, res);
3790 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ f_close()

FRESULT f_close ( FIL fp)
3804 {
3805  FRESULT res;
3806  FATFS *fs;
3807 
3808 #if !_FS_READONLY
3809  res = f_sync(fp); /* Flush cached data */
3810  if (res == FR_OK)
3811 #endif
3812  {
3813  res = validate(&fp->obj, &fs); /* Lock volume */
3814  if (res == FR_OK) {
3815 #if _FS_LOCK != 0
3816  res = dec_lock(fp->obj.lockid); /* Decrement file open counter */
3817  if (res == FR_OK)
3818 #endif
3819  {
3820  fp->obj.fs = 0; /* Invalidate file object */
3821  }
3822 #if _FS_REENTRANT
3823  unlock_fs(fs, FR_OK); /* Unlock volume */
3824 #endif
3825  }
3826  }
3827  return res;
3828 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ f_lseek()

FRESULT f_lseek ( FIL fp,
FSIZE_t  ofs 
)
4064 {
4065  FRESULT res;
4066  FATFS *fs;
4067  DWORD clst, bcs, nsect;
4068  FSIZE_t ifptr;
4069 #if _USE_FASTSEEK
4070  DWORD cl, pcl, ncl, tcl, dsc, tlen, ulen, *tbl;
4071 #endif
4072 
4073  res = validate(&fp->obj, &fs); /* Check validity of the file object */
4074  if (res == FR_OK) res = (FRESULT)fp->err;
4075 #if _FS_EXFAT && !_FS_READONLY
4076  if (res == FR_OK && fs->fs_type == FS_EXFAT) {
4077  res = fill_last_frag(&fp->obj, fp->clust, 0xFFFFFFFF); /* Fill last fragment on the FAT if needed */
4078  }
4079 #endif
4080  if (res != FR_OK) LEAVE_FF(fs, res);
4081 
4082 #if _USE_FASTSEEK
4083  if (fp->cltbl) { /* Fast seek */
4084  if (ofs == CREATE_LINKMAP) { /* Create CLMT */
4085  tbl = fp->cltbl;
4086  tlen = *tbl++; ulen = 2; /* Given table size and required table size */
4087  cl = fp->obj.sclust; /* Origin of the chain */
4088  if (cl) {
4089  do {
4090  /* Get a fragment */
4091  tcl = cl; ncl = 0; ulen += 2; /* Top, length and used items */
4092  do {
4093  pcl = cl; ncl++;
4094  cl = get_fat(&fp->obj, cl);
4095  if (cl <= 1) ABORT(fs, FR_INT_ERR);
4096  if (cl == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR);
4097  } while (cl == pcl + 1);
4098  if (ulen <= tlen) { /* Store the length and top of the fragment */
4099  *tbl++ = ncl; *tbl++ = tcl;
4100  }
4101  } while (cl < fs->n_fatent); /* Repeat until end of chain */
4102  }
4103  *fp->cltbl = ulen; /* Number of items used */
4104  if (ulen <= tlen) {
4105  *tbl = 0; /* Terminate table */
4106  } else {
4107  res = FR_NOT_ENOUGH_CORE; /* Given table size is smaller than required */
4108  }
4109  } else { /* Fast seek */
4110  if (ofs > fp->obj.objsize) ofs = fp->obj.objsize; /* Clip offset at the file size */
4111  fp->fptr = ofs; /* Set file pointer */
4112  if (ofs) {
4113  fp->clust = clmt_clust(fp, ofs - 1);
4114  dsc = clust2sect(fs, fp->clust);
4115  if (!dsc) ABORT(fs, FR_INT_ERR);
4116  dsc += (DWORD)((ofs - 1) / SS(fs)) & (fs->csize - 1);
4117  if (fp->fptr % SS(fs) && dsc != fp->sect) { /* Refill sector cache if needed */
4118 #if !_FS_TINY
4119 #if !_FS_READONLY
4120  if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */
4121  if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);
4122  fp->flag &= (BYTE)~FA_DIRTY;
4123  }
4124 #endif
4125  if (disk_read(fs->drv, fp->buf, dsc, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Load current sector */
4126 #endif
4127  fp->sect = dsc;
4128  }
4129  }
4130  }
4131  } else
4132 #endif
4133 
4134  /* Normal Seek */
4135  {
4136 #if _FS_EXFAT
4137  if (fs->fs_type != FS_EXFAT && ofs >= 0x100000000) ofs = 0xFFFFFFFF; /* Clip at 4GiB-1 if at FATxx */
4138 #endif
4139  if (ofs > fp->obj.objsize && (_FS_READONLY || !(fp->flag & FA_WRITE))) { /* In read-only mode, clip offset with the file size */
4140  ofs = fp->obj.objsize;
4141  }
4142  ifptr = fp->fptr;
4143  fp->fptr = nsect = 0;
4144  if (ofs) {
4145  bcs = (DWORD)fs->csize * SS(fs); /* Cluster size (byte) */
4146  if (ifptr > 0 &&
4147  (ofs - 1) / bcs >= (ifptr - 1) / bcs) { /* When seek to same or following cluster, */
4148  fp->fptr = (ifptr - 1) & ~(FSIZE_t)(bcs - 1); /* start from the current cluster */
4149  ofs -= fp->fptr;
4150  clst = fp->clust;
4151  } else { /* When seek to back cluster, */
4152  clst = fp->obj.sclust; /* start from the first cluster */
4153 #if !_FS_READONLY
4154  if (clst == 0) { /* If no cluster chain, create a new chain */
4155  clst = create_chain(&fp->obj, 0);
4156  if (clst == 1) ABORT(fs, FR_INT_ERR);
4157  if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR);
4158  fp->obj.sclust = clst;
4159  }
4160 #endif
4161  fp->clust = clst;
4162  }
4163  if (clst != 0) {
4164  while (ofs > bcs) { /* Cluster following loop */
4165  ofs -= bcs; fp->fptr += bcs;
4166 #if !_FS_READONLY
4167  if (fp->flag & FA_WRITE) { /* Check if in write mode or not */
4168  if (_FS_EXFAT && fp->fptr > fp->obj.objsize) { /* No FAT chain object needs correct objsize to generate FAT value */
4169  fp->obj.objsize = fp->fptr;
4170  fp->flag |= FA_MODIFIED;
4171  }
4172  clst = create_chain(&fp->obj, clst); /* Follow chain with forceed stretch */
4173  if (clst == 0) { /* Clip file size in case of disk full */
4174  ofs = 0; break;
4175  }
4176  } else
4177 #endif
4178  {
4179  clst = get_fat(&fp->obj, clst); /* Follow cluster chain if not in write mode */
4180  }
4181  if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR);
4182  if (clst <= 1 || clst >= fs->n_fatent) ABORT(fs, FR_INT_ERR);
4183  fp->clust = clst;
4184  }
4185  fp->fptr += ofs;
4186  if (ofs % SS(fs)) {
4187  nsect = clust2sect(fs, clst); /* Current sector */
4188  if (!nsect) ABORT(fs, FR_INT_ERR);
4189  nsect += (DWORD)(ofs / SS(fs));
4190  }
4191  }
4192  }
4193  if (!_FS_READONLY && fp->fptr > fp->obj.objsize) { /* Set file change flag if the file size is extended */
4194  fp->obj.objsize = fp->fptr;
4195  fp->flag |= FA_MODIFIED;
4196  }
4197  if (fp->fptr % SS(fs) && nsect != fp->sect) { /* Fill sector cache if needed */
4198 #if !_FS_TINY
4199 #if !_FS_READONLY
4200  if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */
4201  if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);
4202  fp->flag &= (BYTE)~FA_DIRTY;
4203  }
4204 #endif
4205  if (disk_read(fs->drv, fp->buf, nsect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */
4206 #endif
4207  fp->sect = nsect;
4208  }
4209  }
4210 
4211  LEAVE_FF(fs, res);
4212 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ f_opendir()

FRESULT f_opendir ( DIR dp,
const TCHAR path 
)
4225 {
4226  FRESULT res;
4227  FATFS *fs;
4228  _FDID *obj;
4229  DEF_NAMBUF
4230 
4231 
4232  if (!dp) return FR_INVALID_OBJECT;
4233 
4234  /* Get logical drive */
4235  obj = &dp->obj;
4236  res = find_volume(&path, &fs, 0);
4237  if (res == FR_OK) {
4238  obj->fs = fs;
4239  INIT_NAMBUF(fs);
4240  res = follow_path(dp, path); /* Follow the path to the directory */
4241  if (res == FR_OK) { /* Follow completed */
4242  if (!(dp->fn[NSFLAG] & NS_NONAME)) { /* It is not the origin directory itself */
4243  if (obj->attr & AM_DIR) { /* This object is a sub-directory */
4244 #if _FS_EXFAT
4245  if (fs->fs_type == FS_EXFAT) {
4246  obj->c_scl = obj->sclust; /* Get containing directory inforamation */
4247  obj->c_size = ((DWORD)obj->objsize & 0xFFFFFF00) | obj->stat;
4248  obj->c_ofs = dp->blk_ofs;
4249  obj->sclust = ld_dword(fs->dirbuf + XDIR_FstClus); /* Get object allocation info */
4250  obj->objsize = ld_qword(fs->dirbuf + XDIR_FileSize);
4251  obj->stat = fs->dirbuf[XDIR_GenFlags] & 2;
4252  } else
4253 #endif
4254  {
4255  obj->sclust = ld_clust(fs, dp->dir); /* Get object allocation info */
4256  }
4257  } else { /* This object is a file */
4258  res = FR_NO_PATH;
4259  }
4260  }
4261  if (res == FR_OK) {
4262  obj->id = fs->id;
4263  res = dir_sdi(dp, 0); /* Rewind directory */
4264 #if _FS_LOCK != 0
4265  if (res == FR_OK) {
4266  if (obj->sclust) {
4267  obj->lockid = inc_lock(dp, 0); /* Lock the sub directory */
4268  if (!obj->lockid) res = FR_TOO_MANY_OPEN_FILES;
4269  } else {
4270  obj->lockid = 0; /* Root directory need not to be locked */
4271  }
4272  }
4273 #endif
4274  }
4275  }
4276  FREE_NAMBUF();
4277  if (res == FR_NO_FILE) res = FR_NO_PATH;
4278  }
4279  if (res != FR_OK) obj->fs = 0; /* Invalidate the directory object if function faild */
4280 
4281  LEAVE_FF(fs, res);
4282 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ f_closedir()

FRESULT f_closedir ( DIR dp)
4294 {
4295  FRESULT res;
4296  FATFS *fs;
4297 
4298 
4299  res = validate(&dp->obj, &fs); /* Check validity of the file object */
4300  if (res == FR_OK) {
4301 #if _FS_LOCK != 0
4302  if (dp->obj.lockid) { /* Decrement sub-directory open counter */
4303  res = dec_lock(dp->obj.lockid);
4304  }
4305  if (res == FR_OK)
4306 #endif
4307  {
4308  dp->obj.fs = 0; /* Invalidate directory object */
4309  }
4310 #if _FS_REENTRANT
4311  unlock_fs(fs, FR_OK); /* Unlock volume */
4312 #endif
4313  }
4314  return res;
4315 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ f_readdir()

FRESULT f_readdir ( DIR dp,
FILINFO fno 
)
4328 {
4329  FRESULT res;
4330  FATFS *fs;
4331  DEF_NAMBUF
4332 
4333 
4334  res = validate(&dp->obj, &fs); /* Check validity of the directory object */
4335  if (res == FR_OK) {
4336  if (!fno) {
4337  res = dir_sdi(dp, 0); /* Rewind the directory object */
4338  } else {
4339  INIT_NAMBUF(fs);
4340  res = dir_read(dp, 0); /* Read an item */
4341  if (res == FR_NO_FILE) res = FR_OK; /* Ignore end of directory */
4342  if (res == FR_OK) { /* A valid entry is found */
4343  get_fileinfo(dp, fno); /* Get the object information */
4344  res = dir_next(dp, 0); /* Increment index for next */
4345  if (res == FR_NO_FILE) res = FR_OK; /* Ignore end of directory now */
4346  }
4347  FREE_NAMBUF();
4348  }
4349  }
4350  LEAVE_FF(fs, res);
4351 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ f_stat()

FRESULT f_stat ( const TCHAR path,
FILINFO fno 
)
4416 {
4417  FRESULT res;
4418  DIR dj;
4419  DEF_NAMBUF
4420 
4421 
4422  /* Get logical drive */
4423  res = find_volume(&path, &dj.obj.fs, 0);
4424  if (res == FR_OK) {
4425  INIT_NAMBUF(dj.obj.fs);
4426  res = follow_path(&dj, path); /* Follow the file path */
4427  if (res == FR_OK) { /* Follow completed */
4428  if (dj.fn[NSFLAG] & NS_NONAME) { /* It is origin directory */
4429  res = FR_INVALID_NAME;
4430  } else { /* Found an object */
4431  if (fno) get_fileinfo(&dj, fno);
4432  }
4433  }
4434  FREE_NAMBUF();
4435  }
4436 
4437  LEAVE_FF(dj.obj.fs, res);
4438 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ f_getfree()

FRESULT f_getfree ( const TCHAR path,
DWORD nclst,
FATFS **  fatfs 
)
4452 {
4453  FRESULT res;
4454  FATFS *fs;
4455  DWORD nfree, clst, sect, stat;
4456  UINT i;
4457  BYTE *p;
4458  _FDID obj;
4459 
4460 
4461  /* Get logical drive */
4462  res = find_volume(&path, &fs, 0);
4463  if (res == FR_OK) {
4464  *fatfs = fs; /* Return ptr to the fs object */
4465  /* If free_clst is valid, return it without full cluster scan */
4466  if (fs->free_clst <= fs->n_fatent - 2) {
4467  *nclst = fs->free_clst;
4468  } else {
4469  /* Get number of free clusters */
4470  nfree = 0;
4471  if (fs->fs_type == FS_FAT12) { /* FAT12: Sector unalighed FAT entries */
4472  clst = 2; obj.fs = fs;
4473  do {
4474  stat = get_fat(&obj, clst);
4475  if (stat == 0xFFFFFFFF) { res = FR_DISK_ERR; break; }
4476  if (stat == 1) { res = FR_INT_ERR; break; }
4477  if (stat == 0) nfree++;
4478  } while (++clst < fs->n_fatent);
4479  } else {
4480 #if _FS_EXFAT
4481  if (fs->fs_type == FS_EXFAT) { /* exFAT: Scan bitmap table */
4482  BYTE bm;
4483  UINT b;
4484 
4485  clst = fs->n_fatent - 2;
4486  sect = fs->database;
4487  i = 0;
4488  do {
4489  if (i == 0 && (res = move_window(fs, sect++)) != FR_OK) break;
4490  for (b = 8, bm = fs->win[i]; b && clst; b--, clst--) {
4491  if (!(bm & 1)) nfree++;
4492  bm >>= 1;
4493  }
4494  i = (i + 1) % SS(fs);
4495  } while (clst);
4496  } else
4497 #endif
4498  { /* FAT16/32: Sector alighed FAT entries */
4499  clst = fs->n_fatent; sect = fs->fatbase;
4500  i = 0; p = 0;
4501  do {
4502  if (i == 0) {
4503  res = move_window(fs, sect++);
4504  if (res != FR_OK) break;
4505  p = fs->win;
4506  i = SS(fs);
4507  }
4508  if (fs->fs_type == FS_FAT16) {
4509  if (ld_word(p) == 0) nfree++;
4510  p += 2; i -= 2;
4511  } else {
4512  if ((ld_dword(p) & 0x0FFFFFFF) == 0) nfree++;
4513  p += 4; i -= 4;
4514  }
4515  } while (--clst);
4516  }
4517  }
4518  *nclst = nfree; /* Return the free clusters */
4519  fs->free_clst = nfree; /* Now free_clst is valid */
4520  fs->fsi_flag |= 1; /* FSInfo is to be updated */
4521  }
4522  }
4523 
4524  LEAVE_FF(fs, res);
4525 }
Here is the call graph for this function:

◆ f_truncate()

FRESULT f_truncate ( FIL fp)
4537 {
4538  FRESULT res;
4539  FATFS *fs;
4540  DWORD ncl;
4541 
4542 
4543  res = validate(&fp->obj, &fs); /* Check validity of the file object */
4544  if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res);
4545  if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */
4546 
4547  if (fp->fptr < fp->obj.objsize) { /* Process when fptr is not on the eof */
4548  if (fp->fptr == 0) { /* When set file size to zero, remove entire cluster chain */
4549  res = remove_chain(&fp->obj, fp->obj.sclust, 0);
4550  fp->obj.sclust = 0;
4551  } else { /* When truncate a part of the file, remove remaining clusters */
4552  ncl = get_fat(&fp->obj, fp->clust);
4553  res = FR_OK;
4554  if (ncl == 0xFFFFFFFF) res = FR_DISK_ERR;
4555  if (ncl == 1) res = FR_INT_ERR;
4556  if (res == FR_OK && ncl < fs->n_fatent) {
4557  res = remove_chain(&fp->obj, ncl, fp->clust);
4558  }
4559  }
4560  fp->obj.objsize = fp->fptr; /* Set file size to current R/W point */
4561  fp->flag |= FA_MODIFIED;
4562 #if !_FS_TINY
4563  if (res == FR_OK && (fp->flag & FA_DIRTY)) {
4564  if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) {
4565  res = FR_DISK_ERR;
4566  } else {
4567  fp->flag &= (BYTE)~FA_DIRTY;
4568  }
4569  }
4570 #endif
4571  if (res != FR_OK) ABORT(fs, res);
4572  }
4573 
4574  LEAVE_FF(fs, res);
4575 }
Here is the call graph for this function:

◆ f_unlink()

FRESULT f_unlink ( const TCHAR path)
4587 {
4588  FRESULT res;
4589  DIR dj, sdj;
4590  DWORD dclst = 0;
4591  FATFS *fs;
4592 #if _FS_EXFAT
4593  _FDID obj;
4594 #endif
4595  DEF_NAMBUF
4596 
4597 
4598  /* Get logical drive */
4599  res = find_volume(&path, &fs, FA_WRITE);
4600  dj.obj.fs = fs;
4601  if (res == FR_OK) {
4602  INIT_NAMBUF(fs);
4603  res = follow_path(&dj, path); /* Follow the file path */
4604  if (_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) {
4605  res = FR_INVALID_NAME; /* Cannot remove dot entry */
4606  }
4607 #if _FS_LOCK != 0
4608  if (res == FR_OK) res = chk_lock(&dj, 2); /* Check if it is an open object */
4609 #endif
4610  if (res == FR_OK) { /* The object is accessible */
4611  if (dj.fn[NSFLAG] & NS_NONAME) {
4612  res = FR_INVALID_NAME; /* Cannot remove the origin directory */
4613  } else {
4614  if (dj.obj.attr & AM_RDO) {
4615  res = FR_DENIED; /* Cannot remove R/O object */
4616  }
4617  }
4618  if (res == FR_OK) {
4619 #if _FS_EXFAT
4620  obj.fs = fs;
4621  if (fs->fs_type == FS_EXFAT) {
4622  obj.sclust = dclst = ld_dword(fs->dirbuf + XDIR_FstClus);
4623  obj.objsize = ld_qword(fs->dirbuf + XDIR_FileSize);
4624  obj.stat = fs->dirbuf[XDIR_GenFlags] & 2;
4625  } else
4626 #endif
4627  {
4628  dclst = ld_clust(fs, dj.dir);
4629  }
4630  if (dj.obj.attr & AM_DIR) { /* Is it a sub-directory? */
4631 #if _FS_RPATH != 0
4632  if (dclst == fs->cdir) { /* Is it the current directory? */
4633  res = FR_DENIED;
4634  } else
4635 #endif
4636  {
4637  sdj.obj.fs = fs; /* Open the sub-directory */
4638  sdj.obj.sclust = dclst;
4639 #if _FS_EXFAT
4640  if (fs->fs_type == FS_EXFAT) {
4641  sdj.obj.objsize = obj.objsize;
4642  sdj.obj.stat = obj.stat;
4643  }
4644 #endif
4645  res = dir_sdi(&sdj, 0);
4646  if (res == FR_OK) {
4647  res = dir_read(&sdj, 0); /* Read an item */
4648  if (res == FR_OK) res = FR_DENIED; /* Not empty? */
4649  if (res == FR_NO_FILE) res = FR_OK; /* Empty? */
4650  }
4651  }
4652  }
4653  }
4654  if (res == FR_OK) {
4655  res = dir_remove(&dj); /* Remove the directory entry */
4656  if (res == FR_OK && dclst) { /* Remove the cluster chain if exist */
4657 #if _FS_EXFAT
4658  res = remove_chain(&obj, dclst, 0);
4659 #else
4660  res = remove_chain(&dj.obj, dclst, 0);
4661 #endif
4662  }
4663  if (res == FR_OK) res = sync_fs(fs);
4664  }
4665  }
4666  FREE_NAMBUF();
4667  }
4668 
4669  LEAVE_FF(fs, res);
4670 }
Here is the call graph for this function:

◆ f_mkdir()

FRESULT f_mkdir ( const TCHAR path)
4682 {
4683  FRESULT res;
4684  DIR dj;
4685  FATFS *fs;
4686  BYTE *dir;
4687  UINT n;
4688  DWORD dsc, dcl, pcl, tm;
4689  DEF_NAMBUF
4690 
4691 
4692  /* Get logical drive */
4693  res = find_volume(&path, &fs, FA_WRITE);
4694  dj.obj.fs = fs;
4695  if (res == FR_OK) {
4696  INIT_NAMBUF(fs);
4697  res = follow_path(&dj, path); /* Follow the file path */
4698  if (res == FR_OK) res = FR_EXIST; /* Any object with same name is already existing */
4699  if (_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) {
4700  res = FR_INVALID_NAME;
4701  }
4702  if (res == FR_NO_FILE) { /* Can create a new directory */
4703  dcl = create_chain(&dj.obj, 0); /* Allocate a cluster for the new directory table */
4704  dj.obj.objsize = (DWORD)fs->csize * SS(fs);
4705  res = FR_OK;
4706  if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster */
4707  if (dcl == 1) res = FR_INT_ERR;
4708  if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR;
4709  if (res == FR_OK) res = sync_window(fs); /* Flush FAT */
4710  tm = GET_FATTIME();
4711  if (res == FR_OK) { /* Initialize the new directory table */
4712  dsc = clust2sect(fs, dcl);
4713  dir = fs->win;
4714  mem_set(dir, 0, SS(fs));
4715  if (!_FS_EXFAT || fs->fs_type != FS_EXFAT) {
4716  mem_set(dir + DIR_Name, ' ', 11); /* Create "." entry */
4717  dir[DIR_Name] = '.';
4718  dir[DIR_Attr] = AM_DIR;
4719  st_dword(dir + DIR_ModTime, tm);
4720  st_clust(fs, dir, dcl);
4721  mem_cpy(dir + SZDIRE, dir, SZDIRE); /* Create ".." entry */
4722  dir[SZDIRE + 1] = '.'; pcl = dj.obj.sclust;
4723  if (fs->fs_type == FS_FAT32 && pcl == fs->dirbase) pcl = 0;
4724  st_clust(fs, dir + SZDIRE, pcl);
4725  }
4726  for (n = fs->csize; n; n--) { /* Write dot entries and clear following sectors */
4727  fs->winsect = dsc++;
4728  fs->wflag = 1;
4729  res = sync_window(fs);
4730  if (res != FR_OK) break;
4731  mem_set(dir, 0, SS(fs));
4732  }
4733  }
4734  if (res == FR_OK) {
4735  res = dir_register(&dj); /* Register the object to the directoy */
4736  }
4737  if (res == FR_OK) {
4738 #if _FS_EXFAT
4739  if (fs->fs_type == FS_EXFAT) { /* Initialize directory entry block */
4740  st_dword(fs->dirbuf + XDIR_ModTime, tm); /* Created time */
4741  st_dword(fs->dirbuf + XDIR_FstClus, dcl); /* Table start cluster */
4742  st_dword(fs->dirbuf + XDIR_FileSize, (DWORD)dj.obj.objsize); /* File size needs to be valid */
4743  st_dword(fs->dirbuf + XDIR_ValidFileSize, (DWORD)dj.obj.objsize);
4744  fs->dirbuf[XDIR_GenFlags] = 3; /* Initialize the object flag (contiguous) */
4745  fs->dirbuf[XDIR_Attr] = AM_DIR; /* Attribute */
4746  res = store_xdir(&dj);
4747  } else
4748 #endif
4749  {
4750  dir = dj.dir;
4751  st_dword(dir + DIR_ModTime, tm); /* Created time */
4752  st_clust(fs, dir, dcl); /* Table start cluster */
4753  dir[DIR_Attr] = AM_DIR; /* Attribute */
4754  fs->wflag = 1;
4755  }
4756  if (res == FR_OK) {
4757  res = sync_fs(fs);
4758  }
4759  } else {
4760  remove_chain(&dj.obj, dcl, 0); /* Could not register, remove cluster chain */
4761  }
4762  }
4763  FREE_NAMBUF();
4764  }
4765 
4766  LEAVE_FF(fs, res);
4767 }
Here is the call graph for this function:

◆ f_rename()

FRESULT f_rename ( const TCHAR path_old,
const TCHAR path_new 
)
4780 {
4781  FRESULT res;
4782  DIR djo, djn;
4783  FATFS *fs;
4784  BYTE buf[_FS_EXFAT ? SZDIRE * 2 : 24], *dir;
4785  DWORD dw;
4786  DEF_NAMBUF
4787 
4788 
4789  get_ldnumber(&path_new); /* Snip drive number of new name off */
4790  res = find_volume(&path_old, &fs, FA_WRITE); /* Get logical drive of the old object */
4791  if (res == FR_OK) {
4792  djo.obj.fs = fs;
4793  INIT_NAMBUF(fs);
4794  res = follow_path(&djo, path_old); /* Check old object */
4795  if (res == FR_OK && (djo.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check validity of name */
4796 #if _FS_LOCK != 0
4797  if (res == FR_OK) {
4798  res = chk_lock(&djo, 2);
4799  }
4800 #endif
4801  if (res == FR_OK) { /* Object to be renamed is found */
4802 #if _FS_EXFAT
4803  if (fs->fs_type == FS_EXFAT) { /* At exFAT */
4804  BYTE nf, nn;
4805  WORD nh;
4806 
4807  mem_cpy(buf, fs->dirbuf, SZDIRE * 2); /* Save 85+C0 entry of old object */
4808  mem_cpy(&djn, &djo, sizeof djo);
4809  res = follow_path(&djn, path_new); /* Make sure if new object name is not in use */
4810  if (res == FR_OK) { /* Is new name already in use by any other object? */
4811  res = (djn.obj.sclust == djo.obj.sclust && djn.dptr == djo.dptr) ? FR_NO_FILE : FR_EXIST;
4812  }
4813  if (res == FR_NO_FILE) { /* It is a valid path and no name collision */
4814  res = dir_register(&djn); /* Register the new entry */
4815  if (res == FR_OK) {
4816  nf = fs->dirbuf[XDIR_NumSec]; nn = fs->dirbuf[XDIR_NumName];
4817  nh = ld_word(fs->dirbuf + XDIR_NameHash);
4818  mem_cpy(fs->dirbuf, buf, SZDIRE * 2);
4819  fs->dirbuf[XDIR_NumSec] = nf; fs->dirbuf[XDIR_NumName] = nn;
4820  st_word(fs->dirbuf + XDIR_NameHash, nh);
4821 /* Start of critical section where an interruption can cause a cross-link */
4822  res = store_xdir(&djn);
4823  }
4824  }
4825  } else
4826 #endif
4827  { /* At FAT12/FAT16/FAT32 */
4828  mem_cpy(buf, djo.dir + DIR_Attr, 21); /* Save information about the object except name */
4829  mem_cpy(&djn, &djo, sizeof (DIR)); /* Duplicate the directory object */
4830  res = follow_path(&djn, path_new); /* Make sure if new object name is not in use */
4831  if (res == FR_OK) { /* Is new name already in use by any other object? */
4832  res = (djn.obj.sclust == djo.obj.sclust && djn.dptr == djo.dptr) ? FR_NO_FILE : FR_EXIST;
4833  }
4834  if (res == FR_NO_FILE) { /* It is a valid path and no name collision */
4835  res = dir_register(&djn); /* Register the new entry */
4836  if (res == FR_OK) {
4837  dir = djn.dir; /* Copy information about object except name */
4838  mem_cpy(dir + 13, buf + 2, 19);
4839  dir[DIR_Attr] = buf[0] | AM_ARC;
4840  fs->wflag = 1;
4841  if ((dir[DIR_Attr] & AM_DIR) && djo.obj.sclust != djn.obj.sclust) { /* Update .. entry in the sub-directory if needed */
4842  dw = clust2sect(fs, ld_clust(fs, dir));
4843  if (!dw) {
4844  res = FR_INT_ERR;
4845  } else {
4846 /* Start of critical section where an interruption can cause a cross-link */
4847  res = move_window(fs, dw);
4848  dir = fs->win + SZDIRE * 1; /* Ptr to .. entry */
4849  if (res == FR_OK && dir[1] == '.') {
4850  st_clust(fs, dir, djn.obj.sclust);
4851  fs->wflag = 1;
4852  }
4853  }
4854  }
4855  }
4856  }
4857  }
4858  if (res == FR_OK) {
4859  res = dir_remove(&djo); /* Remove old entry */
4860  if (res == FR_OK) {
4861  res = sync_fs(fs);
4862  }
4863  }
4864 /* End of the critical section */
4865  }
4866  FREE_NAMBUF();
4867  }
4868 
4869  LEAVE_FF(fs, res);
4870 }
Here is the call graph for this function:

Variable Documentation

◆ FatFs

FATFS* FatFs[_VOLUMES]
static

◆ Fsid

WORD Fsid
static
dir_read
static FRESULT dir_read(DIR *dp, int vol)
Definition: ff.c:2131
ff_wtoupper
WCHAR ff_wtoupper(WCHAR chr)
Definition: ccsbcs.c:303
STA_NOINIT
#define STA_NOINIT
Definition: onboard_sd.h:55
FR_NOT_ENOUGH_CORE
Definition: ff.h:232
FA_OPEN_ALWAYS
#define FA_OPEN_ALWAYS
Definition: ff.h:331
check_fs
static BYTE check_fs(FATFS *fs, DWORD sect)
Definition: ff.c:2964
XDIR_FstClus
#define XDIR_FstClus
Definition: ff.c:427
BPB_ZeroedEx
#define BPB_ZeroedEx
Definition: ff.c:373
TCHAR
char TCHAR
Definition: ff.h:62
BPB_FSVerEx
#define BPB_FSVerEx
Definition: ff.c:382
FSI_Free_Count
#define FSI_Free_Count
Definition: ff.c:437
XDIR_FileSize
#define XDIR_FileSize
Definition: ff.c:428
NS_LOSS
#define NS_LOSS
Definition: ff.c:314
dir_next
static FRESULT dir_next(DIR *dp, int stretch)
Definition: ff.c:1519
XDIR_ValidFileSize
#define XDIR_ValidFileSize
Definition: ff.c:426
FR_DISK_ERR
Definition: ff.h:216
FR_INVALID_OBJECT
Definition: ff.h:224
DIR_CrtTime
#define DIR_CrtTime
Definition: ff.c:397
FR_EXIST
Definition: ff.h:223
FATFS::last_clst
DWORD last_clst
Definition: ff.h:107
FATFS::fatbase
DWORD fatbase
Definition: ff.h:121
dir_sdi
static FRESULT dir_sdi(DIR *dp, DWORD ofs)
Definition: ff.c:1470
_FDID::stat
BYTE stat
Definition: ff.h:136
NS_EXT
#define NS_EXT
Definition: ff.c:318
LLEF
#define LLEF
Definition: ff.c:433
MAX_DIR
#define MAX_DIR
Definition: ff.c:325
DIR_FstClusHI
#define DIR_FstClusHI
Definition: ff.c:399
FR_NO_FILE
Definition: ff.h:219
BPB_FSVer32
#define BPB_FSVer32
Definition: ff.c:361
BS_FilSysType32
#define BS_FilSysType32
Definition: ff.c:370
FA_WRITE
#define FA_WRITE
Definition: ff.h:327
st_dword
static void st_dword(BYTE *ptr, DWORD val)
Definition: ff.c:661
DIR_FileSize
#define DIR_FileSize
Definition: ff.c:402
XDIR_AccTime
#define XDIR_AccTime
Definition: ff.c:417
FATFS::csize
WORD csize
Definition: ff.h:93
DIR_NTres
#define DIR_NTres
Definition: ff.c:395
NS_LFN
#define NS_LFN
Definition: ff.c:315
disk_initialize
DSTATUS disk_initialize(BYTE pdrv)
Initializes a Drive.
Definition: diskio.c:91
FILINFO::fattrib
BYTE fattrib
Definition: ff.h:201
LDIR_Chksum
#define LDIR_Chksum
Definition: ff.c:406
FIL::fptr
FSIZE_t fptr
Definition: ff.h:159
FATFS::winsect
DWORD winsect
Definition: ff.h:124
dir_find
static FRESULT dir_find(DIR *dp)
Definition: ff.c:2210
CREATE_LINKMAP
#define CREATE_LINKMAP
Definition: ff.h:335
INIT_NAMBUF
#define INIT_NAMBUF(fs)
Definition: ff.c:546
FR_NO_PATH
Definition: ff.h:220
FA_OPEN_APPEND
#define FA_OPEN_APPEND
Definition: ff.h:332
BPB_NumClusEx
#define BPB_NumClusEx
Definition: ff.c:379
FIL::clust
DWORD clust
Definition: ff.h:160
LD2PD
#define LD2PD(vol)
Definition: ff.c:476
dir_remove
static FRESULT dir_remove(DIR *dp)
Definition: ff.c:2396
validate
static FRESULT validate(_FDID *obj, FATFS **fs)
Definition: ff.c:3215
BPB_FATSz16
#define BPB_FATSz16
Definition: ff.c:345
FA_CREATE_ALWAYS
#define FA_CREATE_ALWAYS
Definition: ff.h:330
FATFS::n_fatent
DWORD n_fatent
Definition: ff.h:118
MBR_Table
#define MBR_Table
Definition: ff.c:440
WORD
unsigned short WORD
Definition: onboard_sd.h:14
FILINFO::fdate
WORD fdate
Definition: ff.h:199
BS_JmpBoot
#define BS_JmpBoot
Definition: ff.c:336
FIL::obj
_FDID obj
Definition: ff.h:156
disk_read
DRESULT disk_read(BYTE pdrv, BYTE *buff, DWORD sector, UINT count)
Reads Sector(s)
Definition: diskio.c:113
BPB_SecPerClus
#define BPB_SecPerClus
Definition: ff.c:339
i
uint8_t i
Definition: screen_test_graph.c:72
get_fileinfo
static void get_fileinfo(DIR *dp, FILINFO *fno)
Definition: ff.c:2444
FS_EXFAT
#define FS_EXFAT
Definition: ff.h:348
BS_55AA
#define BS_55AA
Definition: ff.c:357
_FDID::sclust
DWORD sclust
Definition: ff.h:137
DIR::clust
DWORD clust
Definition: ff.h:181
FSIZE_t
DWORD FSIZE_t
Definition: ff.h:78
ld_clust
static DWORD ld_clust(FATFS *fs, const BYTE *dir)
Definition: ff.c:1632
BPB_RootClusEx
#define BPB_RootClusEx
Definition: ff.c:380
NS_NONAME
#define NS_NONAME
Definition: ff.c:321
FR_WRITE_PROTECTED
Definition: ff.h:225
clust2sect
static DWORD clust2sect(FATFS *fs, DWORD clst)
Definition: ff.c:983
IsLower
#define IsLower(c)
Definition: ff.c:275
FSI_LeadSig
#define FSI_LeadSig
Definition: ff.c:435
remove_chain
static FRESULT remove_chain(_FDID *obj, DWORD clst, DWORD pclst)
Definition: ff.c:1271
BPB_NumFATsEx
#define BPB_NumFATsEx
Definition: ff.c:387
FS_FAT16
#define FS_FAT16
Definition: ff.h:346
put_fat
static FRESULT put_fat(FATFS *fs, DWORD clst, DWORD val)
Definition: ff.c:1081
_VOLUMES
#define _VOLUMES
Definition: ffconf.h:194
DIR_ModTime
#define DIR_ModTime
Definition: ff.c:400
DIR::fn
BYTE fn[12]
Definition: ff.h:184
dir_register
static FRESULT dir_register(DIR *dp)
Definition: ff.c:2292
DIR::dptr
DWORD dptr
Definition: ff.h:180
FIL::flag
BYTE flag
Definition: ff.h:157
sync_window
static FRESULT sync_window(FATFS *fs)
Definition: ff.c:883
FSI_StrucSig
#define FSI_StrucSig
Definition: ff.c:436
STA_PROTECT
#define STA_PROTECT
Definition: onboard_sd.h:57
NSFLAG
#define NSFLAG
Definition: ff.c:313
DIR_Name
#define DIR_Name
Definition: ff.c:393
DIR_FstClusLO
#define DIR_FstClusLO
Definition: ff.c:401
ld_word
static WORD ld_word(const BYTE *ptr)
Definition: ff.c:613
DIR::dir
BYTE * dir
Definition: ff.h:183
BYTE
#define BYTE
Definition: MarlinSerial.h:142
FATFS::n_rootdir
WORD n_rootdir
Definition: ff.h:92
BPB_BytsPerSec
#define BPB_BytsPerSec
Definition: ff.c:338
st_clust
static void st_clust(FATFS *fs, BYTE *dir, DWORD cl)
Definition: ff.c:1650
FA_MODIFIED
#define FA_MODIFIED
Definition: ff.c:308
_FS_RPATH
#define _FS_RPATH
Definition: ffconf.h:182
NS_NOLFN
#define NS_NOLFN
Definition: ff.c:320
BPB_FATSz32
#define BPB_FATSz32
Definition: ff.c:359
mem_cpy
static void mem_cpy(void *dst, const void *src, UINT cnt)
Definition: ff.c:693
BS_FilSysType
#define BS_FilSysType
Definition: ff.c:355
XDIR_CrtTime
#define XDIR_CrtTime
Definition: ff.c:415
ld_dword
static DWORD ld_dword(const BYTE *ptr)
Definition: ff.c:623
FR_NOT_ENABLED
Definition: ff.h:227
FATFS::fsi_flag
BYTE fsi_flag
Definition: ff.h:90
XDIR_NameHash
#define XDIR_NameHash
Definition: ff.c:425
FATFS::n_fats
BYTE n_fats
Definition: ff.h:88
MAX_FAT12
#define MAX_FAT12
Definition: ff.c:327
_FDID::objsize
FSIZE_t objsize
Definition: ff.h:138
FATFS
Definition: ff.h:85
XDIR_ModTime
#define XDIR_ModTime
Definition: ff.c:416
FA_READ
#define FA_READ
Definition: ff.h:326
FS_FAT32
#define FS_FAT32
Definition: ff.h:347
follow_path
static FRESULT follow_path(DIR *dp, const TCHAR *path)
Definition: ff.c:2812
XDIR_Attr
#define XDIR_Attr
Definition: ff.c:414
BPB_TotSecEx
#define BPB_TotSecEx
Definition: ff.c:375
st_word
static void st_word(BYTE *ptr, WORD val)
Definition: ff.c:654
find_volume
static FRESULT find_volume(const TCHAR **path, FATFS **rfs, BYTE mode)
Definition: ff.c:2992
GET_FATTIME
#define GET_FATTIME()
Definition: ff.c:499
NS_BODY
#define NS_BODY
Definition: ff.c:317
BPB_TotSec32
#define BPB_TotSec32
Definition: ff.c:349
create_chain
static DWORD create_chain(_FDID *obj, DWORD clst)
Definition: ff.c:1351
SZ_PTE
#define SZ_PTE
Definition: ff.c:441
MAX_FAT16
#define MAX_FAT16
Definition: ff.c:328
FILINFO::ftime
WORD ftime
Definition: ff.h:200
mem_set
static void mem_set(void *dst, int val, UINT cnt)
Definition: ff.c:706
AM_VOL
#define AM_VOL
Definition: ff.c:301
FIL::dir_ptr
BYTE * dir_ptr
Definition: ff.h:164
FA_SEEKEND
#define FA_SEEKEND
Definition: ff.c:307
_FDID::id
WORD id
Definition: ff.h:134
NS_DOT
#define NS_DOT
Definition: ff.c:319
BPB_BytsPerSecEx
#define BPB_BytsPerSecEx
Definition: ff.c:385
RES_OK
Definition: onboard_sd.h:23
FR_DENIED
Definition: ff.h:222
DIR_Attr
#define DIR_Attr
Definition: ff.c:394
BPB_DataOfsEx
#define BPB_DataOfsEx
Definition: ff.c:378
disk_status
DSTATUS disk_status(BYTE pdrv)
Gets Disk Status.
Definition: diskio.c:76
BPB_FSInfo32
#define BPB_FSInfo32
Definition: ff.c:363
DIR::sect
DWORD sect
Definition: ff.h:182
Fsid
static WORD Fsid
Definition: ff.c:534
mem_cmp
static int mem_cmp(const void *dst, const void *src, UINT cnt)
Definition: ff.c:716
_MAX_LFN
#define _MAX_LFN
Definition: ffconf.h:150
FR_NOT_READY
Definition: ff.h:218
if
if(size<=((png_alloc_size_t) -1) - ob)
Definition: pngwrite.c:2176
DSTATUS
BYTE DSTATUS
Definition: onboard_sd.h:19
createSpeedLookupTable.a
list a
Definition: createSpeedLookupTable.py:29
BPB_RootClus32
#define BPB_RootClus32
Definition: ff.c:362
FATFS::id
WORD id
Definition: ff.h:91
FSI_Nxt_Free
#define FSI_Nxt_Free
Definition: ff.c:438
BPB_FatSzEx
#define BPB_FatSzEx
Definition: ff.c:377
FIL::err
BYTE err
Definition: ff.h:158
_VOLUME_STRS
#define _VOLUME_STRS
Definition: ffconf.h:199
FATFS::fs_type
BYTE fs_type
Definition: ff.h:86
disk_write
DRESULT disk_write(BYTE pdrv, const BYTE *buff, DWORD sector, UINT count)
Writes Sector(s)
Definition: diskio.c:135
FATFS::wflag
BYTE wflag
Definition: ff.h:89
_FDID
Definition: ff.h:132
FR_NO_FILESYSTEM
Definition: ff.h:228
FATFS::win
BYTE win[_MAX_SS]
Definition: ff.h:125
FILINFO::fname
TCHAR fname[13]
Definition: ff.h:206
IsDBCS1
#define IsDBCS1(c)
Definition: ff.c:294
BPB_FatOfsEx
#define BPB_FatOfsEx
Definition: ff.c:376
FIL::dir_sect
DWORD dir_sect
Definition: ff.h:163
XDIR_GenFlags
#define XDIR_GenFlags
Definition: ff.c:423
XDIR_NumName
#define XDIR_NumName
Definition: ff.c:424
disk_ioctl
DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void *buff)
I/O control operation.
Definition: diskio.c:157
LEAVE_FF
#define LEAVE_FF(fs, res)
Definition: ff.c:467
SS
#define SS(fs)
Definition: ff.c:486
GET_SECTOR_SIZE
#define GET_SECTOR_SIZE
Definition: onboard_sd.h:64
FATFS::free_clst
DWORD free_clst
Definition: ff.h:108
DWORD
unsigned long DWORD
Definition: onboard_sd.h:15
get_fat
static DWORD get_fat(_FDID *obj, DWORD clst)
Definition: ff.c:1001
FR_INT_ERR
Definition: ff.h:217
_USE_LFN
#define _USE_LFN
Definition: ffconf.h:148
FRESULT
FRESULT
Definition: ff.h:214
AM_DIR
#define AM_DIR
Definition: ff.h:354
FATFS::volbase
DWORD volbase
Definition: ff.h:120
_FS_READONLY
#define _FS_READONLY
Definition: ffconf.h:69
_MIN_SS
#define _MIN_SS
Definition: ffconf.h:214
rbuff
uint8_t rbuff[10]
Definition: HardwareSerial.cpp:19
XDIR_NumSec
#define XDIR_NumSec
Definition: ff.c:412
_FS_EXFAT
#define _FS_EXFAT
Definition: ffconf.h:249
FR_OK
Definition: ff.h:215
FATFS::fsize
DWORD fsize
Definition: ff.h:119
IsUpper
#define IsUpper(c)
Definition: ff.c:274
FIL::buf
BYTE buf[_MAX_SS]
Definition: ff.h:170
FREE_NAMBUF
#define FREE_NAMBUF()
Definition: ff.c:547
MAX_EXFAT
#define MAX_EXFAT
Definition: ff.c:330
IsDBCS2
#define IsDBCS2(c)
Definition: ff.c:295
PTE_StLba
#define PTE_StLba
Definition: ff.c:450
FS_FAT12
#define FS_FAT12
Definition: ff.h:345
ENTER_FF
#define ENTER_FF(fs)
Definition: ff.c:466
ABORT
#define ABORT(fs, res)
Definition: ff.c:455
get_ldnumber
static int get_ldnumber(const TCHAR **path)
Definition: ff.c:2903
FIL::sect
DWORD sect
Definition: ff.h:161
DIR
Definition: ff.h:178
BPB_RsvdSecCnt
#define BPB_RsvdSecCnt
Definition: ff.c:340
AM_LFN
#define AM_LFN
Definition: ff.c:302
sync_fs
static FRESULT sync_fs(FATFS *fs)
Definition: ff.c:944
DDEM
#define DDEM
Definition: ff.c:431
FR_TOO_MANY_OPEN_FILES
Definition: ff.h:233
XDIR_CrtTime10
#define XDIR_CrtTime10
Definition: ff.c:418
BYTE
unsigned char BYTE
Definition: onboard_sd.h:13
FATFS::dirbase
DWORD dirbase
Definition: ff.h:122
_FDID::fs
FATFS * fs
Definition: ff.h:133
ff_convert
WCHAR ff_convert(WCHAR chr, UINT dir)
Definition: ccsbcs.c:275
FATFS::drv
BYTE drv
Definition: ff.h:87
createSpeedLookupTable.int
int
Definition: createSpeedLookupTable.py:15
XDIR_ModTime10
#define XDIR_ModTime10
Definition: ff.c:419
QWORD
unsigned long long QWORD
Definition: integer.h:34
FR_INVALID_NAME
Definition: ff.h:221
BPB_SecPerClusEx
#define BPB_SecPerClusEx
Definition: ff.c:386
RDDEM
#define RDDEM
Definition: ff.c:432
MAX_DIR_EX
#define MAX_DIR_EX
Definition: ff.c:326
DEF_NAMBUF
#define DEF_NAMBUF
Definition: ff.c:545
dir_alloc
static FRESULT dir_alloc(DIR *dp, UINT nent)
Definition: ff.c:1589
FA_DIRTY
#define FA_DIRTY
Definition: ff.c:309
CTRL_TRIM
#define CTRL_TRIM
Definition: onboard_sd.h:66
WCHAR
unsigned short WCHAR
Definition: integer.h:27
SZDIRE
#define SZDIRE
Definition: ff.c:430
BPB_TotSec16
#define BPB_TotSec16
Definition: ff.c:343
create_name
static FRESULT create_name(DIR *dp, const TCHAR **path)
Definition: ff.c:2617
LD2PT
#define LD2PT(vol)
Definition: ff.c:477
mode
png_structrp int mode
Definition: png.h:1139
createSpeedLookupTable.b
list b
Definition: createSpeedLookupTable.py:30
AM_RDO
#define AM_RDO
Definition: ff.h:351
UINT
unsigned int UINT
Definition: onboard_sd.h:16
AM_ARC
#define AM_ARC
Definition: ff.h:355
FR_INVALID_DRIVE
Definition: ff.h:226
PTE_System
#define PTE_System
Definition: ff.c:446
_USE_LABEL
#define _USE_LABEL
Definition: ffconf.h:109
AM_MASK
#define AM_MASK
Definition: ff.c:303
f_sync
FRESULT f_sync(FIL *fp)
Definition: ff.c:3720
FATFS::database
DWORD database
Definition: ff.h:123
BPB_NumFATs
#define BPB_NumFATs
Definition: ff.c:341
XDIR_Type
#define XDIR_Type
Definition: ff.c:408
DIR::obj
_FDID obj
Definition: ff.h:179
move_window
static FRESULT move_window(FATFS *fs, DWORD sector)
Definition: ff.c:912
CTRL_SYNC
#define CTRL_SYNC
Definition: onboard_sd.h:62
FA_CREATE_NEW
#define FA_CREATE_NEW
Definition: ff.h:329
chk_chr
static int chk_chr(const char *str, int chr)
Definition: ff.c:729
FatFs
static FATFS * FatFs[_VOLUMES]
Definition: ff.c:533
_FDID::attr
BYTE attr
Definition: ff.h:135
FILINFO::fsize
FSIZE_t fsize
Definition: ff.h:198
_MAX_SS
#define _MAX_SS
Definition: ffconf.h:215
NS_LAST
#define NS_LAST
Definition: ff.c:316
DIR_LstAccDate
#define DIR_LstAccDate
Definition: ff.c:398
BPB_RootEntCnt
#define BPB_RootEntCnt
Definition: ff.c:342