?login_element?

Subversion Repositories NedoOS

Rev

Rev 8 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*----------------------------------------------------------------------------/
  2. /  FatFs - Generic FAT Filesystem Module  R0.13c                              /
  3. /-----------------------------------------------------------------------------/
  4. /
  5. / Copyright (C) 2018, ChaN, all right reserved.
  6. /
  7. / FatFs module is an open source software. Redistribution and use of FatFs in
  8. / source and binary forms, with or without modification, are permitted provided
  9. / that the following condition is met:
  10. /
  11. / 1. Redistributions of source code must retain the above copyright notice,
  12. /    this condition and the following disclaimer.
  13. /
  14. / This software is provided by the copyright holder and contributors "AS IS"
  15. / and any warranties related to this software are DISCLAIMED.
  16. / The copyright owner or contributors be NOT LIABLE for any damages caused
  17. / by use of this software.
  18. /
  19. /----------------------------------------------------------------------------*/
  20.  
  21.  
  22. #include "ff.h"                 /* Declarations of FatFs API */
  23. #include "diskio.h"             /* Declarations of device I/O functions */
  24.  
  25.  
  26. /*--------------------------------------------------------------------------
  27.  
  28.    Module Private Definitions
  29.  
  30. ---------------------------------------------------------------------------*/
  31.  
  32. #if FF_DEFINED != 86604 /* Revision ID */
  33. #error Wrong include file (ff.h).
  34. #endif
  35.  
  36.  
  37. /* Limits and boundaries */
  38. #define MAX_DIR         0x200000                /* Max size of FAT directory */
  39. #define MAX_DIR_EX      0x10000000              /* Max size of exFAT directory */
  40. #define MAX_FAT12       0xFF5                   /* Max FAT12 clusters (differs from specs, but right for real DOS/Windows behavior) */
  41. #define MAX_FAT16       0xFFF5                  /* Max FAT16 clusters (differs from specs, but right for real DOS/Windows behavior) */
  42. #define MAX_FAT32       0x0FFFFFF5              /* Max FAT32 clusters (not specified, practical limit) */
  43. #define MAX_EXFAT       0x7FFFFFFD              /* Max exFAT clusters (differs from specs, implementation limit) */
  44.  
  45.  
  46. /* Character code support macros */
  47. #define IsUpper(c)              ((c) >= 'A' && (c) <= 'Z')
  48. #define IsLower(c)              ((c) >= 'a' && (c) <= 'z')
  49. #define IsDigit(c)              ((c) >= '0' && (c) <= '9')
  50. #define IsSurrogate(c)  ((c) >= 0xD800 && (c) <= 0xDFFF)
  51. #define IsSurrogateH(c) ((c) >= 0xD800 && (c) <= 0xDBFF)
  52. #define IsSurrogateL(c) ((c) >= 0xDC00 && (c) <= 0xDFFF)
  53.  
  54.  
  55. /* Additional file access control and file status flags for internal use */
  56. #define FA_SEEKEND      0x20    /* Seek to end of the file on file open */
  57. #define FA_MODIFIED     0x40    /* File has been modified */
  58. #define FA_DIRTY        0x80    /* FIL.buf[] needs to be written-back */
  59.  
  60.  
  61. /* Additional file attribute bits for internal use */
  62. #define AM_VOL          0x08    /* Volume label */
  63. #define AM_LFN          0x0F    /* LFN entry */
  64. #define AM_MASK         0x3F    /* Mask of defined bits */
  65.  
  66.  
  67. /* Name status flags in fn[11] */
  68. #define NSFLAG          11              /* Index of the name status byte */
  69. #define NS_LOSS         0x01    /* Out of 8.3 format */
  70. #define NS_LFN          0x02    /* Force to create LFN entry */
  71. #define NS_LAST         0x04    /* Last segment */
  72. #define NS_BODY         0x08    /* Lower case flag (body) */
  73. #define NS_EXT          0x10    /* Lower case flag (ext) */
  74. #define NS_DOT          0x20    /* Dot entry */
  75. #define NS_NOLFN        0x40    /* Do not find LFN */
  76. #define NS_NONAME       0x80    /* Not followed */
  77.  
  78.  
  79. /* exFAT directory entry types */
  80. #define ET_BITMAP       0x81    /* Allocation bitmap */
  81. #define ET_UPCASE       0x82    /* Up-case table */
  82. #define ET_VLABEL       0x83    /* Volume label */
  83. #define ET_FILEDIR      0x85    /* File and directory */
  84. #define ET_STREAM       0xC0    /* Stream extension */
  85. #define ET_FILENAME     0xC1    /* Name extension */
  86.  
  87.  
  88. /* FatFs refers the FAT structure as simple byte array instead of structure member
  89. / because the C structure is not binary compatible between different platforms */
  90.  
  91. #define BS_JmpBoot                      0               /* x86 jump instruction (3-byte) */
  92. #define BS_OEMName                      3               /* OEM name (8-byte) */
  93. #define BPB_BytsPerSec          11              /* Sector size [byte] (WORD) */
  94. #define BPB_SecPerClus          13              /* Cluster size [sector] (BYTE) */
  95. #define BPB_RsvdSecCnt          14              /* Size of reserved area [sector] (WORD) */
  96. #define BPB_NumFATs                     16              /* Number of FATs (BYTE) */
  97. #define BPB_RootEntCnt          17              /* Size of root directory area for FAT [entry] (WORD) */
  98. #define BPB_TotSec16            19              /* Volume size (16-bit) [sector] (WORD) */
  99. #define BPB_Media                       21              /* Media descriptor byte (BYTE) */
  100. #define BPB_FATSz16                     22              /* FAT size (16-bit) [sector] (WORD) */
  101. #define BPB_SecPerTrk           24              /* Number of sectors per track for int13h [sector] (WORD) */
  102. #define BPB_NumHeads            26              /* Number of heads for int13h (WORD) */
  103. #define BPB_HiddSec                     28              /* Volume offset from top of the drive (DWORD) */
  104. #define BPB_TotSec32            32              /* Volume size (32-bit) [sector] (DWORD) */
  105. #define BS_DrvNum                       36              /* Physical drive number for int13h (BYTE) */
  106. #define BS_NTres                        37              /* WindowsNT error flag (BYTE) */
  107. #define BS_BootSig                      38              /* Extended boot signature (BYTE) */
  108. #define BS_VolID                        39              /* Volume serial number (DWORD) */
  109. #define BS_VolLab                       43              /* Volume label string (8-byte) */
  110. #define BS_FilSysType           54              /* Filesystem type string (8-byte) */
  111. #define BS_BootCode                     62              /* Boot code (448-byte) */
  112. #define BS_55AA                         510             /* Signature word (WORD) */
  113.  
  114. #define BPB_FATSz32                     36              /* FAT32: FAT size [sector] (DWORD) */
  115. #define BPB_ExtFlags32          40              /* FAT32: Extended flags (WORD) */
  116. #define BPB_FSVer32                     42              /* FAT32: Filesystem version (WORD) */
  117. #define BPB_RootClus32          44              /* FAT32: Root directory cluster (DWORD) */
  118. #define BPB_FSInfo32            48              /* FAT32: Offset of FSINFO sector (WORD) */
  119. #define BPB_BkBootSec32         50              /* FAT32: Offset of backup boot sector (WORD) */
  120. #define BS_DrvNum32                     64              /* FAT32: Physical drive number for int13h (BYTE) */
  121. #define BS_NTres32                      65              /* FAT32: Error flag (BYTE) */
  122. #define BS_BootSig32            66              /* FAT32: Extended boot signature (BYTE) */
  123. #define BS_VolID32                      67              /* FAT32: Volume serial number (DWORD) */
  124. #define BS_VolLab32                     71              /* FAT32: Volume label string (8-byte) */
  125. #define BS_FilSysType32         82              /* FAT32: Filesystem type string (8-byte) */
  126. #define BS_BootCode32           90              /* FAT32: Boot code (420-byte) */
  127.  
  128. #define BPB_ZeroedEx            11              /* exFAT: MBZ field (53-byte) */
  129. #define BPB_VolOfsEx            64              /* exFAT: Volume offset from top of the drive [sector] (QWORD) */
  130. #define BPB_TotSecEx            72              /* exFAT: Volume size [sector] (QWORD) */
  131. #define BPB_FatOfsEx            80              /* exFAT: FAT offset from top of the volume [sector] (DWORD) */
  132. #define BPB_FatSzEx                     84              /* exFAT: FAT size [sector] (DWORD) */
  133. #define BPB_DataOfsEx           88              /* exFAT: Data offset from top of the volume [sector] (DWORD) */
  134. #define BPB_NumClusEx           92              /* exFAT: Number of clusters (DWORD) */
  135. #define BPB_RootClusEx          96              /* exFAT: Root directory start cluster (DWORD) */
  136. #define BPB_VolIDEx                     100             /* exFAT: Volume serial number (DWORD) */
  137. #define BPB_FSVerEx                     104             /* exFAT: Filesystem version (WORD) */
  138. #define BPB_VolFlagEx           106             /* exFAT: Volume flags (WORD) */
  139. #define BPB_BytsPerSecEx        108             /* exFAT: Log2 of sector size in unit of byte (BYTE) */
  140. #define BPB_SecPerClusEx        109             /* exFAT: Log2 of cluster size in unit of sector (BYTE) */
  141. #define BPB_NumFATsEx           110             /* exFAT: Number of FATs (BYTE) */
  142. #define BPB_DrvNumEx            111             /* exFAT: Physical drive number for int13h (BYTE) */
  143. #define BPB_PercInUseEx         112             /* exFAT: Percent in use (BYTE) */
  144. #define BPB_RsvdEx                      113             /* exFAT: Reserved (7-byte) */
  145. #define BS_BootCodeEx           120             /* exFAT: Boot code (390-byte) */
  146.  
  147. #define DIR_Name                        0               /* Short file name (11-byte) */
  148. #define DIR_Attr                        11              /* Attribute (BYTE) */
  149. #define DIR_NTres                       12              /* Lower case flag (BYTE) */
  150. #define DIR_CrtTime10           13              /* Created time sub-second (BYTE) */
  151. #define DIR_CrtTime                     14              /* Created time (DWORD) */
  152. #define DIR_LstAccDate          18              /* Last accessed date (WORD) */
  153. #define DIR_FstClusHI           20              /* Higher 16-bit of first cluster (WORD) */
  154. #define DIR_ModTime                     22              /* Modified time (DWORD) */
  155. #define DIR_FstClusLO           26              /* Lower 16-bit of first cluster (WORD) */
  156. #define DIR_FileSize            28              /* File size (DWORD) */
  157. #define LDIR_Ord                        0               /* LFN: LFN order and LLE flag (BYTE) */
  158. #define LDIR_Attr                       11              /* LFN: LFN attribute (BYTE) */
  159. #define LDIR_Type                       12              /* LFN: Entry type (BYTE) */
  160. #define LDIR_Chksum                     13              /* LFN: Checksum of the SFN (BYTE) */
  161. #define LDIR_FstClusLO          26              /* LFN: MBZ field (WORD) */
  162. #define XDIR_Type                       0               /* exFAT: Type of exFAT directory entry (BYTE) */
  163. #define XDIR_NumLabel           1               /* exFAT: Number of volume label characters (BYTE) */
  164. #define XDIR_Label                      2               /* exFAT: Volume label (11-WORD) */
  165. #define XDIR_CaseSum            4               /* exFAT: Sum of case conversion table (DWORD) */
  166. #define XDIR_NumSec                     1               /* exFAT: Number of secondary entries (BYTE) */
  167. #define XDIR_SetSum                     2               /* exFAT: Sum of the set of directory entries (WORD) */
  168. #define XDIR_Attr                       4               /* exFAT: File attribute (WORD) */
  169. #define XDIR_CrtTime            8               /* exFAT: Created time (DWORD) */
  170. #define XDIR_ModTime            12              /* exFAT: Modified time (DWORD) */
  171. #define XDIR_AccTime            16              /* exFAT: Last accessed time (DWORD) */
  172. #define XDIR_CrtTime10          20              /* exFAT: Created time subsecond (BYTE) */
  173. #define XDIR_ModTime10          21              /* exFAT: Modified time subsecond (BYTE) */
  174. #define XDIR_CrtTZ                      22              /* exFAT: Created timezone (BYTE) */
  175. #define XDIR_ModTZ                      23              /* exFAT: Modified timezone (BYTE) */
  176. #define XDIR_AccTZ                      24              /* exFAT: Last accessed timezone (BYTE) */
  177. #define XDIR_GenFlags           33              /* exFAT: General secondary flags (BYTE) */
  178. #define XDIR_NumName            35              /* exFAT: Number of file name characters (BYTE) */
  179. #define XDIR_NameHash           36              /* exFAT: Hash of file name (WORD) */
  180. #define XDIR_ValidFileSize      40              /* exFAT: Valid file size (QWORD) */
  181. #define XDIR_FstClus            52              /* exFAT: First cluster of the file data (DWORD) */
  182. #define XDIR_FileSize           56              /* exFAT: File/Directory size (QWORD) */
  183.  
  184. #define SZDIRE                          32              /* Size of a directory entry */
  185. #define DDEM                            0xE5    /* Deleted directory entry mark set to DIR_Name[0] */
  186. #define RDDEM                           0x05    /* Replacement of the character collides with DDEM */
  187. #define LLEF                            0x40    /* Last long entry flag in LDIR_Ord */
  188.  
  189. #define FSI_LeadSig                     0               /* FAT32 FSI: Leading signature (DWORD) */
  190. #define FSI_StrucSig            484             /* FAT32 FSI: Structure signature (DWORD) */
  191. #define FSI_Free_Count          488             /* FAT32 FSI: Number of free clusters (DWORD) */
  192. #define FSI_Nxt_Free            492             /* FAT32 FSI: Last allocated cluster (DWORD) */
  193.  
  194. #define MBR_Table                       446             /* MBR: Offset of partition table in the MBR */
  195. #define SZ_PTE                          16              /* MBR: Size of a partition table entry */
  196. #define PTE_Boot                        0               /* MBR PTE: Boot indicator */
  197. #define PTE_StHead                      1               /* MBR PTE: Start head */
  198. #define PTE_StSec                       2               /* MBR PTE: Start sector */
  199. #define PTE_StCyl                       3               /* MBR PTE: Start cylinder */
  200. #define PTE_System                      4               /* MBR PTE: System ID */
  201. #define PTE_EdHead                      5               /* MBR PTE: End head */
  202. #define PTE_EdSec                       6               /* MBR PTE: End sector */
  203. #define PTE_EdCyl                       7               /* MBR PTE: End cylinder */
  204. #define PTE_StLba                       8               /* MBR PTE: Start in LBA */
  205. #define PTE_SizLba                      12              /* MBR PTE: Size in LBA */
  206.  
  207.  
  208. /* Post process on fatal error in the file operations */
  209. #define ABORT(fs, res)          { fp->err = (BYTE)(res); LEAVE_FF(fs, res); }
  210.  
  211.  
  212. /* Re-entrancy related */
  213. #if FF_FS_REENTRANT
  214. #if FF_USE_LFN == 1
  215. #error Static LFN work area cannot be used at thread-safe configuration
  216. #endif
  217. #define LEAVE_FF(fs, res)       { unlock_fs(fs, res); return res; }
  218. #else
  219. #define LEAVE_FF(fs, res)       return res
  220. #endif
  221.  
  222.  
  223. /* Definitions of volume - physical location conversion */
  224. #if FF_MULTI_PARTITION
  225. #define LD2PD(vol) VolToPart[vol].pd    /* Get physical drive number */
  226. #define LD2PT(vol) VolToPart[vol].pt    /* Get partition index */
  227. #else
  228. #define LD2PD(vol) (BYTE)(vol)  /* Each logical drive is bound to the same physical drive number */
  229. #define LD2PT(vol) 0                    /* Find first valid partition or in SFD */
  230. #endif
  231.  
  232.  
  233. /* Definitions of sector size */
  234. #if (FF_MAX_SS < FF_MIN_SS) || (FF_MAX_SS != 512 && FF_MAX_SS != 1024 && FF_MAX_SS != 2048 && FF_MAX_SS != 4096) || (FF_MIN_SS != 512 && FF_MIN_SS != 1024 && FF_MIN_SS != 2048 && FF_MIN_SS != 4096)
  235. #error Wrong sector size configuration
  236. #endif
  237. #if FF_MAX_SS == FF_MIN_SS
  238. #define SS(fs)  ((UINT)FF_MAX_SS)       /* Fixed sector size */
  239. #else
  240. #define SS(fs)  ((fs)->ssize)   /* Variable sector size */
  241. #endif
  242.  
  243.  
  244. /* Timestamp */
  245. #if FF_FS_NORTC == 1
  246. #if FF_NORTC_YEAR < 1980 || FF_NORTC_YEAR > 2107 || FF_NORTC_MON < 1 || FF_NORTC_MON > 12 || FF_NORTC_MDAY < 1 || FF_NORTC_MDAY > 31
  247. #error Invalid FF_FS_NORTC settings
  248. #endif
  249. #define GET_FATTIME()   ((DWORD)(FF_NORTC_YEAR - 1980) << 25 | (DWORD)FF_NORTC_MON << 21 | (DWORD)FF_NORTC_MDAY << 16)
  250. #else
  251. #define GET_FATTIME()   get_fattime()
  252. #endif
  253.  
  254.  
  255. /* File lock controls */
  256. #if FF_FS_LOCK != 0
  257. #if FF_FS_READONLY
  258. #error FF_FS_LOCK must be 0 at read-only configuration
  259. #endif
  260. typedef struct {
  261.         FATFS *fs;              /* Object ID 1, volume (NULL:blank entry) */
  262.         DWORD clu;              /* Object ID 2, containing directory (0:root) */
  263.         DWORD ofs;              /* Object ID 3, offset in the directory */
  264.         WORD ctr;               /* Object open counter, 0:none, 0x01..0xFF:read mode open count, 0x100:write mode */
  265. } FILESEM;
  266. #endif
  267.  
  268.  
  269. /* SBCS up-case tables (\x80-\xFF) */
  270. #define TBL_CT437  {0x80,0x9A,0x45,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \
  271.                                         0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
  272.                                         0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
  273.                                         0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
  274.                                         0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
  275.                                         0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
  276.                                         0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \
  277.                                         0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
  278. #define TBL_CT720  {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \
  279.                                         0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
  280.                                         0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
  281.                                         0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
  282.                                         0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
  283.                                         0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
  284.                                         0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \
  285.                                         0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
  286. #define TBL_CT737  {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \
  287.                                         0x90,0x92,0x92,0x93,0x94,0x95,0x96,0x97,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, \
  288.                                         0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0xAA,0x92,0x93,0x94,0x95,0x96, \
  289.                                         0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
  290.                                         0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
  291.                                         0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
  292.                                         0x97,0xEA,0xEB,0xEC,0xE4,0xED,0xEE,0xEF,0xF5,0xF0,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \
  293.                                         0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
  294. #define TBL_CT771  {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \
  295.                                         0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
  296.                                         0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \
  297.                                         0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
  298.                                         0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
  299.                                         0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDC,0xDE,0xDE, \
  300.                                         0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
  301.                                         0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFE,0xFF}
  302. #define TBL_CT775  {0x80,0x9A,0x91,0xA0,0x8E,0x95,0x8F,0x80,0xAD,0xED,0x8A,0x8A,0xA1,0x8D,0x8E,0x8F, \
  303.                                         0x90,0x92,0x92,0xE2,0x99,0x95,0x96,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \
  304.                                         0xA0,0xA1,0xE0,0xA3,0xA3,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
  305.                                         0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
  306.                                         0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
  307.                                         0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xA5,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
  308.                                         0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE3,0xE8,0xE8,0xEA,0xEA,0xEE,0xED,0xEE,0xEF, \
  309.                                         0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
  310. #define TBL_CT850  {0x43,0x55,0x45,0x41,0x41,0x41,0x41,0x43,0x45,0x45,0x45,0x49,0x49,0x49,0x41,0x41, \
  311.                                         0x45,0x92,0x92,0x4F,0x4F,0x4F,0x55,0x55,0x59,0x4F,0x55,0x4F,0x9C,0x4F,0x9E,0x9F, \
  312.                                         0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
  313.                                         0xB0,0xB1,0xB2,0xB3,0xB4,0x41,0x41,0x41,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
  314.                                         0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0x41,0x41,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
  315.                                         0xD1,0xD1,0x45,0x45,0x45,0x49,0x49,0x49,0x49,0xD9,0xDA,0xDB,0xDC,0xDD,0x49,0xDF, \
  316.                                         0x4F,0xE1,0x4F,0x4F,0x4F,0x4F,0xE6,0xE8,0xE8,0x55,0x55,0x55,0x59,0x59,0xEE,0xEF, \
  317.                                         0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
  318. #define TBL_CT852  {0x80,0x9A,0x90,0xB6,0x8E,0xDE,0x8F,0x80,0x9D,0xD3,0x8A,0x8A,0xD7,0x8D,0x8E,0x8F, \
  319.                                         0x90,0x91,0x91,0xE2,0x99,0x95,0x95,0x97,0x97,0x99,0x9A,0x9B,0x9B,0x9D,0x9E,0xAC, \
  320.                                         0xB5,0xD6,0xE0,0xE9,0xA4,0xA4,0xA6,0xA6,0xA8,0xA8,0xAA,0x8D,0xAC,0xB8,0xAE,0xAF, \
  321.                                         0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBD,0xBF, \
  322.                                         0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC6,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
  323.                                         0xD1,0xD1,0xD2,0xD3,0xD2,0xD5,0xD6,0xD7,0xB7,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
  324.                                         0xE0,0xE1,0xE2,0xE3,0xE3,0xD5,0xE6,0xE6,0xE8,0xE9,0xE8,0xEB,0xED,0xED,0xDD,0xEF, \
  325.                                         0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xEB,0xFC,0xFC,0xFE,0xFF}
  326. #define TBL_CT855  {0x81,0x81,0x83,0x83,0x85,0x85,0x87,0x87,0x89,0x89,0x8B,0x8B,0x8D,0x8D,0x8F,0x8F, \
  327.                                         0x91,0x91,0x93,0x93,0x95,0x95,0x97,0x97,0x99,0x99,0x9B,0x9B,0x9D,0x9D,0x9F,0x9F, \
  328.                                         0xA1,0xA1,0xA3,0xA3,0xA5,0xA5,0xA7,0xA7,0xA9,0xA9,0xAB,0xAB,0xAD,0xAD,0xAE,0xAF, \
  329.                                         0xB0,0xB1,0xB2,0xB3,0xB4,0xB6,0xB6,0xB8,0xB8,0xB9,0xBA,0xBB,0xBC,0xBE,0xBE,0xBF, \
  330.                                         0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
  331.                                         0xD1,0xD1,0xD3,0xD3,0xD5,0xD5,0xD7,0xD7,0xDD,0xD9,0xDA,0xDB,0xDC,0xDD,0xE0,0xDF, \
  332.                                         0xE0,0xE2,0xE2,0xE4,0xE4,0xE6,0xE6,0xE8,0xE8,0xEA,0xEA,0xEC,0xEC,0xEE,0xEE,0xEF, \
  333.                                         0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFD,0xFE,0xFF}
  334. #define TBL_CT857  {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0x49,0x8E,0x8F, \
  335.                                         0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x98,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9E, \
  336.                                         0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA6,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
  337.                                         0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
  338.                                         0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
  339.                                         0xD0,0xD1,0xD2,0xD3,0xD4,0x49,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
  340.                                         0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xDE,0xED,0xEE,0xEF, \
  341.                                         0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
  342. #define TBL_CT860  {0x80,0x9A,0x90,0x8F,0x8E,0x91,0x86,0x80,0x89,0x89,0x92,0x8B,0x8C,0x98,0x8E,0x8F, \
  343.                                         0x90,0x91,0x92,0x8C,0x99,0xA9,0x96,0x9D,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
  344.                                         0x86,0x8B,0x9F,0x96,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
  345.                                         0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
  346.                                         0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
  347.                                         0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
  348.                                         0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \
  349.                                         0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
  350. #define TBL_CT861  {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x8B,0x8B,0x8D,0x8E,0x8F, \
  351.                                         0x90,0x92,0x92,0x4F,0x99,0x8D,0x55,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \
  352.                                         0xA4,0xA5,0xA6,0xA7,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
  353.                                         0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
  354.                                         0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
  355.                                         0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
  356.                                         0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \
  357.                                         0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
  358. #define TBL_CT862  {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \
  359.                                         0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
  360.                                         0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
  361.                                         0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
  362.                                         0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
  363.                                         0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
  364.                                         0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \
  365.                                         0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
  366. #define TBL_CT863  {0x43,0x55,0x45,0x41,0x41,0x41,0x86,0x43,0x45,0x45,0x45,0x49,0x49,0x8D,0x41,0x8F, \
  367.                                         0x45,0x45,0x45,0x4F,0x45,0x49,0x55,0x55,0x98,0x4F,0x55,0x9B,0x9C,0x55,0x55,0x9F, \
  368.                                         0xA0,0xA1,0x4F,0x55,0xA4,0xA5,0xA6,0xA7,0x49,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
  369.                                         0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
  370.                                         0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
  371.                                         0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
  372.                                         0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \
  373.                                         0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
  374. #define TBL_CT864  {0x80,0x9A,0x45,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \
  375.                                         0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
  376.                                         0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
  377.                                         0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
  378.                                         0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
  379.                                         0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
  380.                                         0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \
  381.                                         0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
  382. #define TBL_CT865  {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \
  383.                                         0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
  384.                                         0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
  385.                                         0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
  386.                                         0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
  387.                                         0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
  388.                                         0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \
  389.                                         0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
  390. #define TBL_CT866  {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \
  391.                                         0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
  392.                                         0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \
  393.                                         0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
  394.                                         0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
  395.                                         0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
  396.                                         0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
  397.                                         0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
  398. #define TBL_CT869  {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \
  399.                                         0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x86,0x9C,0x8D,0x8F,0x90, \
  400.                                         0x91,0x90,0x92,0x95,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
  401.                                         0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
  402.                                         0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
  403.                                         0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xA4,0xA5,0xA6,0xD9,0xDA,0xDB,0xDC,0xA7,0xA8,0xDF, \
  404.                                         0xA9,0xAA,0xAC,0xAD,0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xCF,0xCF,0xD0,0xEF, \
  405.                                         0xF0,0xF1,0xD1,0xD2,0xD3,0xF5,0xD4,0xF7,0xF8,0xF9,0xD5,0x96,0x95,0x98,0xFE,0xFF}
  406.  
  407.  
  408. /* DBCS code range |----- 1st byte -----|  |----------- 2nd byte -----------| */
  409. #define TBL_DC932 {0x81, 0x9F, 0xE0, 0xFC, 0x40, 0x7E, 0x80, 0xFC, 0x00, 0x00}
  410. #define TBL_DC936 {0x81, 0xFE, 0x00, 0x00, 0x40, 0x7E, 0x80, 0xFE, 0x00, 0x00}
  411. #define TBL_DC949 {0x81, 0xFE, 0x00, 0x00, 0x41, 0x5A, 0x61, 0x7A, 0x81, 0xFE}
  412. #define TBL_DC950 {0x81, 0xFE, 0x00, 0x00, 0x40, 0x7E, 0xA1, 0xFE, 0x00, 0x00}
  413.  
  414.  
  415. /* Macros for table definitions */
  416. #define MERGE_2STR(a, b) a ## b
  417. #define MKCVTBL(hd, cp) MERGE_2STR(hd, cp)
  418.  
  419.  
  420.  
  421.  
  422. /*--------------------------------------------------------------------------
  423.  
  424.    Module Private Work Area
  425.  
  426. ---------------------------------------------------------------------------*/
  427. /* Remark: Variables defined here without initial value shall be guaranteed
  428. /  zero/null at start-up. If not, the linker option or start-up routine is
  429. /  not compliance with C standard. */
  430.  
  431. /*--------------------------------*/
  432. /* File/Volume controls           */
  433. /*--------------------------------*/
  434.  
  435. #if FF_VOLUMES < 1 || FF_VOLUMES > 10
  436. #error Wrong FF_VOLUMES setting
  437. #endif
  438. static FATFS* FatFs[FF_VOLUMES];        /* Pointer to the filesystem objects (logical drives) */
  439. static WORD Fsid;                                       /* Filesystem mount ID */
  440.  
  441. #if FF_FS_RPATH != 0
  442. static BYTE CurrVol;                            /* Current drive */
  443. #endif
  444.  
  445. #if FF_FS_LOCK != 0
  446. static FILESEM Files[FF_FS_LOCK];       /* Open object lock semaphores */
  447. #endif
  448.  
  449. #if FF_STR_VOLUME_ID
  450. #ifdef FF_VOLUME_STRS
  451. static const char* const VolumeStr[FF_VOLUMES] = {FF_VOLUME_STRS};      /* Pre-defined volume ID */
  452. #endif
  453. #endif
  454.  
  455.  
  456. /*--------------------------------*/
  457. /* LFN/Directory working buffer   */
  458. /*--------------------------------*/
  459.  
  460. #if FF_USE_LFN == 0             /* Non-LFN configuration */
  461. #if FF_FS_EXFAT
  462. #error LFN must be enabled when enable exFAT
  463. #endif
  464. #define DEF_NAMBUF
  465. #define INIT_NAMBUF(fs)
  466. #define FREE_NAMBUF()
  467. #define LEAVE_MKFS(res) return res
  468.  
  469. #else                                   /* LFN configurations */
  470. #if FF_MAX_LFN < 12 || FF_MAX_LFN > 255
  471. #error Wrong setting of FF_MAX_LFN
  472. #endif
  473. #if FF_LFN_BUF < FF_SFN_BUF || FF_SFN_BUF < 12
  474. #error Wrong setting of FF_LFN_BUF or FF_SFN_BUF
  475. #endif
  476. #if FF_LFN_UNICODE < 0 || FF_LFN_UNICODE > 3
  477. #error Wrong setting of FF_LFN_UNICODE
  478. #endif
  479. static const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30};       /* FAT: Offset of LFN characters in the directory entry */
  480. #define MAXDIRB(nc)     ((nc + 44U) / 15 * SZDIRE)      /* exFAT: Size of directory entry block scratchpad buffer needed for the name length */
  481.  
  482. #if FF_USE_LFN == 1             /* LFN enabled with static working buffer */
  483. #if FF_FS_EXFAT
  484. static BYTE     DirBuf[MAXDIRB(FF_MAX_LFN)];    /* Directory entry block scratchpad buffer */
  485. #endif
  486. static WCHAR LfnBuf[FF_MAX_LFN + 1];            /* LFN working buffer */
  487. #define DEF_NAMBUF
  488. #define INIT_NAMBUF(fs)
  489. #define FREE_NAMBUF()
  490. #define LEAVE_MKFS(res) return res
  491.  
  492. #elif FF_USE_LFN == 2   /* LFN enabled with dynamic working buffer on the stack */
  493. #if FF_FS_EXFAT
  494. #define DEF_NAMBUF              WCHAR lbuf[FF_MAX_LFN+1]; BYTE dbuf[MAXDIRB(FF_MAX_LFN)];       /* LFN working buffer and directory entry block scratchpad buffer */
  495. #define INIT_NAMBUF(fs) { (fs)->lfnbuf = lbuf; (fs)->dirbuf = dbuf; }
  496. #define FREE_NAMBUF()
  497. #else
  498. #define DEF_NAMBUF              WCHAR lbuf[FF_MAX_LFN+1];       /* LFN working buffer */
  499. #define INIT_NAMBUF(fs) { (fs)->lfnbuf = lbuf; }
  500. #define FREE_NAMBUF()
  501. #endif
  502. #define LEAVE_MKFS(res) return res
  503.  
  504. #elif FF_USE_LFN == 3   /* LFN enabled with dynamic working buffer on the heap */
  505. #if FF_FS_EXFAT
  506. #define DEF_NAMBUF              WCHAR *lfn;     /* Pointer to LFN working buffer and directory entry block scratchpad buffer */
  507. #define INIT_NAMBUF(fs) { lfn = ff_memalloc((FF_MAX_LFN+1)*2 + MAXDIRB(FF_MAX_LFN)); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; (fs)->dirbuf = (BYTE*)(lfn+FF_MAX_LFN+1); }
  508. #define FREE_NAMBUF()   ff_memfree(lfn)
  509. #else
  510. #define DEF_NAMBUF              WCHAR *lfn;     /* Pointer to LFN working buffer */
  511. #define INIT_NAMBUF(fs) { lfn = ff_memalloc((FF_MAX_LFN+1)*2); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; }
  512. #define FREE_NAMBUF()   ff_memfree(lfn)
  513. #endif
  514. #define LEAVE_MKFS(res) { if (!work) ff_memfree(buf); return res; }
  515. #define MAX_MALLOC      0x8000  /* Must be >=FF_MAX_SS */
  516.  
  517. #else
  518. #error Wrong setting of FF_USE_LFN
  519.  
  520. #endif  /* FF_USE_LFN == 1 */
  521. #endif  /* FF_USE_LFN == 0 */
  522.  
  523.  
  524.  
  525. /*--------------------------------*/
  526. /* Code conversion tables         */
  527. /*--------------------------------*/
  528.  
  529. #if FF_CODE_PAGE == 0           /* Run-time code page configuration */
  530. #define CODEPAGE CodePage
  531. static WORD CodePage;   /* Current code page */
  532. static const BYTE *ExCvt, *DbcTbl;      /* Pointer to current SBCS up-case table and DBCS code range table below */
  533.  
  534. static const BYTE Ct437[] = TBL_CT437;
  535. static const BYTE Ct720[] = TBL_CT720;
  536. static const BYTE Ct737[] = TBL_CT737;
  537. static const BYTE Ct771[] = TBL_CT771;
  538. static const BYTE Ct775[] = TBL_CT775;
  539. static const BYTE Ct850[] = TBL_CT850;
  540. static const BYTE Ct852[] = TBL_CT852;
  541. static const BYTE Ct855[] = TBL_CT855;
  542. static const BYTE Ct857[] = TBL_CT857;
  543. static const BYTE Ct860[] = TBL_CT860;
  544. static const BYTE Ct861[] = TBL_CT861;
  545. static const BYTE Ct862[] = TBL_CT862;
  546. static const BYTE Ct863[] = TBL_CT863;
  547. static const BYTE Ct864[] = TBL_CT864;
  548. static const BYTE Ct865[] = TBL_CT865;
  549. static const BYTE Ct866[] = TBL_CT866;
  550. static const BYTE Ct869[] = TBL_CT869;
  551. static const BYTE Dc932[] = TBL_DC932;
  552. static const BYTE Dc936[] = TBL_DC936;
  553. static const BYTE Dc949[] = TBL_DC949;
  554. static const BYTE Dc950[] = TBL_DC950;
  555.  
  556. #elif FF_CODE_PAGE < 900        /* Static code page configuration (SBCS) */
  557. #define CODEPAGE FF_CODE_PAGE
  558. static const BYTE ExCvt[] = MKCVTBL(TBL_CT, FF_CODE_PAGE);
  559.  
  560. #else                                   /* Static code page configuration (DBCS) */
  561. #define CODEPAGE FF_CODE_PAGE
  562. static const BYTE DbcTbl[] = MKCVTBL(TBL_DC, FF_CODE_PAGE);
  563.  
  564. #endif
  565.  
  566.  
  567.  
  568.  
  569. /*--------------------------------------------------------------------------
  570.  
  571.    Module Private Functions
  572.  
  573. ---------------------------------------------------------------------------*/
  574.  
  575.  
  576. /*-----------------------------------------------------------------------*/
  577. /* Load/Store multi-byte word in the FAT structure                       */
  578. /*-----------------------------------------------------------------------*/
  579.  
  580. static WORD ld_word (const BYTE* ptr)   /*       Load a 2-byte little-endian word */
  581. {
  582.         WORD rv;
  583.  
  584.         rv = ptr[1];
  585.         rv = rv << 8 | ptr[0];
  586.         return rv;
  587. }
  588.  
  589. static DWORD ld_dword (const BYTE* ptr) /* Load a 4-byte little-endian word */
  590. {
  591.         DWORD rv;
  592.  
  593.         rv = ptr[3];
  594.         rv = rv << 8 | ptr[2];
  595.         rv = rv << 8 | ptr[1];
  596.         rv = rv << 8 | ptr[0];
  597.         return rv;
  598. }
  599.  
  600. #if FF_FS_EXFAT
  601. static QWORD ld_qword (const BYTE* ptr) /* Load an 8-byte little-endian word */
  602. {
  603.         QWORD rv;
  604.  
  605.         rv = ptr[7];
  606.         rv = rv << 8 | ptr[6];
  607.         rv = rv << 8 | ptr[5];
  608.         rv = rv << 8 | ptr[4];
  609.         rv = rv << 8 | ptr[3];
  610.         rv = rv << 8 | ptr[2];
  611.         rv = rv << 8 | ptr[1];
  612.         rv = rv << 8 | ptr[0];
  613.         return rv;
  614. }
  615. #endif
  616.  
  617. #if !FF_FS_READONLY
  618. static void st_word (BYTE* ptr, WORD val)       /* Store a 2-byte word in little-endian */
  619. {
  620.         *ptr++ = (BYTE)val; val >>= 8;
  621.         *ptr++ = (BYTE)val;
  622. }
  623.  
  624. static void st_dword (BYTE* ptr, DWORD val)     /* Store a 4-byte word in little-endian */
  625. {
  626.         *ptr++ = (BYTE)val; val >>= 8;
  627.         *ptr++ = (BYTE)val; val >>= 8;
  628.         *ptr++ = (BYTE)val; val >>= 8;
  629.         *ptr++ = (BYTE)val;
  630. }
  631.  
  632. #if FF_FS_EXFAT
  633. static void st_qword (BYTE* ptr, QWORD val)     /* Store an 8-byte word in little-endian */
  634. {
  635.         *ptr++ = (BYTE)val; val >>= 8;
  636.         *ptr++ = (BYTE)val; val >>= 8;
  637.         *ptr++ = (BYTE)val; val >>= 8;
  638.         *ptr++ = (BYTE)val; val >>= 8;
  639.         *ptr++ = (BYTE)val; val >>= 8;
  640.         *ptr++ = (BYTE)val; val >>= 8;
  641.         *ptr++ = (BYTE)val; val >>= 8;
  642.         *ptr++ = (BYTE)val;
  643. }
  644. #endif
  645. #endif  /* !FF_FS_READONLY */
  646.  
  647.  
  648.  
  649. /*-----------------------------------------------------------------------*/
  650. /* String functions                                                      */
  651. /*-----------------------------------------------------------------------*/
  652.  
  653. /* Copy memory to memory */
  654. static void mem_cpy (void* dst, const void* src, UINT cnt)
  655. {
  656.         BYTE *d = (BYTE*)dst;
  657.         const BYTE *s = (const BYTE*)src;
  658.  
  659.         if (cnt != 0) {
  660.                 do {
  661.                         *d++ = *s++;
  662.                 } while (--cnt);
  663.         }
  664. }
  665.  
  666.  
  667. /* Fill memory block */
  668. static void mem_set (void* dst, int val, UINT cnt)
  669. {
  670.         BYTE *d = (BYTE*)dst;
  671.  
  672.         do {
  673.                 *d++ = (BYTE)val;
  674.         } while (--cnt);
  675. }
  676.  
  677.  
  678. /* Compare memory block */
  679. static int mem_cmp (const void* dst, const void* src, UINT cnt) /* ZR:same, NZ:different */
  680. {
  681.         const BYTE *d = (const BYTE *)dst, *s = (const BYTE *)src;
  682.         int r = 0;
  683.  
  684.         do {
  685.                 r = *d++ - *s++;
  686.         } while (--cnt && r == 0);
  687.  
  688.         return r;
  689. }
  690.  
  691.  
  692. /* Check if chr is contained in the string */
  693. static int chk_chr (const char* str, int chr)   /* NZ:contained, ZR:not contained */
  694. {
  695.         while (*str && *str != chr) str++;
  696.         return *str;
  697. }
  698.  
  699.  
  700. /* Test if the character is DBC 1st byte */
  701. static int dbc_1st (BYTE c)
  702. {
  703. #if FF_CODE_PAGE == 0           /* Variable code page */
  704.         if (DbcTbl && c >= DbcTbl[0]) {
  705.                 if (c <= DbcTbl[1]) return 1;                                   /* 1st byte range 1 */
  706.                 if (c >= DbcTbl[2] && c <= DbcTbl[3]) return 1; /* 1st byte range 2 */
  707.         }
  708. #elif FF_CODE_PAGE >= 900       /* DBCS fixed code page */
  709.         if (c >= DbcTbl[0]) {
  710.                 if (c <= DbcTbl[1]) return 1;
  711.                 if (c >= DbcTbl[2] && c <= DbcTbl[3]) return 1;
  712.         }
  713. #else                                           /* SBCS fixed code page */
  714.         if (c != 0) return 0;   /* Always false */
  715. #endif
  716.         return 0;
  717. }
  718.  
  719.  
  720. /* Test if the character is DBC 2nd byte */
  721. static int dbc_2nd (BYTE c)
  722. {
  723. #if FF_CODE_PAGE == 0           /* Variable code page */
  724.         if (DbcTbl && c >= DbcTbl[4]) {
  725.                 if (c <= DbcTbl[5]) return 1;                                   /* 2nd byte range 1 */
  726.                 if (c >= DbcTbl[6] && c <= DbcTbl[7]) return 1; /* 2nd byte range 2 */
  727.                 if (c >= DbcTbl[8] && c <= DbcTbl[9]) return 1; /* 2nd byte range 3 */
  728.         }
  729. #elif FF_CODE_PAGE >= 900       /* DBCS fixed code page */
  730.         if (c >= DbcTbl[4]) {
  731.                 if (c <= DbcTbl[5]) return 1;
  732.                 if (c >= DbcTbl[6] && c <= DbcTbl[7]) return 1;
  733.                 if (c >= DbcTbl[8] && c <= DbcTbl[9]) return 1;
  734.         }
  735. #else                                           /* SBCS fixed code page */
  736.         if (c != 0) return 0;   /* Always false */
  737. #endif
  738.         return 0;
  739. }
  740.  
  741.  
  742. #if FF_USE_LFN
  743.  
  744. /* Get a character from TCHAR string in defined API encodeing */
  745. static DWORD tchar2uni (        /* Returns character in UTF-16 encoding (>=0x10000 on double encoding unit, 0xFFFFFFFF on decode error) */
  746.         const TCHAR** str               /* Pointer to pointer to TCHAR string in configured encoding */
  747. )
  748. {
  749.         DWORD uc;
  750.         const TCHAR *p = *str;
  751.  
  752. #if FF_LFN_UNICODE == 1         /* UTF-16 input */
  753.         WCHAR wc;
  754.  
  755.         uc = *p++;      /* Get a unit */
  756.         if (IsSurrogate(uc)) {  /* Surrogate? */
  757.                 wc = *p++;              /* Get low surrogate */
  758.                 if (!IsSurrogateH(uc) || !IsSurrogateL(wc)) return 0xFFFFFFFF;  /* Wrong surrogate? */
  759.                 uc = uc << 16 | wc;
  760.         }
  761.  
  762. #elif FF_LFN_UNICODE == 2       /* UTF-8 input */
  763.         BYTE b;
  764.         int nf;
  765.  
  766.         uc = (BYTE)*p++;        /* Get a unit */
  767.         if (uc & 0x80) {        /* Multiple byte code? */
  768.                 if ((uc & 0xE0) == 0xC0) {      /* 2-byte sequence? */
  769.                         uc &= 0x1F; nf = 1;
  770.                 } else {
  771.                         if ((uc & 0xF0) == 0xE0) {      /* 3-byte sequence? */
  772.                                 uc &= 0x0F; nf = 2;
  773.                         } else {
  774.                                 if ((uc & 0xF8) == 0xF0) {      /* 4-byte sequence? */
  775.                                         uc &= 0x07; nf = 3;
  776.                                 } else {                                        /* Wrong sequence */
  777.                                         return 0xFFFFFFFF;
  778.                                 }
  779.                         }
  780.                 }
  781.                 do {    /* Get trailing bytes */
  782.                         b = (BYTE)*p++;
  783.                         if ((b & 0xC0) != 0x80) return 0xFFFFFFFF;      /* Wrong sequence? */
  784.                         uc = uc << 6 | (b & 0x3F);
  785.                 } while (--nf != 0);
  786.                 if (uc < 0x80 || IsSurrogate(uc) || uc >= 0x110000) return 0xFFFFFFFF;  /* Wrong code? */
  787.                 if (uc >= 0x010000) uc = 0xD800DC00 | ((uc - 0x10000) << 6 & 0x3FF0000) | (uc & 0x3FF); /* Make a surrogate pair if needed */
  788.         }
  789.  
  790. #elif FF_LFN_UNICODE == 3       /* UTF-32 input */
  791.         uc = (TCHAR)*p++;       /* Get a unit */
  792.         if (uc >= 0x110000) return 0xFFFFFFFF;  /* Wrong code? */
  793.         if (uc >= 0x010000) uc = 0xD800DC00 | ((uc - 0x10000) << 6 & 0x3FF0000) | (uc & 0x3FF); /* Make a surrogate pair if needed */
  794.  
  795. #else           /* ANSI/OEM input */
  796.         BYTE b;
  797.         WCHAR wc;
  798.  
  799.         wc = (BYTE)*p++;                        /* Get a byte */
  800.         if (dbc_1st((BYTE)wc)) {        /* Is it a DBC 1st byte? */
  801.                 b = (BYTE)*p++;                 /* Get 2nd byte */
  802.                 if (!dbc_2nd(b)) return 0xFFFFFFFF;     /* Invalid code? */
  803.                 wc = (wc << 8) + b;             /* Make a DBC */
  804.         }
  805.         if (wc != 0) {
  806.                 wc = ff_oem2uni(wc, CODEPAGE);  /* ANSI/OEM ==> Unicode */
  807.                 if (wc == 0) return 0xFFFFFFFF; /* Invalid code? */
  808.         }
  809.         uc = wc;
  810.  
  811. #endif
  812.         *str = p;       /* Next read pointer */
  813.         return uc;
  814. }
  815.  
  816.  
  817. /* Output a TCHAR string in defined API encoding */
  818. static BYTE put_utf (   /* Returns number of encoding units written (0:buffer overflow or wrong encoding) */
  819.         DWORD chr,      /* UTF-16 encoded character (Double encoding unit char if >=0x10000) */
  820.         TCHAR* buf,     /* Output buffer */
  821.         UINT szb        /* Size of the buffer */
  822. )
  823. {
  824. #if FF_LFN_UNICODE == 1 /* UTF-16 output */
  825.         WCHAR hs, wc;
  826.  
  827.         hs = (WCHAR)(chr >> 16);
  828.         wc = (WCHAR)chr;
  829.         if (hs == 0) {  /* Single encoding unit? */
  830.                 if (szb < 1 || IsSurrogate(wc)) return 0;       /* Buffer overflow or wrong code? */
  831.                 *buf = wc;
  832.                 return 1;
  833.         }
  834.         if (szb < 2 || !IsSurrogateH(hs) || !IsSurrogateL(wc)) return 0;        /* Buffer overflow or wrong surrogate? */
  835.         *buf++ = hs;
  836.         *buf++ = wc;
  837.         return 2;
  838.  
  839. #elif FF_LFN_UNICODE == 2       /* UTF-8 output */
  840.         DWORD hc;
  841.  
  842.         if (chr < 0x80) {       /* Single byte code? */
  843.                 if (szb < 1) return 0;  /* Buffer overflow? */
  844.                 *buf = (TCHAR)chr;
  845.                 return 1;
  846.         }
  847.         if (chr < 0x800) {      /* 2-byte sequence? */
  848.                 if (szb < 2) return 0;  /* Buffer overflow? */
  849.                 *buf++ = (TCHAR)(0xC0 | (chr >> 6 & 0x1F));
  850.                 *buf++ = (TCHAR)(0x80 | (chr >> 0 & 0x3F));
  851.                 return 2;
  852.         }
  853.         if (chr < 0x10000) {    /* 3-byte sequence? */
  854.                 if (szb < 3 || IsSurrogate(chr)) return 0;      /* Buffer overflow or wrong code? */
  855.                 *buf++ = (TCHAR)(0xE0 | (chr >> 12 & 0x0F));
  856.                 *buf++ = (TCHAR)(0x80 | (chr >> 6 & 0x3F));
  857.                 *buf++ = (TCHAR)(0x80 | (chr >> 0 & 0x3F));
  858.                 return 3;
  859.         }
  860.         /* 4-byte sequence */
  861.         if (szb < 4) return 0;  /* Buffer overflow? */
  862.         hc = ((chr & 0xFFFF0000) - 0xD8000000) >> 6;    /* Get high 10 bits */
  863.         chr = (chr & 0xFFFF) - 0xDC00;                                  /* Get low 10 bits */
  864.         if (hc >= 0x100000 || chr >= 0x400) return 0;   /* Wrong surrogate? */
  865.         chr = (hc | chr) + 0x10000;
  866.         *buf++ = (TCHAR)(0xF0 | (chr >> 18 & 0x07));
  867.         *buf++ = (TCHAR)(0x80 | (chr >> 12 & 0x3F));
  868.         *buf++ = (TCHAR)(0x80 | (chr >> 6 & 0x3F));
  869.         *buf++ = (TCHAR)(0x80 | (chr >> 0 & 0x3F));
  870.         return 4;
  871.  
  872. #elif FF_LFN_UNICODE == 3       /* UTF-32 output */
  873.         DWORD hc;
  874.  
  875.         if (szb < 1) return 0;  /* Buffer overflow? */
  876.         if (chr >= 0x10000) {   /* Out of BMP? */
  877.                 hc = ((chr & 0xFFFF0000) - 0xD8000000) >> 6;    /* Get high 10 bits */
  878.                 chr = (chr & 0xFFFF) - 0xDC00;                                  /* Get low 10 bits */
  879.                 if (hc >= 0x100000 || chr >= 0x400) return 0;   /* Wrong surrogate? */
  880.                 chr = (hc | chr) + 0x10000;
  881.         }
  882.         *buf++ = (TCHAR)chr;
  883.         return 1;
  884.  
  885. #else                                           /* ANSI/OEM output */
  886.         WCHAR wc;
  887.  
  888.         wc = ff_uni2oem(chr, CODEPAGE);
  889.         if (wc >= 0x100) {      /* Is this a DBC? */
  890.                 if (szb < 2) return 0;
  891.                 *buf++ = (char)(wc >> 8);       /* Store DBC 1st byte */
  892.                 *buf++ = (TCHAR)wc;                     /* Store DBC 2nd byte */
  893.                 return 2;
  894.         }
  895.         if (wc == 0 || szb < 1) return 0;       /* Invalid char or buffer overflow? */
  896.         *buf++ = (TCHAR)wc;                                     /* Store the character */
  897.         return 1;
  898. #endif
  899. }
  900. #endif  /* FF_USE_LFN */
  901.  
  902.  
  903. #if FF_FS_REENTRANT
  904. /*-----------------------------------------------------------------------*/
  905. /* Request/Release grant to access the volume                            */
  906. /*-----------------------------------------------------------------------*/
  907. static int lock_fs (            /* 1:Ok, 0:timeout */
  908.         FATFS* fs               /* Filesystem object */
  909. )
  910. {
  911.         return ff_req_grant(fs->sobj);
  912. }
  913.  
  914.  
  915. static void unlock_fs (
  916.         FATFS* fs,              /* Filesystem object */
  917.         FRESULT res             /* Result code to be returned */
  918. )
  919. {
  920.         if (fs && res != FR_NOT_ENABLED && res != FR_INVALID_DRIVE && res != FR_TIMEOUT) {
  921.                 ff_rel_grant(fs->sobj);
  922.         }
  923. }
  924.  
  925. #endif
  926.  
  927.  
  928.  
  929. #if FF_FS_LOCK != 0
  930. /*-----------------------------------------------------------------------*/
  931. /* File lock control functions                                           */
  932. /*-----------------------------------------------------------------------*/
  933.  
  934. static FRESULT chk_lock (       /* Check if the file can be accessed */
  935.         DIR* dp,                /* Directory object pointing the file to be checked */
  936.         int acc                 /* Desired access type (0:Read mode open, 1:Write mode open, 2:Delete or rename) */
  937. )
  938. {
  939.         UINT i, be;
  940.  
  941.         /* Search open object table for the object */
  942.         be = 0;
  943.         for (i = 0; i < FF_FS_LOCK; i++) {
  944.                 if (Files[i].fs) {      /* Existing entry */
  945.                         if (Files[i].fs == dp->obj.fs &&                /* Check if the object matches with an open object */
  946.                                 Files[i].clu == dp->obj.sclust &&
  947.                                 Files[i].ofs == dp->dptr) break;
  948.                 } else {                        /* Blank entry */
  949.                         be = 1;
  950.                 }
  951.         }
  952.         if (i == FF_FS_LOCK) {  /* The object has not been opened */
  953.                 return (!be && acc != 2) ? FR_TOO_MANY_OPEN_FILES : FR_OK;      /* Is there a blank entry for new object? */
  954.         }
  955.  
  956.         /* The object was opened. Reject any open against writing file and all write mode open */
  957.         return (acc != 0 || Files[i].ctr == 0x100) ? FR_LOCKED : FR_OK;
  958. }
  959.  
  960.  
  961. static int enq_lock (void)      /* Check if an entry is available for a new object */
  962. {
  963.         UINT i;
  964.  
  965.         for (i = 0; i < FF_FS_LOCK && Files[i].fs; i++) ;
  966.         return (i == FF_FS_LOCK) ? 0 : 1;
  967. }
  968.  
  969.  
  970. static UINT inc_lock (  /* Increment object open counter and returns its index (0:Internal error) */
  971.         DIR* dp,        /* Directory object pointing the file to register or increment */
  972.         int acc         /* Desired access (0:Read, 1:Write, 2:Delete/Rename) */
  973. )
  974. {
  975.         UINT i;
  976.  
  977.  
  978.         for (i = 0; i < FF_FS_LOCK; i++) {      /* Find the object */
  979.                 if (Files[i].fs == dp->obj.fs &&
  980.                         Files[i].clu == dp->obj.sclust &&
  981.                         Files[i].ofs == dp->dptr) break;
  982.         }
  983.  
  984.         if (i == FF_FS_LOCK) {                          /* Not opened. Register it as new. */
  985.                 for (i = 0; i < FF_FS_LOCK && Files[i].fs; i++) ;
  986.                 if (i == FF_FS_LOCK) return 0;  /* No free entry to register (int err) */
  987.                 Files[i].fs = dp->obj.fs;
  988.                 Files[i].clu = dp->obj.sclust;
  989.                 Files[i].ofs = dp->dptr;
  990.                 Files[i].ctr = 0;
  991.         }
  992.  
  993.         if (acc >= 1 && Files[i].ctr) return 0; /* Access violation (int err) */
  994.  
  995.         Files[i].ctr = acc ? 0x100 : Files[i].ctr + 1;  /* Set semaphore value */
  996.  
  997.         return i + 1;   /* Index number origin from 1 */
  998. }
  999.  
  1000.  
  1001. static FRESULT dec_lock (       /* Decrement object open counter */
  1002.         UINT i                  /* Semaphore index (1..) */
  1003. )
  1004. {
  1005.         WORD n;
  1006.         FRESULT res;
  1007.  
  1008.  
  1009.         if (--i < FF_FS_LOCK) { /* Index number origin from 0 */
  1010.                 n = Files[i].ctr;
  1011.                 if (n == 0x100) n = 0;          /* If write mode open, delete the entry */
  1012.                 if (n > 0) n--;                         /* Decrement read mode open count */
  1013.                 Files[i].ctr = n;
  1014.                 if (n == 0) Files[i].fs = 0;    /* Delete the entry if open count gets zero */
  1015.                 res = FR_OK;
  1016.         } else {
  1017.                 res = FR_INT_ERR;                       /* Invalid index nunber */
  1018.         }
  1019.         return res;
  1020. }
  1021.  
  1022.  
  1023. static void clear_lock (        /* Clear lock entries of the volume */
  1024.         FATFS *fs
  1025. )
  1026. {
  1027.         UINT i;
  1028.  
  1029.         for (i = 0; i < FF_FS_LOCK; i++) {
  1030.                 if (Files[i].fs == fs) Files[i].fs = 0;
  1031.         }
  1032. }
  1033.  
  1034. #endif  /* FF_FS_LOCK != 0 */
  1035.  
  1036.  
  1037.  
  1038. /*-----------------------------------------------------------------------*/
  1039. /* Move/Flush disk access window in the filesystem object                */
  1040. /*-----------------------------------------------------------------------*/
  1041. #if !FF_FS_READONLY
  1042. static FRESULT sync_window (    /* Returns FR_OK or FR_DISK_ERR */
  1043.         FATFS* fs                       /* Filesystem object */
  1044. )
  1045. {
  1046.         FRESULT res = FR_OK;
  1047.  
  1048.  
  1049.         if (fs->wflag) {        /* Is the disk access window dirty */
  1050.                 if (disk_write(fs->pdrv, fs->win, fs->winsect, 1) == RES_OK) {  /* Write back the window */
  1051.                         fs->wflag = 0;  /* Clear window dirty flag */
  1052.                         if (fs->winsect - fs->fatbase < fs->fsize) {    /* Is it in the 1st FAT? */
  1053.                                 if (fs->n_fats == 2) disk_write(fs->pdrv, fs->win, fs->winsect + fs->fsize, 1); /* Reflect it to 2nd FAT if needed */
  1054.                         }
  1055.                 } else {
  1056.                         res = FR_DISK_ERR;
  1057.                 }
  1058.         }
  1059.         return res;
  1060. }
  1061. #endif
  1062.  
  1063.  
  1064. static FRESULT move_window (    /* Returns FR_OK or FR_DISK_ERR */
  1065.         FATFS* fs,                      /* Filesystem object */
  1066.         DWORD sector            /* Sector number to make appearance in the fs->win[] */
  1067. )
  1068. {
  1069.         FRESULT res = FR_OK;
  1070.  
  1071.  
  1072.         if (sector != fs->winsect) {    /* Window offset changed? */
  1073. #if !FF_FS_READONLY
  1074.                 res = sync_window(fs);          /* Write-back changes */
  1075. #endif
  1076.                 if (res == FR_OK) {                     /* Fill sector window with new data */
  1077.                         if (disk_read(fs->pdrv, fs->win, sector, 1) != RES_OK) {
  1078.                                 sector = 0xFFFFFFFF;    /* Invalidate window if read data is not valid */
  1079.                                 res = FR_DISK_ERR;
  1080.                         }
  1081.                         fs->winsect = sector;
  1082.                 }
  1083.         }
  1084.         return res;
  1085. }
  1086.  
  1087.  
  1088.  
  1089.  
  1090. #if !FF_FS_READONLY
  1091. /*-----------------------------------------------------------------------*/
  1092. /* Synchronize filesystem and data on the storage                        */
  1093. /*-----------------------------------------------------------------------*/
  1094.  
  1095. static FRESULT sync_fs (        /* Returns FR_OK or FR_DISK_ERR */
  1096.         FATFS* fs               /* Filesystem object */
  1097. )
  1098. {
  1099.         FRESULT res;
  1100.  
  1101.  
  1102.         res = sync_window(fs);
  1103.         if (res == FR_OK) {
  1104.                 if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) {     /* FAT32: Update FSInfo sector if needed */
  1105.                         /* Create FSInfo structure */
  1106.                         mem_set(fs->win, 0, sizeof fs->win);
  1107.                         st_word(fs->win + BS_55AA, 0xAA55);
  1108.                         st_dword(fs->win + FSI_LeadSig, 0x41615252);
  1109.                         st_dword(fs->win + FSI_StrucSig, 0x61417272);
  1110.                         st_dword(fs->win + FSI_Free_Count, fs->free_clst);
  1111.                         st_dword(fs->win + FSI_Nxt_Free, fs->last_clst);
  1112.                         /* Write it into the FSInfo sector */
  1113.                         fs->winsect = fs->volbase + 1;
  1114.                         disk_write(fs->pdrv, fs->win, fs->winsect, 1);
  1115.                         fs->fsi_flag = 0;
  1116.                 }
  1117.                 /* Make sure that no pending write process in the lower layer */
  1118.                 if (disk_ioctl(fs->pdrv, CTRL_SYNC, 0) != RES_OK) res = FR_DISK_ERR;
  1119.         }
  1120.  
  1121.         return res;
  1122. }
  1123.  
  1124. #endif
  1125.  
  1126.  
  1127.  
  1128. /*-----------------------------------------------------------------------*/
  1129. /* Get physical sector number from cluster number                        */
  1130. /*-----------------------------------------------------------------------*/
  1131.  
  1132. static DWORD clst2sect (        /* !=0:Sector number, 0:Failed (invalid cluster#) */
  1133.         FATFS* fs,              /* Filesystem object */
  1134.         DWORD clst              /* Cluster# to be converted */
  1135. )
  1136. {
  1137.         clst -= 2;              /* Cluster number is origin from 2 */
  1138.         if (clst >= fs->n_fatent - 2) return 0;         /* Is it invalid cluster number? */
  1139.         return fs->database + fs->csize * clst;         /* Start sector number of the cluster */
  1140. }
  1141.  
  1142.  
  1143.  
  1144.  
  1145. /*-----------------------------------------------------------------------*/
  1146. /* FAT access - Read value of a FAT entry                                */
  1147. /*-----------------------------------------------------------------------*/
  1148.  
  1149. static DWORD get_fat (          /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x7FFFFFFF:Cluster status */
  1150.         FFOBJID* obj,   /* Corresponding object */
  1151.         DWORD clst              /* Cluster number to get the value */
  1152. )
  1153. {
  1154.         UINT wc, bc;
  1155.         DWORD val;
  1156.         FATFS *fs = obj->fs;
  1157.  
  1158.  
  1159.         if (clst < 2 || clst >= fs->n_fatent) { /* Check if in valid range */
  1160.                 val = 1;        /* Internal error */
  1161.  
  1162.         } else {
  1163.                 val = 0xFFFFFFFF;       /* Default value falls on disk error */
  1164.  
  1165.                 switch (fs->fs_type) {
  1166.                 case FS_FAT12 :
  1167.                         bc = (UINT)clst; bc += bc / 2;
  1168.                         if (move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK) break;
  1169.                         wc = fs->win[bc++ % SS(fs)];            /* Get 1st byte of the entry */
  1170.                         if (move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK) break;
  1171.                         wc |= fs->win[bc % SS(fs)] << 8;        /* Merge 2nd byte of the entry */
  1172.                         val = (clst & 1) ? (wc >> 4) : (wc & 0xFFF);    /* Adjust bit position */
  1173.                         break;
  1174.  
  1175.                 case FS_FAT16 :
  1176.                         if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))) != FR_OK) break;
  1177.                         val = ld_word(fs->win + clst * 2 % SS(fs));             /* Simple WORD array */
  1178.                         break;
  1179.  
  1180.                 case FS_FAT32 :
  1181.                         if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break;
  1182.                         val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x0FFFFFFF;       /* Simple DWORD array but mask out upper 4 bits */
  1183.                         break;
  1184. #if FF_FS_EXFAT
  1185.                 case FS_EXFAT :
  1186.                         if ((obj->objsize != 0 && obj->sclust != 0) || obj->stat == 0) {        /* Object except root dir must have valid data length */
  1187.                                 DWORD cofs = clst - obj->sclust;        /* Offset from start cluster */
  1188.                                 DWORD clen = (DWORD)((obj->objsize - 1) / SS(fs)) / fs->csize;  /* Number of clusters - 1 */
  1189.  
  1190.                                 if (obj->stat == 2 && cofs <= clen) {   /* Is it a contiguous chain? */
  1191.                                         val = (cofs == clen) ? 0x7FFFFFFF : clst + 1;   /* No data on the FAT, generate the value */
  1192.                                         break;
  1193.                                 }
  1194.                                 if (obj->stat == 3 && cofs < obj->n_cont) {     /* Is it in the 1st fragment? */
  1195.                                         val = clst + 1;         /* Generate the value */
  1196.                                         break;
  1197.                                 }
  1198.                                 if (obj->stat != 2) {   /* Get value from FAT if FAT chain is valid */
  1199.                                         if (obj->n_frag != 0) { /* Is it on the growing edge? */
  1200.                                                 val = 0x7FFFFFFF;       /* Generate EOC */
  1201.                                         } else {
  1202.                                                 if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break;
  1203.                                                 val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x7FFFFFFF;
  1204.                                         }
  1205.                                         break;
  1206.                                 }
  1207.                         }
  1208.                         /* go to default */
  1209. #endif
  1210.                 default:
  1211.                         val = 1;        /* Internal error */
  1212.                 }
  1213.         }
  1214.  
  1215.         return val;
  1216. }
  1217.  
  1218.  
  1219.  
  1220.  
  1221. #if !FF_FS_READONLY
  1222. /*-----------------------------------------------------------------------*/
  1223. /* FAT access - Change value of a FAT entry                              */
  1224. /*-----------------------------------------------------------------------*/
  1225.  
  1226. static FRESULT put_fat (        /* FR_OK(0):succeeded, !=0:error */
  1227.         FATFS* fs,              /* Corresponding filesystem object */
  1228.         DWORD clst,             /* FAT index number (cluster number) to be changed */
  1229.         DWORD val               /* New value to be set to the entry */
  1230. )
  1231. {
  1232.         UINT bc;
  1233.         BYTE *p;
  1234.         FRESULT res = FR_INT_ERR;
  1235.  
  1236.  
  1237.         if (clst >= 2 && clst < fs->n_fatent) { /* Check if in valid range */
  1238.                 switch (fs->fs_type) {
  1239.                 case FS_FAT12 :
  1240.                         bc = (UINT)clst; bc += bc / 2;  /* bc: byte offset of the entry */
  1241.                         res = move_window(fs, fs->fatbase + (bc / SS(fs)));
  1242.                         if (res != FR_OK) break;
  1243.                         p = fs->win + bc++ % SS(fs);
  1244.                         *p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val;         /* Put 1st byte */
  1245.                         fs->wflag = 1;
  1246.                         res = move_window(fs, fs->fatbase + (bc / SS(fs)));
  1247.                         if (res != FR_OK) break;
  1248.                         p = fs->win + bc % SS(fs);
  1249.                         *p = (clst & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F)); /* Put 2nd byte */
  1250.                         fs->wflag = 1;
  1251.                         break;
  1252.  
  1253.                 case FS_FAT16 :
  1254.                         res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 2)));
  1255.                         if (res != FR_OK) break;
  1256.                         st_word(fs->win + clst * 2 % SS(fs), (WORD)val);        /* Simple WORD array */
  1257.                         fs->wflag = 1;
  1258.                         break;
  1259.  
  1260.                 case FS_FAT32 :
  1261. #if FF_FS_EXFAT
  1262.                 case FS_EXFAT :
  1263. #endif
  1264.                         res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 4)));
  1265.                         if (res != FR_OK) break;
  1266.                         if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) {
  1267.                                 val = (val & 0x0FFFFFFF) | (ld_dword(fs->win + clst * 4 % SS(fs)) & 0xF0000000);
  1268.                         }
  1269.                         st_dword(fs->win + clst * 4 % SS(fs), val);
  1270.                         fs->wflag = 1;
  1271.                         break;
  1272.                 }
  1273.         }
  1274.         return res;
  1275. }
  1276.  
  1277. #endif /* !FF_FS_READONLY */
  1278.  
  1279.  
  1280.  
  1281.  
  1282. #if FF_FS_EXFAT && !FF_FS_READONLY
  1283. /*-----------------------------------------------------------------------*/
  1284. /* exFAT: Accessing FAT and Allocation Bitmap                            */
  1285. /*-----------------------------------------------------------------------*/
  1286.  
  1287. /*--------------------------------------*/
  1288. /* Find a contiguous free cluster block */
  1289. /*--------------------------------------*/
  1290.  
  1291. static DWORD find_bitmap (      /* 0:Not found, 2..:Cluster block found, 0xFFFFFFFF:Disk error */
  1292.         FATFS* fs,      /* Filesystem object */
  1293.         DWORD clst,     /* Cluster number to scan from */
  1294.         DWORD ncl       /* Number of contiguous clusters to find (1..) */
  1295. )
  1296. {
  1297.         BYTE bm, bv;
  1298.         UINT i;
  1299.         DWORD val, scl, ctr;
  1300.  
  1301.  
  1302.         clst -= 2;      /* The first bit in the bitmap corresponds to cluster #2 */
  1303.         if (clst >= fs->n_fatent - 2) clst = 0;
  1304.         scl = val = clst; ctr = 0;
  1305.         for (;;) {
  1306.                 if (move_window(fs, fs->bitbase + val / 8 / SS(fs)) != FR_OK) return 0xFFFFFFFF;
  1307.                 i = val / 8 % SS(fs); bm = 1 << (val % 8);
  1308.                 do {
  1309.                         do {
  1310.                                 bv = fs->win[i] & bm; bm <<= 1;         /* Get bit value */
  1311.                                 if (++val >= fs->n_fatent - 2) {        /* Next cluster (with wrap-around) */
  1312.                                         val = 0; bm = 0; i = SS(fs);
  1313.                                 }
  1314.                                 if (bv == 0) {  /* Is it a free cluster? */
  1315.                                         if (++ctr == ncl) return scl + 2;       /* Check if run length is sufficient for required */
  1316.                                 } else {
  1317.                                         scl = val; ctr = 0;             /* Encountered a cluster in-use, restart to scan */
  1318.                                 }
  1319.                                 if (val == clst) return 0;      /* All cluster scanned? */
  1320.                         } while (bm != 0);
  1321.                         bm = 1;
  1322.                 } while (++i < SS(fs));
  1323.         }
  1324. }
  1325.  
  1326.  
  1327. /*----------------------------------------*/
  1328. /* Set/Clear a block of allocation bitmap */
  1329. /*----------------------------------------*/
  1330.  
  1331. static FRESULT change_bitmap (
  1332.         FATFS* fs,      /* Filesystem object */
  1333.         DWORD clst,     /* Cluster number to change from */
  1334.         DWORD ncl,      /* Number of clusters to be changed */
  1335.         int bv          /* bit value to be set (0 or 1) */
  1336. )
  1337. {
  1338.         BYTE bm;
  1339.         UINT i;
  1340.         DWORD sect;
  1341.  
  1342.  
  1343.         clst -= 2;      /* The first bit corresponds to cluster #2 */
  1344.         sect = fs->bitbase + clst / 8 / SS(fs); /* Sector address */
  1345.         i = clst / 8 % SS(fs);                                  /* Byte offset in the sector */
  1346.         bm = 1 << (clst % 8);                                   /* Bit mask in the byte */
  1347.         for (;;) {
  1348.                 if (move_window(fs, sect++) != FR_OK) return FR_DISK_ERR;
  1349.                 do {
  1350.                         do {
  1351.                                 if (bv == (int)((fs->win[i] & bm) != 0)) return FR_INT_ERR;     /* Is the bit expected value? */
  1352.                                 fs->win[i] ^= bm;       /* Flip the bit */
  1353.                                 fs->wflag = 1;
  1354.                                 if (--ncl == 0) return FR_OK;   /* All bits processed? */
  1355.                         } while (bm <<= 1);             /* Next bit */
  1356.                         bm = 1;
  1357.                 } while (++i < SS(fs));         /* Next byte */
  1358.                 i = 0;
  1359.         }
  1360. }
  1361.  
  1362.  
  1363. /*---------------------------------------------*/
  1364. /* Fill the first fragment of the FAT chain    */
  1365. /*---------------------------------------------*/
  1366.  
  1367. static FRESULT fill_first_frag (
  1368.         FFOBJID* obj    /* Pointer to the corresponding object */
  1369. )
  1370. {
  1371.         FRESULT res;
  1372.         DWORD cl, n;
  1373.  
  1374.  
  1375.         if (obj->stat == 3) {   /* Has the object been changed 'fragmented' in this session? */
  1376.                 for (cl = obj->sclust, n = obj->n_cont; n; cl++, n--) { /* Create cluster chain on the FAT */
  1377.                         res = put_fat(obj->fs, cl, cl + 1);
  1378.                         if (res != FR_OK) return res;
  1379.                 }
  1380.                 obj->stat = 0;  /* Change status 'FAT chain is valid' */
  1381.         }
  1382.         return FR_OK;
  1383. }
  1384.  
  1385.  
  1386. /*---------------------------------------------*/
  1387. /* Fill the last fragment of the FAT chain     */
  1388. /*---------------------------------------------*/
  1389.  
  1390. static FRESULT fill_last_frag (
  1391.         FFOBJID* obj,   /* Pointer to the corresponding object */
  1392.         DWORD lcl,              /* Last cluster of the fragment */
  1393.         DWORD term              /* Value to set the last FAT entry */
  1394. )
  1395. {
  1396.         FRESULT res;
  1397.  
  1398.  
  1399.         while (obj->n_frag > 0) {       /* Create the chain of last fragment */
  1400.                 res = put_fat(obj->fs, lcl - obj->n_frag + 1, (obj->n_frag > 1) ? lcl - obj->n_frag + 2 : term);
  1401.                 if (res != FR_OK) return res;
  1402.                 obj->n_frag--;
  1403.         }
  1404.         return FR_OK;
  1405. }
  1406.  
  1407. #endif  /* FF_FS_EXFAT && !FF_FS_READONLY */
  1408.  
  1409.  
  1410.  
  1411. #if !FF_FS_READONLY
  1412. /*-----------------------------------------------------------------------*/
  1413. /* FAT handling - Remove a cluster chain                                 */
  1414. /*-----------------------------------------------------------------------*/
  1415.  
  1416. static FRESULT remove_chain (   /* FR_OK(0):succeeded, !=0:error */
  1417.         FFOBJID* obj,           /* Corresponding object */
  1418.         DWORD clst,                     /* Cluster to remove a chain from */
  1419.         DWORD pclst                     /* Previous cluster of clst (0 if entire chain) */
  1420. )
  1421. {
  1422.         FRESULT res = FR_OK;
  1423.         DWORD nxt;
  1424.         FATFS *fs = obj->fs;
  1425. #if FF_FS_EXFAT || FF_USE_TRIM
  1426.         DWORD scl = clst, ecl = clst;
  1427. #endif
  1428. #if FF_USE_TRIM
  1429.         DWORD rt[2];
  1430. #endif
  1431.  
  1432.         if (clst < 2 || clst >= fs->n_fatent) return FR_INT_ERR;        /* Check if in valid range */
  1433.  
  1434.         /* Mark the previous cluster 'EOC' on the FAT if it exists */
  1435.         if (pclst != 0 && (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT || obj->stat != 2)) {
  1436.                 res = put_fat(fs, pclst, 0xFFFFFFFF);
  1437.                 if (res != FR_OK) return res;
  1438.         }
  1439.  
  1440.         /* Remove the chain */
  1441.         do {
  1442.                 nxt = get_fat(obj, clst);                       /* Get cluster status */
  1443.                 if (nxt == 0) break;                            /* Empty cluster? */
  1444.                 if (nxt == 1) return FR_INT_ERR;        /* Internal error? */
  1445.                 if (nxt == 0xFFFFFFFF) return FR_DISK_ERR;      /* Disk error? */
  1446.                 if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) {
  1447.                         res = put_fat(fs, clst, 0);             /* Mark the cluster 'free' on the FAT */
  1448.                         if (res != FR_OK) return res;
  1449.                 }
  1450.                 if (fs->free_clst < fs->n_fatent - 2) { /* Update FSINFO */
  1451.                         fs->free_clst++;
  1452.                         fs->fsi_flag |= 1;
  1453.                 }
  1454. #if FF_FS_EXFAT || FF_USE_TRIM
  1455.                 if (ecl + 1 == nxt) {   /* Is next cluster contiguous? */
  1456.                         ecl = nxt;
  1457.                 } else {                                /* End of contiguous cluster block */
  1458. #if FF_FS_EXFAT
  1459.                         if (fs->fs_type == FS_EXFAT) {
  1460.                                 res = change_bitmap(fs, scl, ecl - scl + 1, 0); /* Mark the cluster block 'free' on the bitmap */
  1461.                                 if (res != FR_OK) return res;
  1462.                         }
  1463. #endif
  1464. #if FF_USE_TRIM
  1465.                         rt[0] = clst2sect(fs, scl);                                     /* Start of data area freed */
  1466.                         rt[1] = clst2sect(fs, ecl) + fs->csize - 1;     /* End of data area freed */
  1467.                         disk_ioctl(fs->pdrv, CTRL_TRIM, rt);            /* Inform device the data in the block is no longer needed */
  1468. #endif
  1469.                         scl = ecl = nxt;
  1470.                 }
  1471. #endif
  1472.                 clst = nxt;                                     /* Next cluster */
  1473.         } while (clst < fs->n_fatent);  /* Repeat while not the last link */
  1474.  
  1475. #if FF_FS_EXFAT
  1476.         /* Some post processes for chain status */
  1477.         if (fs->fs_type == FS_EXFAT) {
  1478.                 if (pclst == 0) {       /* Has the entire chain been removed? */
  1479.                         obj->stat = 0;          /* Change the chain status 'initial' */
  1480.                 } else {
  1481.                         if (obj->stat == 0) {   /* Is it a fragmented chain from the beginning of this session? */
  1482.                                 clst = obj->sclust;             /* Follow the chain to check if it gets contiguous */
  1483.                                 while (clst != pclst) {
  1484.                                         nxt = get_fat(obj, clst);
  1485.                                         if (nxt < 2) return FR_INT_ERR;
  1486.                                         if (nxt == 0xFFFFFFFF) return FR_DISK_ERR;
  1487.                                         if (nxt != clst + 1) break;     /* Not contiguous? */
  1488.                                         clst++;
  1489.                                 }
  1490.                                 if (clst == pclst) {    /* Has the chain got contiguous again? */
  1491.                                         obj->stat = 2;          /* Change the chain status 'contiguous' */
  1492.                                 }
  1493.                         } else {
  1494.                                 if (obj->stat == 3 && pclst >= obj->sclust && pclst <= obj->sclust + obj->n_cont) {     /* Was the chain fragmented in this session and got contiguous again? */
  1495.                                         obj->stat = 2;  /* Change the chain status 'contiguous' */
  1496.                                 }
  1497.                         }
  1498.                 }
  1499.         }
  1500. #endif
  1501.         return FR_OK;
  1502. }
  1503.  
  1504.  
  1505.  
  1506.  
  1507. /*-----------------------------------------------------------------------*/
  1508. /* FAT handling - Stretch a chain or Create a new chain                  */
  1509. /*-----------------------------------------------------------------------*/
  1510.  
  1511. static DWORD create_chain (     /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */
  1512.         FFOBJID* obj,           /* Corresponding object */
  1513.         DWORD clst                      /* Cluster# to stretch, 0:Create a new chain */
  1514. )
  1515. {
  1516.         DWORD cs, ncl, scl;
  1517.         FRESULT res;
  1518.         FATFS *fs = obj->fs;
  1519.  
  1520.  
  1521.         if (clst == 0) {        /* Create a new chain */
  1522.                 scl = fs->last_clst;                            /* Suggested cluster to start to find */
  1523.                 if (scl == 0 || scl >= fs->n_fatent) scl = 1;
  1524.         }
  1525.         else {                          /* Stretch a chain */
  1526.                 cs = get_fat(obj, clst);                        /* Check the cluster status */
  1527.                 if (cs < 2) return 1;                           /* Test for insanity */
  1528.                 if (cs == 0xFFFFFFFF) return cs;        /* Test for disk error */
  1529.                 if (cs < fs->n_fatent) return cs;       /* It is already followed by next cluster */
  1530.                 scl = clst;                                                     /* Cluster to start to find */
  1531.         }
  1532.         if (fs->free_clst == 0) return 0;               /* No free cluster */
  1533.  
  1534. #if FF_FS_EXFAT
  1535.         if (fs->fs_type == FS_EXFAT) {  /* On the exFAT volume */
  1536.                 ncl = find_bitmap(fs, scl, 1);                          /* Find a free cluster */
  1537.                 if (ncl == 0 || ncl == 0xFFFFFFFF) return ncl;  /* No free cluster or hard error? */
  1538.                 res = change_bitmap(fs, ncl, 1, 1);                     /* Mark the cluster 'in use' */
  1539.                 if (res == FR_INT_ERR) return 1;
  1540.                 if (res == FR_DISK_ERR) return 0xFFFFFFFF;
  1541.                 if (clst == 0) {                                                        /* Is it a new chain? */
  1542.                         obj->stat = 2;                                                  /* Set status 'contiguous' */
  1543.                 } else {                                                                        /* It is a stretched chain */
  1544.                         if (obj->stat == 2 && ncl != scl + 1) { /* Is the chain got fragmented? */
  1545.                                 obj->n_cont = scl - obj->sclust;        /* Set size of the contiguous part */
  1546.                                 obj->stat = 3;                                          /* Change status 'just fragmented' */
  1547.                         }
  1548.                 }
  1549.                 if (obj->stat != 2) {   /* Is the file non-contiguous? */
  1550.                         if (ncl == clst + 1) {  /* Is the cluster next to previous one? */
  1551.                                 obj->n_frag = obj->n_frag ? obj->n_frag + 1 : 2;        /* Increment size of last framgent */
  1552.                         } else {                                /* New fragment */
  1553.                                 if (obj->n_frag == 0) obj->n_frag = 1;
  1554.                                 res = fill_last_frag(obj, clst, ncl);   /* Fill last fragment on the FAT and link it to new one */
  1555.                                 if (res == FR_OK) obj->n_frag = 1;
  1556.                         }
  1557.                 }
  1558.         } else
  1559. #endif
  1560.         {       /* On the FAT/FAT32 volume */
  1561.                 ncl = 0;
  1562.                 if (scl == clst) {                                              /* Stretching an existing chain? */
  1563.                         ncl = scl + 1;                                          /* Test if next cluster is free */
  1564.                         if (ncl >= fs->n_fatent) ncl = 2;
  1565.                         cs = get_fat(obj, ncl);                         /* Get next cluster status */
  1566.                         if (cs == 1 || cs == 0xFFFFFFFF) return cs;     /* Test for error */
  1567.                         if (cs != 0) {                                          /* Not free? */
  1568.                                 cs = fs->last_clst;                             /* Start at suggested cluster if it is valid */
  1569.                                 if (cs >= 2 && cs < fs->n_fatent) scl = cs;
  1570.                                 ncl = 0;
  1571.                         }
  1572.                 }
  1573.                 if (ncl == 0) { /* The new cluster cannot be contiguous and find another fragment */
  1574.                         ncl = scl;      /* Start cluster */
  1575.                         for (;;) {
  1576.                                 ncl++;                                                  /* Next cluster */
  1577.                                 if (ncl >= fs->n_fatent) {              /* Check wrap-around */
  1578.                                         ncl = 2;
  1579.                                         if (ncl > scl) return 0;        /* No free cluster found? */
  1580.                                 }
  1581.                                 cs = get_fat(obj, ncl);                 /* Get the cluster status */
  1582.                                 if (cs == 0) break;                             /* Found a free cluster? */
  1583.                                 if (cs == 1 || cs == 0xFFFFFFFF) return cs;     /* Test for error */
  1584.                                 if (ncl == scl) return 0;               /* No free cluster found? */
  1585.                         }
  1586.                 }
  1587.                 res = put_fat(fs, ncl, 0xFFFFFFFF);             /* Mark the new cluster 'EOC' */
  1588.                 if (res == FR_OK && clst != 0) {
  1589.                         res = put_fat(fs, clst, ncl);           /* Link it from the previous one if needed */
  1590.                 }
  1591.         }
  1592.  
  1593.         if (res == FR_OK) {                     /* Update FSINFO if function succeeded. */
  1594.                 fs->last_clst = ncl;
  1595.                 if (fs->free_clst <= fs->n_fatent - 2) fs->free_clst--;
  1596.                 fs->fsi_flag |= 1;
  1597.         } else {
  1598.                 ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1;    /* Failed. Generate error status */
  1599.         }
  1600.  
  1601.         return ncl;             /* Return new cluster number or error status */
  1602. }
  1603.  
  1604. #endif /* !FF_FS_READONLY */
  1605.  
  1606.  
  1607.  
  1608.  
  1609. #if FF_USE_FASTSEEK
  1610. /*-----------------------------------------------------------------------*/
  1611. /* FAT handling - Convert offset into cluster with link map table        */
  1612. /*-----------------------------------------------------------------------*/
  1613.  
  1614. static DWORD clmt_clust (       /* <2:Error, >=2:Cluster number */
  1615.         FIL* fp,                /* Pointer to the file object */
  1616.         FSIZE_t ofs             /* File offset to be converted to cluster# */
  1617. )
  1618. {
  1619.         DWORD cl, ncl, *tbl;
  1620.         FATFS *fs = fp->obj.fs;
  1621.  
  1622.  
  1623.         tbl = fp->cltbl + 1;    /* Top of CLMT */
  1624.         cl = (DWORD)(ofs / SS(fs) / fs->csize); /* Cluster order from top of the file */
  1625.         for (;;) {
  1626.                 ncl = *tbl++;                   /* Number of cluters in the fragment */
  1627.                 if (ncl == 0) return 0; /* End of table? (error) */
  1628.                 if (cl < ncl) break;    /* In this fragment? */
  1629.                 cl -= ncl; tbl++;               /* Next fragment */
  1630.         }
  1631.         return cl + *tbl;       /* Return the cluster number */
  1632. }
  1633.  
  1634. #endif  /* FF_USE_FASTSEEK */
  1635.  
  1636.  
  1637.  
  1638.  
  1639. /*-----------------------------------------------------------------------*/
  1640. /* Directory handling - Fill a cluster with zeros                        */
  1641. /*-----------------------------------------------------------------------*/
  1642.  
  1643. #if !FF_FS_READONLY
  1644. static FRESULT dir_clear (      /* Returns FR_OK or FR_DISK_ERR */
  1645.         FATFS *fs,              /* Filesystem object */
  1646.         DWORD clst              /* Directory table to clear */
  1647. )
  1648. {
  1649.         DWORD sect;
  1650.         UINT n, szb;
  1651.         BYTE *ibuf;
  1652.  
  1653.  
  1654.         if (sync_window(fs) != FR_OK) return FR_DISK_ERR;       /* Flush disk access window */
  1655.         sect = clst2sect(fs, clst);             /* Top of the cluster */
  1656.         fs->winsect = sect;                             /* Set window to top of the cluster */
  1657.         mem_set(fs->win, 0, sizeof fs->win);    /* Clear window buffer */
  1658. #if FF_USE_LFN == 3             /* Quick table clear by using multi-secter write */
  1659.         /* Allocate a temporary buffer */
  1660.         for (szb = ((DWORD)fs->csize * SS(fs) >= MAX_MALLOC) ? MAX_MALLOC : fs->csize * SS(fs), ibuf = 0; szb > SS(fs) && (ibuf = ff_memalloc(szb)) == 0; szb /= 2) ;
  1661.         if (szb > SS(fs)) {             /* Buffer allocated? */
  1662.                 mem_set(ibuf, 0, szb);
  1663.                 szb /= SS(fs);          /* Bytes -> Sectors */
  1664.                 for (n = 0; n < fs->csize && disk_write(fs->pdrv, ibuf, sect + n, szb) == RES_OK; n += szb) ;   /* Fill the cluster with 0 */
  1665.                 ff_memfree(ibuf);
  1666.         } else
  1667. #endif
  1668.         {
  1669.                 ibuf = fs->win; szb = 1;        /* Use window buffer (many single-sector writes may take a time) */
  1670.                 for (n = 0; n < fs->csize && disk_write(fs->pdrv, ibuf, sect + n, szb) == RES_OK; n += szb) ;   /* Fill the cluster with 0 */
  1671.         }
  1672.         return (n == fs->csize) ? FR_OK : FR_DISK_ERR;
  1673. }
  1674. #endif  /* !FF_FS_READONLY */
  1675.  
  1676.  
  1677.  
  1678.  
  1679. /*-----------------------------------------------------------------------*/
  1680. /* Directory handling - Set directory index                              */
  1681. /*-----------------------------------------------------------------------*/
  1682.  
  1683. static FRESULT dir_sdi (        /* FR_OK(0):succeeded, !=0:error */
  1684.         DIR* dp,                /* Pointer to directory object */
  1685.         DWORD ofs               /* Offset of directory table */
  1686. )
  1687. {
  1688.         DWORD csz, clst;
  1689.         FATFS *fs = dp->obj.fs;
  1690.  
  1691.  
  1692.         if (ofs >= (DWORD)((FF_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR) || ofs % SZDIRE) {  /* Check range of offset and alignment */
  1693.                 return FR_INT_ERR;
  1694.         }
  1695.         dp->dptr = ofs;                         /* Set current offset */
  1696.         clst = dp->obj.sclust;          /* Table start cluster (0:root) */
  1697.         if (clst == 0 && fs->fs_type >= FS_FAT32) {     /* Replace cluster# 0 with root cluster# */
  1698.                 clst = fs->dirbase;
  1699.                 if (FF_FS_EXFAT) dp->obj.stat = 0;      /* exFAT: Root dir has an FAT chain */
  1700.         }
  1701.  
  1702.         if (clst == 0) {        /* Static table (root-directory on the FAT volume) */
  1703.                 if (ofs / SZDIRE >= fs->n_rootdir) return FR_INT_ERR;   /* Is index out of range? */
  1704.                 dp->sect = fs->dirbase;
  1705.  
  1706.         } else {                        /* Dynamic table (sub-directory or root-directory on the FAT32/exFAT volume) */
  1707.                 csz = (DWORD)fs->csize * SS(fs);        /* Bytes per cluster */
  1708.                 while (ofs >= csz) {                            /* Follow cluster chain */
  1709.                         clst = get_fat(&dp->obj, clst);                         /* Get next cluster */
  1710.                         if (clst == 0xFFFFFFFF) return FR_DISK_ERR;     /* Disk error */
  1711.                         if (clst < 2 || clst >= fs->n_fatent) return FR_INT_ERR;        /* Reached to end of table or internal error */
  1712.                         ofs -= csz;
  1713.                 }
  1714.                 dp->sect = clst2sect(fs, clst);
  1715.         }
  1716.         dp->clust = clst;                                       /* Current cluster# */
  1717.         if (dp->sect == 0) return FR_INT_ERR;
  1718.         dp->sect += ofs / SS(fs);                       /* Sector# of the directory entry */
  1719.         dp->dir = fs->win + (ofs % SS(fs));     /* Pointer to the entry in the win[] */
  1720.  
  1721.         return FR_OK;
  1722. }
  1723.  
  1724.  
  1725.  
  1726.  
  1727. /*-----------------------------------------------------------------------*/
  1728. /* Directory handling - Move directory table index next                  */
  1729. /*-----------------------------------------------------------------------*/
  1730.  
  1731. static FRESULT dir_next (       /* FR_OK(0):succeeded, FR_NO_FILE:End of table, FR_DENIED:Could not stretch */
  1732.         DIR* dp,                                /* Pointer to the directory object */
  1733.         int stretch                             /* 0: Do not stretch table, 1: Stretch table if needed */
  1734. )
  1735. {
  1736.         DWORD ofs, clst;
  1737.         FATFS *fs = dp->obj.fs;
  1738.  
  1739.  
  1740.         ofs = dp->dptr + SZDIRE;        /* Next entry */
  1741.         if (ofs >= (DWORD)((FF_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR)) dp->sect = 0;      /* Disable it if the offset reached the max value */
  1742.         if (dp->sect == 0) return FR_NO_FILE;   /* Report EOT if it has been disabled */
  1743.  
  1744.         if (ofs % SS(fs) == 0) {        /* Sector changed? */
  1745.                 dp->sect++;                             /* Next sector */
  1746.  
  1747.                 if (dp->clust == 0) {   /* Static table */
  1748.                         if (ofs / SZDIRE >= fs->n_rootdir) {    /* Report EOT if it reached end of static table */
  1749.                                 dp->sect = 0; return FR_NO_FILE;
  1750.                         }
  1751.                 }
  1752.                 else {                                  /* Dynamic table */
  1753.                         if ((ofs / SS(fs) & (fs->csize - 1)) == 0) {    /* Cluster changed? */
  1754.                                 clst = get_fat(&dp->obj, dp->clust);            /* Get next cluster */
  1755.                                 if (clst <= 1) return FR_INT_ERR;                       /* Internal error */
  1756.                                 if (clst == 0xFFFFFFFF) return FR_DISK_ERR;     /* Disk error */
  1757.                                 if (clst >= fs->n_fatent) {                                     /* It reached end of dynamic table */
  1758. #if !FF_FS_READONLY
  1759.                                         if (!stretch) {                                                         /* If no stretch, report EOT */
  1760.                                                 dp->sect = 0; return FR_NO_FILE;
  1761.                                         }
  1762.                                         clst = create_chain(&dp->obj, dp->clust);       /* Allocate a cluster */
  1763.                                         if (clst == 0) return FR_DENIED;                        /* No free cluster */
  1764.                                         if (clst == 1) return FR_INT_ERR;                       /* Internal error */
  1765.                                         if (clst == 0xFFFFFFFF) return FR_DISK_ERR;     /* Disk error */
  1766.                                         if (dir_clear(fs, clst) != FR_OK) return FR_DISK_ERR;   /* Clean up the stretched table */
  1767.                                         if (FF_FS_EXFAT) dp->obj.stat |= 4;                     /* exFAT: The directory has been stretched */
  1768. #else
  1769.                                         if (!stretch) dp->sect = 0;                                     /* (this line is to suppress compiler warning) */
  1770.                                         dp->sect = 0; return FR_NO_FILE;                        /* Report EOT */
  1771. #endif
  1772.                                 }
  1773.                                 dp->clust = clst;               /* Initialize data for new cluster */
  1774.                                 dp->sect = clst2sect(fs, clst);
  1775.                         }
  1776.                 }
  1777.         }
  1778.         dp->dptr = ofs;                                         /* Current entry */
  1779.         dp->dir = fs->win + ofs % SS(fs);       /* Pointer to the entry in the win[] */
  1780.  
  1781.         return FR_OK;
  1782. }
  1783.  
  1784.  
  1785.  
  1786.  
  1787. #if !FF_FS_READONLY
  1788. /*-----------------------------------------------------------------------*/
  1789. /* Directory handling - Reserve a block of directory entries             */
  1790. /*-----------------------------------------------------------------------*/
  1791.  
  1792. static FRESULT dir_alloc (      /* FR_OK(0):succeeded, !=0:error */
  1793.         DIR* dp,                                /* Pointer to the directory object */
  1794.         UINT nent                               /* Number of contiguous entries to allocate */
  1795. )
  1796. {
  1797.         FRESULT res;
  1798.         UINT n;
  1799.         FATFS *fs = dp->obj.fs;
  1800.  
  1801.  
  1802.         res = dir_sdi(dp, 0);
  1803.         if (res == FR_OK) {
  1804.                 n = 0;
  1805.                 do {
  1806.                         res = move_window(fs, dp->sect);
  1807.                         if (res != FR_OK) break;
  1808. #if FF_FS_EXFAT
  1809.                         if ((fs->fs_type == FS_EXFAT) ? (int)((dp->dir[XDIR_Type] & 0x80) == 0) : (int)(dp->dir[DIR_Name] == DDEM || dp->dir[DIR_Name] == 0)) {
  1810. #else
  1811.                         if (dp->dir[DIR_Name] == DDEM || dp->dir[DIR_Name] == 0) {
  1812. #endif
  1813.                                 if (++n == nent) break; /* A block of contiguous free entries is found */
  1814.                         } else {
  1815.                                 n = 0;                                  /* Not a blank entry. Restart to search */
  1816.                         }
  1817.                         res = dir_next(dp, 1);
  1818.                 } while (res == FR_OK); /* Next entry with table stretch enabled */
  1819.         }
  1820.  
  1821.         if (res == FR_NO_FILE) res = FR_DENIED; /* No directory entry to allocate */
  1822.         return res;
  1823. }
  1824.  
  1825. #endif  /* !FF_FS_READONLY */
  1826.  
  1827.  
  1828.  
  1829.  
  1830. /*-----------------------------------------------------------------------*/
  1831. /* FAT: Directory handling - Load/Store start cluster number             */
  1832. /*-----------------------------------------------------------------------*/
  1833.  
  1834. static DWORD ld_clust ( /* Returns the top cluster value of the SFN entry */
  1835.         FATFS* fs,                      /* Pointer to the fs object */
  1836.         const BYTE* dir         /* Pointer to the key entry */
  1837. )
  1838. {
  1839.         DWORD cl;
  1840.  
  1841.         cl = ld_word(dir + DIR_FstClusLO);
  1842.         if (fs->fs_type == FS_FAT32) {
  1843.                 cl |= (DWORD)ld_word(dir + DIR_FstClusHI) << 16;
  1844.         }
  1845.  
  1846.         return cl;
  1847. }
  1848.  
  1849.  
  1850. #if !FF_FS_READONLY
  1851. static void st_clust (
  1852.         FATFS* fs,      /* Pointer to the fs object */
  1853.         BYTE* dir,      /* Pointer to the key entry */
  1854.         DWORD cl        /* Value to be set */
  1855. )
  1856. {
  1857.         st_word(dir + DIR_FstClusLO, (WORD)cl);
  1858.         if (fs->fs_type == FS_FAT32) {
  1859.                 st_word(dir + DIR_FstClusHI, (WORD)(cl >> 16));
  1860.         }
  1861. }
  1862. #endif
  1863.  
  1864.  
  1865.  
  1866. #if FF_USE_LFN
  1867. /*--------------------------------------------------------*/
  1868. /* FAT-LFN: Compare a part of file name with an LFN entry */
  1869. /*--------------------------------------------------------*/
  1870.  
  1871. static int cmp_lfn (            /* 1:matched, 0:not matched */
  1872.         const WCHAR* lfnbuf,    /* Pointer to the LFN working buffer to be compared */
  1873.         BYTE* dir                               /* Pointer to the directory entry containing the part of LFN */
  1874. )
  1875. {
  1876.         UINT i, s;
  1877.         WCHAR wc, uc;
  1878.  
  1879.  
  1880.         if (ld_word(dir + LDIR_FstClusLO) != 0) return 0;       /* Check LDIR_FstClusLO */
  1881.  
  1882.         i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13;  /* Offset in the LFN buffer */
  1883.  
  1884.         for (wc = 1, s = 0; s < 13; s++) {              /* Process all characters in the entry */
  1885.                 uc = ld_word(dir + LfnOfs[s]);          /* Pick an LFN character */
  1886.                 if (wc != 0) {
  1887.                         if (i >= FF_MAX_LFN || ff_wtoupper(uc) != ff_wtoupper(lfnbuf[i++])) {   /* Compare it */
  1888.                                 return 0;                                       /* Not matched */
  1889.                         }
  1890.                         wc = uc;
  1891.                 } else {
  1892.                         if (uc != 0xFFFF) return 0;             /* Check filler */
  1893.                 }
  1894.         }
  1895.  
  1896.         if ((dir[LDIR_Ord] & LLEF) && wc && lfnbuf[i]) return 0;        /* Last segment matched but different length */
  1897.  
  1898.         return 1;               /* The part of LFN matched */
  1899. }
  1900.  
  1901.  
  1902. #if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 || FF_USE_LABEL || FF_FS_EXFAT
  1903. /*-----------------------------------------------------*/
  1904. /* FAT-LFN: Pick a part of file name from an LFN entry */
  1905. /*-----------------------------------------------------*/
  1906.  
  1907. static int pick_lfn (   /* 1:succeeded, 0:buffer overflow or invalid LFN entry */
  1908.         WCHAR* lfnbuf,          /* Pointer to the LFN working buffer */
  1909.         BYTE* dir                       /* Pointer to the LFN entry */
  1910. )
  1911. {
  1912.         UINT i, s;
  1913.         WCHAR wc, uc;
  1914.  
  1915.  
  1916.         if (ld_word(dir + LDIR_FstClusLO) != 0) return 0;       /* Check LDIR_FstClusLO is 0 */
  1917.  
  1918.         i = ((dir[LDIR_Ord] & ~LLEF) - 1) * 13; /* Offset in the LFN buffer */
  1919.  
  1920.         for (wc = 1, s = 0; s < 13; s++) {              /* Process all characters in the entry */
  1921.                 uc = ld_word(dir + LfnOfs[s]);          /* Pick an LFN character */
  1922.                 if (wc != 0) {
  1923.                         if (i >= FF_MAX_LFN) return 0;  /* Buffer overflow? */
  1924.                         lfnbuf[i++] = wc = uc;                  /* Store it */
  1925.                 } else {
  1926.                         if (uc != 0xFFFF) return 0;             /* Check filler */
  1927.                 }
  1928.         }
  1929.  
  1930.         if (dir[LDIR_Ord] & LLEF) {                             /* Put terminator if it is the last LFN part */
  1931.                 if (i >= FF_MAX_LFN) return 0;          /* Buffer overflow? */
  1932.                 lfnbuf[i] = 0;
  1933.         }
  1934.  
  1935.         return 1;               /* The part of LFN is valid */
  1936. }
  1937. #endif
  1938.  
  1939.  
  1940. #if !FF_FS_READONLY
  1941. /*-----------------------------------------*/
  1942. /* FAT-LFN: Create an entry of LFN entries */
  1943. /*-----------------------------------------*/
  1944.  
  1945. static void put_lfn (
  1946.         const WCHAR* lfn,       /* Pointer to the LFN */
  1947.         BYTE* dir,                      /* Pointer to the LFN entry to be created */
  1948.         BYTE ord,                       /* LFN order (1-20) */
  1949.         BYTE sum                        /* Checksum of the corresponding SFN */
  1950. )
  1951. {
  1952.         UINT i, s;
  1953.         WCHAR wc;
  1954.  
  1955.  
  1956.         dir[LDIR_Chksum] = sum;                 /* Set checksum */
  1957.         dir[LDIR_Attr] = AM_LFN;                /* Set attribute. LFN entry */
  1958.         dir[LDIR_Type] = 0;
  1959.         st_word(dir + LDIR_FstClusLO, 0);
  1960.  
  1961.         i = (ord - 1) * 13;                             /* Get offset in the LFN working buffer */
  1962.         s = wc = 0;
  1963.         do {
  1964.                 if (wc != 0xFFFF) wc = lfn[i++];        /* Get an effective character */
  1965.                 st_word(dir + LfnOfs[s], wc);           /* Put it */
  1966.                 if (wc == 0) wc = 0xFFFF;               /* Padding characters for left locations */
  1967.         } while (++s < 13);
  1968.         if (wc == 0xFFFF || !lfn[i]) ord |= LLEF;       /* Last LFN part is the start of LFN sequence */
  1969.         dir[LDIR_Ord] = ord;                    /* Set the LFN order */
  1970. }
  1971.  
  1972. #endif  /* !FF_FS_READONLY */
  1973. #endif  /* FF_USE_LFN */
  1974.  
  1975.  
  1976.  
  1977. #if FF_USE_LFN && !FF_FS_READONLY
  1978. /*-----------------------------------------------------------------------*/
  1979. /* FAT-LFN: Create a Numbered SFN                                        */
  1980. /*-----------------------------------------------------------------------*/
  1981.  
  1982. static void gen_numname (
  1983.         BYTE* dst,                      /* Pointer to the buffer to store numbered SFN */
  1984.         const BYTE* src,        /* Pointer to SFN */
  1985.         const WCHAR* lfn,       /* Pointer to LFN */
  1986.         UINT seq                        /* Sequence number */
  1987. )
  1988. {
  1989.         BYTE ns[8], c;
  1990.         UINT i, j;
  1991.         WCHAR wc;
  1992.         DWORD sr;
  1993.  
  1994.  
  1995.         mem_cpy(dst, src, 11);
  1996.  
  1997.         if (seq > 5) {  /* In case of many collisions, generate a hash number instead of sequential number */
  1998.                 sr = seq;
  1999.                 while (*lfn) {  /* Create a CRC as hash value */
  2000.                         wc = *lfn++;
  2001.                         for (i = 0; i < 16; i++) {
  2002.                                 sr = (sr << 1) + (wc & 1);
  2003.                                 wc >>= 1;
  2004.                                 if (sr & 0x10000) sr ^= 0x11021;
  2005.                         }
  2006.                 }
  2007.                 seq = (UINT)sr;
  2008.         }
  2009.  
  2010.         /* itoa (hexdecimal) */
  2011.         i = 7;
  2012.         do {
  2013.                 c = (BYTE)((seq % 16) + '0');
  2014.                 if (c > '9') c += 7;
  2015.                 ns[i--] = c;
  2016.                 seq /= 16;
  2017.         } while (seq);
  2018.         ns[i] = '~';
  2019.  
  2020.         /* Append the number to the SFN body */
  2021.         for (j = 0; j < i && dst[j] != ' '; j++) {
  2022.                 if (dbc_1st(dst[j])) {
  2023.                         if (j == i - 1) break;
  2024.                         j++;
  2025.                 }
  2026.         }
  2027.         do {
  2028.                 dst[j++] = (i < 8) ? ns[i++] : ' ';
  2029.         } while (j < 8);
  2030. }
  2031. #endif  /* FF_USE_LFN && !FF_FS_READONLY */
  2032.  
  2033.  
  2034.  
  2035. #if FF_USE_LFN
  2036. /*-----------------------------------------------------------------------*/
  2037. /* FAT-LFN: Calculate checksum of an SFN entry                           */
  2038. /*-----------------------------------------------------------------------*/
  2039.  
  2040. static BYTE sum_sfn (
  2041.         const BYTE* dir         /* Pointer to the SFN entry */
  2042. )
  2043. {
  2044.         BYTE sum = 0;
  2045.         UINT n = 11;
  2046.  
  2047.         do {
  2048.                 sum = (sum >> 1) + (sum << 7) + *dir++;
  2049.         } while (--n);
  2050.         return sum;
  2051. }
  2052.  
  2053. #endif  /* FF_USE_LFN */
  2054.  
  2055.  
  2056.  
  2057. #if FF_FS_EXFAT
  2058. /*-----------------------------------------------------------------------*/
  2059. /* exFAT: Checksum                                                       */
  2060. /*-----------------------------------------------------------------------*/
  2061.  
  2062. static WORD xdir_sum (  /* Get checksum of the directoly entry block */
  2063.         const BYTE* dir         /* Directory entry block to be calculated */
  2064. )
  2065. {
  2066.         UINT i, szblk;
  2067.         WORD sum;
  2068.  
  2069.  
  2070.         szblk = (dir[XDIR_NumSec] + 1) * SZDIRE;        /* Number of bytes of the entry block */
  2071.         for (i = sum = 0; i < szblk; i++) {
  2072.                 if (i == XDIR_SetSum) { /* Skip 2-byte sum field */
  2073.                         i++;
  2074.                 } else {
  2075.                         sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + dir[i];
  2076.                 }
  2077.         }
  2078.         return sum;
  2079. }
  2080.  
  2081.  
  2082.  
  2083. static WORD xname_sum ( /* Get check sum (to be used as hash) of the file name */
  2084.         const WCHAR* name       /* File name to be calculated */
  2085. )
  2086. {
  2087.         WCHAR chr;
  2088.         WORD sum = 0;
  2089.  
  2090.  
  2091.         while ((chr = *name++) != 0) {
  2092.                 chr = (WCHAR)ff_wtoupper(chr);          /* File name needs to be up-case converted */
  2093.                 sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + (chr & 0xFF);
  2094.                 sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + (chr >> 8);
  2095.         }
  2096.         return sum;
  2097. }
  2098.  
  2099.  
  2100. #if !FF_FS_READONLY && FF_USE_MKFS
  2101. static DWORD xsum32 (   /* Returns 32-bit checksum */
  2102.         BYTE  dat,                      /* Byte to be calculated (byte-by-byte processing) */
  2103.         DWORD sum                       /* Previous sum value */
  2104. )
  2105. {
  2106.         sum = ((sum & 1) ? 0x80000000 : 0) + (sum >> 1) + dat;
  2107.         return sum;
  2108. }
  2109. #endif
  2110.  
  2111.  
  2112. #if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2
  2113. /*------------------------------------------------------*/
  2114. /* exFAT: Get object information from a directory block */
  2115. /*------------------------------------------------------*/
  2116.  
  2117. static void get_xfileinfo (
  2118.         BYTE* dirb,                     /* Pointer to the direcotry entry block 85+C0+C1s */
  2119.         FILINFO* fno            /* Buffer to store the extracted file information */
  2120. )
  2121. {
  2122.         WCHAR wc, hs;
  2123.         UINT di, si, nc;
  2124.  
  2125.         /* Get file name from the entry block */
  2126.         si = SZDIRE * 2;        /* 1st C1 entry */
  2127.         nc = 0; hs = 0; di = 0;
  2128.         while (nc < dirb[XDIR_NumName]) {
  2129.                 if (si >= MAXDIRB(FF_MAX_LFN)) { di = 0; break; }       /* Truncated directory block? */
  2130.                 if ((si % SZDIRE) == 0) si += 2;                /* Skip entry type field */
  2131.                 wc = ld_word(dirb + si); si += 2; nc++; /* Get a character */
  2132.                 if (hs == 0 && IsSurrogate(wc)) {       /* Is it a surrogate? */
  2133.                         hs = wc; continue;      /* Get low surrogate */
  2134.                 }
  2135.                 wc = put_utf((DWORD)hs << 16 | wc, &fno->fname[di], FF_LFN_BUF - di);   /* Store it in API encoding */
  2136.                 if (wc == 0) { di = 0; break; } /* Buffer overflow or wrong encoding? */
  2137.                 di += wc;
  2138.                 hs = 0;
  2139.         }
  2140.         if (hs != 0) di = 0;                                    /* Broken surrogate pair? */
  2141.         if (di == 0) fno->fname[di++] = '?';    /* Inaccessible object name? */
  2142.         fno->fname[di] = 0;                                             /* Terminate the name */
  2143.         fno->altname[0] = 0;                                    /* exFAT does not support SFN */
  2144.  
  2145.         fno->fattrib = dirb[XDIR_Attr];                 /* Attribute */
  2146.         fno->fsize = (fno->fattrib & AM_DIR) ? 0 : ld_qword(dirb + XDIR_FileSize);      /* Size */
  2147.         fno->ftime = ld_word(dirb + XDIR_ModTime + 0);  /* Time */
  2148.         fno->fdate = ld_word(dirb + XDIR_ModTime + 2);  /* Date */
  2149. }
  2150.  
  2151. #endif  /* FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 */
  2152.  
  2153.  
  2154. /*-----------------------------------*/
  2155. /* exFAT: Get a directry entry block */
  2156. /*-----------------------------------*/
  2157.  
  2158. static FRESULT load_xdir (      /* FR_INT_ERR: invalid entry block */
  2159.         DIR* dp                                 /* Reading direcotry object pointing top of the entry block to load */
  2160. )
  2161. {
  2162.         FRESULT res;
  2163.         UINT i, sz_ent;
  2164.         BYTE* dirb = dp->obj.fs->dirbuf;        /* Pointer to the on-memory direcotry entry block 85+C0+C1s */
  2165.  
  2166.  
  2167.         /* Load file-directory entry */
  2168.         res = move_window(dp->obj.fs, dp->sect);
  2169.         if (res != FR_OK) return res;
  2170.         if (dp->dir[XDIR_Type] != ET_FILEDIR) return FR_INT_ERR;        /* Invalid order */
  2171.         mem_cpy(dirb + 0 * SZDIRE, dp->dir, SZDIRE);
  2172.         sz_ent = (dirb[XDIR_NumSec] + 1) * SZDIRE;
  2173.         if (sz_ent < 3 * SZDIRE || sz_ent > 19 * SZDIRE) return FR_INT_ERR;
  2174.  
  2175.         /* Load stream-extension entry */
  2176.         res = dir_next(dp, 0);
  2177.         if (res == FR_NO_FILE) res = FR_INT_ERR;        /* It cannot be */
  2178.         if (res != FR_OK) return res;
  2179.         res = move_window(dp->obj.fs, dp->sect);
  2180.         if (res != FR_OK) return res;
  2181.         if (dp->dir[XDIR_Type] != ET_STREAM) return FR_INT_ERR; /* Invalid order */
  2182.         mem_cpy(dirb + 1 * SZDIRE, dp->dir, SZDIRE);
  2183.         if (MAXDIRB(dirb[XDIR_NumName]) > sz_ent) return FR_INT_ERR;
  2184.  
  2185.         /* Load file-name entries */
  2186.         i = 2 * SZDIRE; /* Name offset to load */
  2187.         do {
  2188.                 res = dir_next(dp, 0);
  2189.                 if (res == FR_NO_FILE) res = FR_INT_ERR;        /* It cannot be */
  2190.                 if (res != FR_OK) return res;
  2191.                 res = move_window(dp->obj.fs, dp->sect);
  2192.                 if (res != FR_OK) return res;
  2193.                 if (dp->dir[XDIR_Type] != ET_FILENAME) return FR_INT_ERR;       /* Invalid order */
  2194.                 if (i < MAXDIRB(FF_MAX_LFN)) mem_cpy(dirb + i, dp->dir, SZDIRE);
  2195.         } while ((i += SZDIRE) < sz_ent);
  2196.  
  2197.         /* Sanity check (do it for only accessible object) */
  2198.         if (i <= MAXDIRB(FF_MAX_LFN)) {
  2199.                 if (xdir_sum(dirb) != ld_word(dirb + XDIR_SetSum)) return FR_INT_ERR;
  2200.         }
  2201.         return FR_OK;
  2202. }
  2203.  
  2204.  
  2205. /*------------------------------------------------------------------*/
  2206. /* exFAT: Initialize object allocation info with loaded entry block */
  2207. /*------------------------------------------------------------------*/
  2208.  
  2209. static void init_alloc_info (
  2210.         FATFS* fs,              /* Filesystem object */
  2211.         FFOBJID* obj    /* Object allocation information to be initialized */
  2212. )
  2213. {
  2214.         obj->sclust = ld_dword(fs->dirbuf + XDIR_FstClus);              /* Start cluster */
  2215.         obj->objsize = ld_qword(fs->dirbuf + XDIR_FileSize);    /* Size */
  2216.         obj->stat = fs->dirbuf[XDIR_GenFlags] & 2;                              /* Allocation status */
  2217.         obj->n_frag = 0;                                                                                /* No last fragment info */
  2218. }
  2219.  
  2220.  
  2221.  
  2222. #if !FF_FS_READONLY || FF_FS_RPATH != 0
  2223. /*------------------------------------------------*/
  2224. /* exFAT: Load the object's directory entry block */
  2225. /*------------------------------------------------*/
  2226.  
  2227. static FRESULT load_obj_xdir (
  2228.         DIR* dp,                        /* Blank directory object to be used to access containing direcotry */
  2229.         const FFOBJID* obj      /* Object with its containing directory information */
  2230. )
  2231. {
  2232.         FRESULT res;
  2233.  
  2234.         /* Open object containing directory */
  2235.         dp->obj.fs = obj->fs;
  2236.         dp->obj.sclust = obj->c_scl;
  2237.         dp->obj.stat = (BYTE)obj->c_size;
  2238.         dp->obj.objsize = obj->c_size & 0xFFFFFF00;
  2239.         dp->obj.n_frag = 0;
  2240.         dp->blk_ofs = obj->c_ofs;
  2241.  
  2242.         res = dir_sdi(dp, dp->blk_ofs); /* Goto object's entry block */
  2243.         if (res == FR_OK) {
  2244.                 res = load_xdir(dp);            /* Load the object's entry block */
  2245.         }
  2246.         return res;
  2247. }
  2248. #endif
  2249.  
  2250.  
  2251. #if !FF_FS_READONLY
  2252. /*----------------------------------------*/
  2253. /* exFAT: Store the directory entry block */
  2254. /*----------------------------------------*/
  2255.  
  2256. static FRESULT store_xdir (
  2257.         DIR* dp                         /* Pointer to the direcotry object */
  2258. )
  2259. {
  2260.         FRESULT res;
  2261.         UINT nent;
  2262.         BYTE* dirb = dp->obj.fs->dirbuf;        /* Pointer to the direcotry entry block 85+C0+C1s */
  2263.  
  2264.         /* Create set sum */
  2265.         st_word(dirb + XDIR_SetSum, xdir_sum(dirb));
  2266.         nent = dirb[XDIR_NumSec] + 1;
  2267.  
  2268.         /* Store the direcotry entry block to the directory */
  2269.         res = dir_sdi(dp, dp->blk_ofs);
  2270.         while (res == FR_OK) {
  2271.                 res = move_window(dp->obj.fs, dp->sect);
  2272.                 if (res != FR_OK) break;
  2273.                 mem_cpy(dp->dir, dirb, SZDIRE);
  2274.                 dp->obj.fs->wflag = 1;
  2275.                 if (--nent == 0) break;
  2276.                 dirb += SZDIRE;
  2277.                 res = dir_next(dp, 0);
  2278.         }
  2279.         return (res == FR_OK || res == FR_DISK_ERR) ? res : FR_INT_ERR;
  2280. }
  2281.  
  2282.  
  2283.  
  2284. /*-------------------------------------------*/
  2285. /* exFAT: Create a new directory enrty block */
  2286. /*-------------------------------------------*/
  2287.  
  2288. static void create_xdir (
  2289.         BYTE* dirb,                     /* Pointer to the direcotry entry block buffer */
  2290.         const WCHAR* lfn        /* Pointer to the object name */
  2291. )
  2292. {
  2293.         UINT i;
  2294.         BYTE nc1, nlen;
  2295.         WCHAR wc;
  2296.  
  2297.  
  2298.         /* Create file-directory and stream-extension entry */
  2299.         mem_set(dirb, 0, 2 * SZDIRE);
  2300.         dirb[0 * SZDIRE + XDIR_Type] = ET_FILEDIR;
  2301.         dirb[1 * SZDIRE + XDIR_Type] = ET_STREAM;
  2302.  
  2303.         /* Create file-name entries */
  2304.         i = SZDIRE * 2; /* Top of file_name entries */
  2305.         nlen = nc1 = 0; wc = 1;
  2306.         do {
  2307.                 dirb[i++] = ET_FILENAME; dirb[i++] = 0;
  2308.                 do {    /* Fill name field */
  2309.                         if (wc != 0 && (wc = lfn[nlen]) != 0) nlen++;   /* Get a character if exist */
  2310.                         st_word(dirb + i, wc);          /* Store it */
  2311.                         i += 2;
  2312.                 } while (i % SZDIRE != 0);
  2313.                 nc1++;
  2314.         } while (lfn[nlen]);    /* Fill next entry if any char follows */
  2315.  
  2316.         dirb[XDIR_NumName] = nlen;              /* Set name length */
  2317.         dirb[XDIR_NumSec] = 1 + nc1;    /* Set secondary count (C0 + C1s) */
  2318.         st_word(dirb + XDIR_NameHash, xname_sum(lfn));  /* Set name hash */
  2319. }
  2320.  
  2321. #endif  /* !FF_FS_READONLY */
  2322. #endif  /* FF_FS_EXFAT */
  2323.  
  2324.  
  2325.  
  2326. #if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 || FF_USE_LABEL || FF_FS_EXFAT
  2327. /*-----------------------------------------------------------------------*/
  2328. /* Read an object from the directory                                     */
  2329. /*-----------------------------------------------------------------------*/
  2330.  
  2331. #define DIR_READ_FILE(dp) dir_read(dp, 0)
  2332. #define DIR_READ_LABEL(dp) dir_read(dp, 1)
  2333.  
  2334. static FRESULT dir_read (
  2335.         DIR* dp,                /* Pointer to the directory object */
  2336.         int vol                 /* Filtered by 0:file/directory or 1:volume label */
  2337. )
  2338. {
  2339.         FRESULT res = FR_NO_FILE;
  2340.         FATFS *fs = dp->obj.fs;
  2341.         BYTE attr, b;
  2342. #if FF_USE_LFN
  2343.         BYTE ord = 0xFF, sum = 0xFF;
  2344. #endif
  2345.  
  2346.         while (dp->sect) {
  2347.                 res = move_window(fs, dp->sect);
  2348.                 if (res != FR_OK) break;
  2349.                 b = dp->dir[DIR_Name];  /* Test for the entry type */
  2350.                 if (b == 0) {
  2351.                         res = FR_NO_FILE; break; /* Reached to end of the directory */
  2352.                 }
  2353. #if FF_FS_EXFAT
  2354.                 if (fs->fs_type == FS_EXFAT) {  /* On the exFAT volume */
  2355.                         if (FF_USE_LABEL && vol) {
  2356.                                 if (b == ET_VLABEL) break;      /* Volume label entry? */
  2357.                         } else {
  2358.                                 if (b == ET_FILEDIR) {          /* Start of the file entry block? */
  2359.                                         dp->blk_ofs = dp->dptr; /* Get location of the block */
  2360.                                         res = load_xdir(dp);    /* Load the entry block */
  2361.                                         if (res == FR_OK) {
  2362.                                                 dp->obj.attr = fs->dirbuf[XDIR_Attr] & AM_MASK; /* Get attribute */
  2363.                                         }
  2364.                                         break;
  2365.                                 }
  2366.                         }
  2367.                 } else
  2368. #endif
  2369.                 {       /* On the FAT/FAT32 volume */
  2370.                         dp->obj.attr = attr = dp->dir[DIR_Attr] & AM_MASK;      /* Get attribute */
  2371. #if FF_USE_LFN          /* LFN configuration */
  2372.                         if (b == DDEM || b == '.' || (int)((attr & ~AM_ARC) == AM_VOL) != vol) {        /* An entry without valid data */
  2373.                                 ord = 0xFF;
  2374.                         } else {
  2375.                                 if (attr == AM_LFN) {                   /* An LFN entry is found */
  2376.                                         if (b & LLEF) {                 /* Is it start of an LFN sequence? */
  2377.                                                 sum = dp->dir[LDIR_Chksum];
  2378.                                                 b &= (BYTE)~LLEF; ord = b;
  2379.                                                 dp->blk_ofs = dp->dptr;
  2380.                                         }
  2381.                                         /* Check LFN validity and capture it */
  2382.                                         ord = (b == ord && sum == dp->dir[LDIR_Chksum] && pick_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF;
  2383.                                 } else {                                        /* An SFN entry is found */
  2384.                                         if (ord != 0 || sum != sum_sfn(dp->dir)) {      /* Is there a valid LFN? */
  2385.                                                 dp->blk_ofs = 0xFFFFFFFF;                       /* It has no LFN. */
  2386.                                         }
  2387.                                         break;
  2388.                                 }
  2389.                         }
  2390. #else           /* Non LFN configuration */
  2391.                         if (b != DDEM && b != '.' && attr != AM_LFN && (int)((attr & ~AM_ARC) == AM_VOL) == vol) {      /* Is it a valid entry? */
  2392.                                 break;
  2393.                         }
  2394. #endif
  2395.                 }
  2396.                 res = dir_next(dp, 0);          /* Next entry */
  2397.                 if (res != FR_OK) break;
  2398.         }
  2399.  
  2400.         if (res != FR_OK) dp->sect = 0;         /* Terminate the read operation on error or EOT */
  2401.         return res;
  2402. }
  2403.  
  2404. #endif  /* FF_FS_MINIMIZE <= 1 || FF_USE_LABEL || FF_FS_RPATH >= 2 */
  2405.  
  2406.  
  2407.  
  2408. /*-----------------------------------------------------------------------*/
  2409. /* Directory handling - Find an object in the directory                  */
  2410. /*-----------------------------------------------------------------------*/
  2411.  
  2412. static FRESULT dir_find (       /* FR_OK(0):succeeded, !=0:error */
  2413.         DIR* dp                                 /* Pointer to the directory object with the file name */
  2414. )
  2415. {
  2416.         FRESULT res;
  2417.         FATFS *fs = dp->obj.fs;
  2418.         BYTE c;
  2419. #if FF_USE_LFN
  2420.         BYTE a, ord, sum;
  2421. #endif
  2422.  
  2423.         res = dir_sdi(dp, 0);                   /* Rewind directory object */
  2424.         if (res != FR_OK) return res;
  2425. #if FF_FS_EXFAT
  2426.         if (fs->fs_type == FS_EXFAT) {  /* On the exFAT volume */
  2427.                 BYTE nc;
  2428.                 UINT di, ni;
  2429.                 WORD hash = xname_sum(fs->lfnbuf);              /* Hash value of the name to find */
  2430.  
  2431.                 while ((res = DIR_READ_FILE(dp)) == FR_OK) {    /* Read an item */
  2432. #if FF_MAX_LFN < 255
  2433.                         if (fs->dirbuf[XDIR_NumName] > FF_MAX_LFN) continue;                    /* Skip comparison if inaccessible object name */
  2434. #endif
  2435.                         if (ld_word(fs->dirbuf + XDIR_NameHash) != hash) continue;      /* Skip comparison if hash mismatched */
  2436.                         for (nc = fs->dirbuf[XDIR_NumName], di = SZDIRE * 2, ni = 0; nc; nc--, di += 2, ni++) { /* Compare the name */
  2437.                                 if ((di % SZDIRE) == 0) di += 2;
  2438.                                 if (ff_wtoupper(ld_word(fs->dirbuf + di)) != ff_wtoupper(fs->lfnbuf[ni])) break;
  2439.                         }
  2440.                         if (nc == 0 && !fs->lfnbuf[ni]) break;  /* Name matched? */
  2441.                 }
  2442.                 return res;
  2443.         }
  2444. #endif
  2445.         /* On the FAT/FAT32 volume */
  2446. #if FF_USE_LFN
  2447.         ord = sum = 0xFF; dp->blk_ofs = 0xFFFFFFFF;     /* Reset LFN sequence */
  2448. #endif
  2449.         do {
  2450.                 res = move_window(fs, dp->sect);
  2451.                 if (res != FR_OK) break;
  2452.                 c = dp->dir[DIR_Name];
  2453.                 if (c == 0) { res = FR_NO_FILE; break; }        /* Reached to end of table */
  2454. #if FF_USE_LFN          /* LFN configuration */
  2455.                 dp->obj.attr = a = dp->dir[DIR_Attr] & AM_MASK;
  2456.                 if (c == DDEM || ((a & AM_VOL) && a != AM_LFN)) {       /* An entry without valid data */
  2457.                         ord = 0xFF; dp->blk_ofs = 0xFFFFFFFF;   /* Reset LFN sequence */
  2458.                 } else {
  2459.                         if (a == AM_LFN) {                      /* An LFN entry is found */
  2460.                                 if (!(dp->fn[NSFLAG] & NS_NOLFN)) {
  2461.                                         if (c & LLEF) {         /* Is it start of LFN sequence? */
  2462.                                                 sum = dp->dir[LDIR_Chksum];
  2463.                                                 c &= (BYTE)~LLEF; ord = c;      /* LFN start order */
  2464.                                                 dp->blk_ofs = dp->dptr; /* Start offset of LFN */
  2465.                                         }
  2466.                                         /* Check validity of the LFN entry and compare it with given name */
  2467.                                         ord = (c == ord && sum == dp->dir[LDIR_Chksum] && cmp_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF;
  2468.                                 }
  2469.                         } else {                                        /* An SFN entry is found */
  2470.                                 if (ord == 0 && sum == sum_sfn(dp->dir)) break; /* LFN matched? */
  2471.                                 if (!(dp->fn[NSFLAG] & NS_LOSS) && !mem_cmp(dp->dir, dp->fn, 11)) break;        /* SFN matched? */
  2472.                                 ord = 0xFF; dp->blk_ofs = 0xFFFFFFFF;   /* Reset LFN sequence */
  2473.                         }
  2474.                 }
  2475. #else           /* Non LFN configuration */
  2476.                 dp->obj.attr = dp->dir[DIR_Attr] & AM_MASK;
  2477.                 if (!(dp->dir[DIR_Attr] & AM_VOL) && !mem_cmp(dp->dir, dp->fn, 11)) break;      /* Is it a valid entry? */
  2478. #endif
  2479.                 res = dir_next(dp, 0);  /* Next entry */
  2480.         } while (res == FR_OK);
  2481.  
  2482.         return res;
  2483. }
  2484.  
  2485.  
  2486.  
  2487.  
  2488. #if !FF_FS_READONLY
  2489. /*-----------------------------------------------------------------------*/
  2490. /* Register an object to the directory                                   */
  2491. /*-----------------------------------------------------------------------*/
  2492.  
  2493. static FRESULT dir_register (   /* FR_OK:succeeded, FR_DENIED:no free entry or too many SFN collision, FR_DISK_ERR:disk error */
  2494.         DIR* dp                                         /* Target directory with object name to be created */
  2495. )
  2496. {
  2497.         FRESULT res;
  2498.         FATFS *fs = dp->obj.fs;
  2499. #if FF_USE_LFN          /* LFN configuration */
  2500.         UINT n, nlen, nent;
  2501.         BYTE sn[12], sum;
  2502.  
  2503.  
  2504.         if (dp->fn[NSFLAG] & (NS_DOT | NS_NONAME)) return FR_INVALID_NAME;      /* Check name validity */
  2505.         for (nlen = 0; fs->lfnbuf[nlen]; nlen++) ;      /* Get lfn length */
  2506.  
  2507. #if FF_FS_EXFAT
  2508.         if (fs->fs_type == FS_EXFAT) {  /* On the exFAT volume */
  2509.                 nent = (nlen + 14) / 15 + 2;    /* Number of entries to allocate (85+C0+C1s) */
  2510.                 res = dir_alloc(dp, nent);              /* Allocate directory entries */
  2511.                 if (res != FR_OK) return res;
  2512.                 dp->blk_ofs = dp->dptr - SZDIRE * (nent - 1);   /* Set the allocated entry block offset */
  2513.  
  2514.                 if (dp->obj.stat & 4) {                 /* Has the directory been stretched by new allocation? */
  2515.                         dp->obj.stat &= ~4;
  2516.                         res = fill_first_frag(&dp->obj);        /* Fill the first fragment on the FAT if needed */
  2517.                         if (res != FR_OK) return res;
  2518.                         res = fill_last_frag(&dp->obj, dp->clust, 0xFFFFFFFF);  /* Fill the last fragment on the FAT if needed */
  2519.                         if (res != FR_OK) return res;
  2520.                         if (dp->obj.sclust != 0) {              /* Is it a sub-directory? */
  2521.                                 DIR dj;
  2522.  
  2523.                                 res = load_obj_xdir(&dj, &dp->obj);     /* Load the object status */
  2524.                                 if (res != FR_OK) return res;
  2525.                                 dp->obj.objsize += (DWORD)fs->csize * SS(fs);                   /* Increase the directory size by cluster size */
  2526.                                 st_qword(fs->dirbuf + XDIR_FileSize, dp->obj.objsize);  /* Update the allocation status */
  2527.                                 st_qword(fs->dirbuf + XDIR_ValidFileSize, dp->obj.objsize);
  2528.                                 fs->dirbuf[XDIR_GenFlags] = dp->obj.stat | 1;
  2529.                                 res = store_xdir(&dj);                          /* Store the object status */
  2530.                                 if (res != FR_OK) return res;
  2531.                         }
  2532.                 }
  2533.  
  2534.                 create_xdir(fs->dirbuf, fs->lfnbuf);    /* Create on-memory directory block to be written later */
  2535.                 return FR_OK;
  2536.         }
  2537. #endif
  2538.         /* On the FAT/FAT32 volume */
  2539.         mem_cpy(sn, dp->fn, 12);
  2540.         if (sn[NSFLAG] & NS_LOSS) {                     /* When LFN is out of 8.3 format, generate a numbered name */
  2541.                 dp->fn[NSFLAG] = NS_NOLFN;              /* Find only SFN */
  2542.                 for (n = 1; n < 100; n++) {
  2543.                         gen_numname(dp->fn, sn, fs->lfnbuf, n); /* Generate a numbered name */
  2544.                         res = dir_find(dp);                             /* Check if the name collides with existing SFN */
  2545.                         if (res != FR_OK) break;
  2546.                 }
  2547.                 if (n == 100) return FR_DENIED;         /* Abort if too many collisions */
  2548.                 if (res != FR_NO_FILE) return res;      /* Abort if the result is other than 'not collided' */
  2549.                 dp->fn[NSFLAG] = sn[NSFLAG];
  2550.         }
  2551.  
  2552.         /* Create an SFN with/without LFNs. */
  2553.         nent = (sn[NSFLAG] & NS_LFN) ? (nlen + 12) / 13 + 1 : 1;        /* Number of entries to allocate */
  2554.         res = dir_alloc(dp, nent);              /* Allocate entries */
  2555.         if (res == FR_OK && --nent) {   /* Set LFN entry if needed */
  2556.                 res = dir_sdi(dp, dp->dptr - nent * SZDIRE);
  2557.                 if (res == FR_OK) {
  2558.                         sum = sum_sfn(dp->fn);  /* Checksum value of the SFN tied to the LFN */
  2559.                         do {                                    /* Store LFN entries in bottom first */
  2560.                                 res = move_window(fs, dp->sect);
  2561.                                 if (res != FR_OK) break;
  2562.                                 put_lfn(fs->lfnbuf, dp->dir, (BYTE)nent, sum);
  2563.                                 fs->wflag = 1;
  2564.                                 res = dir_next(dp, 0);  /* Next entry */
  2565.                         } while (res == FR_OK && --nent);
  2566.                 }
  2567.         }
  2568.  
  2569. #else   /* Non LFN configuration */
  2570.         res = dir_alloc(dp, 1);         /* Allocate an entry for SFN */
  2571.  
  2572. #endif
  2573.  
  2574.         /* Set SFN entry */
  2575.         if (res == FR_OK) {
  2576.                 res = move_window(fs, dp->sect);
  2577.                 if (res == FR_OK) {
  2578.                         mem_set(dp->dir, 0, SZDIRE);    /* Clean the entry */
  2579.                         mem_cpy(dp->dir + DIR_Name, dp->fn, 11);        /* Put SFN */
  2580. #if FF_USE_LFN
  2581.                         dp->dir[DIR_NTres] = dp->fn[NSFLAG] & (NS_BODY | NS_EXT);       /* Put NT flag */
  2582. #endif
  2583.                         fs->wflag = 1;
  2584.                 }
  2585.         }
  2586.  
  2587.         return res;
  2588. }
  2589.  
  2590. #endif /* !FF_FS_READONLY */
  2591.  
  2592.  
  2593.  
  2594. #if !FF_FS_READONLY && FF_FS_MINIMIZE == 0
  2595. /*-----------------------------------------------------------------------*/
  2596. /* Remove an object from the directory                                   */
  2597. /*-----------------------------------------------------------------------*/
  2598.  
  2599. static FRESULT dir_remove (     /* FR_OK:Succeeded, FR_DISK_ERR:A disk error */
  2600.         DIR* dp                                 /* Directory object pointing the entry to be removed */
  2601. )
  2602. {
  2603.         FRESULT res;
  2604.         FATFS *fs = dp->obj.fs;
  2605. #if FF_USE_LFN          /* LFN configuration */
  2606.         DWORD last = dp->dptr;
  2607.  
  2608.         res = (dp->blk_ofs == 0xFFFFFFFF) ? FR_OK : dir_sdi(dp, dp->blk_ofs);   /* Goto top of the entry block if LFN is exist */
  2609.         if (res == FR_OK) {
  2610.                 do {
  2611.                         res = move_window(fs, dp->sect);
  2612.                         if (res != FR_OK) break;
  2613.                         if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) {   /* On the exFAT volume */
  2614.                                 dp->dir[XDIR_Type] &= 0x7F;     /* Clear the entry InUse flag. */
  2615.                         } else {                                                                        /* On the FAT/FAT32 volume */
  2616.                                 dp->dir[DIR_Name] = DDEM;       /* Mark the entry 'deleted'. */
  2617.                         }
  2618.                         fs->wflag = 1;
  2619.                         if (dp->dptr >= last) break;    /* If reached last entry then all entries of the object has been deleted. */
  2620.                         res = dir_next(dp, 0);  /* Next entry */
  2621.                 } while (res == FR_OK);
  2622.                 if (res == FR_NO_FILE) res = FR_INT_ERR;
  2623.         }
  2624. #else                   /* Non LFN configuration */
  2625.  
  2626.         res = move_window(fs, dp->sect);
  2627.         if (res == FR_OK) {
  2628.                 dp->dir[DIR_Name] = DDEM;       /* Mark the entry 'deleted'.*/
  2629.                 fs->wflag = 1;
  2630.         }
  2631. #endif
  2632.  
  2633.         return res;
  2634. }
  2635.  
  2636. #endif /* !FF_FS_READONLY && FF_FS_MINIMIZE == 0 */
  2637.  
  2638.  
  2639.  
  2640. #if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2
  2641. /*-----------------------------------------------------------------------*/
  2642. /* Get file information from directory entry                             */
  2643. /*-----------------------------------------------------------------------*/
  2644.  
  2645. static void get_fileinfo (
  2646.         DIR* dp,                        /* Pointer to the directory object */
  2647.         FILINFO* fno            /* Pointer to the file information to be filled */
  2648. )
  2649. {
  2650.         UINT si, di;
  2651. #if FF_USE_LFN
  2652.         WCHAR wc, hs;
  2653.         FATFS *fs = dp->obj.fs;
  2654. #else
  2655.         TCHAR c;
  2656. #endif
  2657.  
  2658.  
  2659.         fno->fname[0] = 0;                      /* Invaidate file info */
  2660.         if (dp->sect == 0) return;      /* Exit if read pointer has reached end of directory */
  2661.  
  2662. #if FF_USE_LFN          /* LFN configuration */
  2663. #if FF_FS_EXFAT
  2664.         if (fs->fs_type == FS_EXFAT) {  /* On the exFAT volume */
  2665.                 get_xfileinfo(fs->dirbuf, fno);
  2666.                 return;
  2667.         } else
  2668. #endif
  2669.         {       /* On the FAT/FAT32 volume */
  2670.                 if (dp->blk_ofs != 0xFFFFFFFF) {        /* Get LFN if available */
  2671.                         si = di = hs = 0;
  2672.                         while (fs->lfnbuf[si] != 0) {
  2673.                                 wc = fs->lfnbuf[si++];          /* Get an LFN character (UTF-16) */
  2674.                                 if (hs == 0 && IsSurrogate(wc)) {       /* Is it a surrogate? */
  2675.                                         hs = wc; continue;              /* Get low surrogate */
  2676.                                 }
  2677.                                 wc = put_utf((DWORD)hs << 16 | wc, &fno->fname[di], FF_LFN_BUF - di);   /* Store it in UTF-16 or UTF-8 encoding */
  2678.                                 if (wc == 0) { di = 0; break; } /* Invalid char or buffer overflow? */
  2679.                                 di += wc;
  2680.                                 hs = 0;
  2681.                         }
  2682.                         if (hs != 0) di = 0;    /* Broken surrogate pair? */
  2683.                         fno->fname[di] = 0;             /* Terminate the LFN (null string means LFN is invalid) */
  2684.                 }
  2685.         }
  2686.  
  2687.         si = di = 0;
  2688.         while (si < 11) {               /* Get SFN from SFN entry */
  2689.                 wc = dp->dir[si++];                     /* Get a char */
  2690.                 if (wc == ' ') continue;        /* Skip padding spaces */
  2691.                 if (wc == RDDEM) wc = DDEM;     /* Restore replaced DDEM character */
  2692.                 if (si == 9 && di < FF_SFN_BUF) fno->altname[di++] = '.';       /* Insert a . if extension is exist */
  2693. #if FF_LFN_UNICODE >= 1 /* Unicode output */
  2694.                 if (dbc_1st((BYTE)wc) && si != 8 && si != 11 && dbc_2nd(dp->dir[si])) { /* Make a DBC if needed */
  2695.                         wc = wc << 8 | dp->dir[si++];
  2696.                 }
  2697.                 wc = ff_oem2uni(wc, CODEPAGE);          /* ANSI/OEM -> Unicode */
  2698.                 if (wc == 0) { di = 0; break; }         /* Wrong char in the current code page? */
  2699.                 wc = put_utf(wc, &fno->altname[di], FF_SFN_BUF - di);   /* Store it in Unicode */
  2700.                 if (wc == 0) { di = 0; break; }         /* Buffer overflow? */
  2701.                 di += wc;
  2702. #else                                   /* ANSI/OEM output */
  2703.                 fno->altname[di++] = (TCHAR)wc; /* Store it without any conversion */
  2704. #endif
  2705.         }
  2706.         fno->altname[di] = 0;   /* Terminate the SFN  (null string means SFN is invalid) */
  2707.  
  2708.         if (fno->fname[0] == 0) {       /* If LFN is invalid, altname[] needs to be copied to fname[] */
  2709.                 if (di == 0) {  /* If LFN and SFN both are invalid, this object is inaccesible */
  2710.                         fno->fname[di++] = '?';
  2711.                 } else {
  2712.                         for (si = di = 0; fno->altname[si]; si++, di++) {       /* Copy altname[] to fname[] with case information */
  2713.                                 wc = (WCHAR)fno->altname[si];
  2714.                                 if (IsUpper(wc) && (dp->dir[DIR_NTres] & ((si >= 9) ? NS_EXT : NS_BODY))) wc += 0x20;
  2715.                                 fno->fname[di] = (TCHAR)wc;
  2716.                         }
  2717.                 }
  2718.                 fno->fname[di] = 0;     /* Terminate the LFN */
  2719.                 if (!dp->dir[DIR_NTres]) fno->altname[0] = 0;   /* Altname is not needed if neither LFN nor case info is exist. */
  2720.         }
  2721.  
  2722. #else   /* Non-LFN configuration */
  2723.         si = di = 0;
  2724.         while (si < 11) {               /* Copy name body and extension */
  2725.                 c = (TCHAR)dp->dir[si++];
  2726.                 if (c == ' ') continue;         /* Skip padding spaces */
  2727.                 if (c == RDDEM) c = DDEM;       /* Restore replaced DDEM character */
  2728.                 if (si == 9) fno->fname[di++] = '.';/* Insert a . if extension is exist */
  2729.                 fno->fname[di++] = c;
  2730.         }
  2731.         fno->fname[di] = 0;
  2732. #endif
  2733.  
  2734.         fno->fattrib = dp->dir[DIR_Attr];                                       /* Attribute */
  2735.         fno->fsize = ld_dword(dp->dir + DIR_FileSize);          /* Size */
  2736.         fno->ftime = ld_word(dp->dir + DIR_ModTime + 0);        /* Time */
  2737.         fno->fdate = ld_word(dp->dir + DIR_ModTime + 2);        /* Date */
  2738. }
  2739.  
  2740. #endif /* FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 */
  2741.  
  2742.  
  2743.  
  2744. #if FF_USE_FIND && FF_FS_MINIMIZE <= 1
  2745. /*-----------------------------------------------------------------------*/
  2746. /* Pattern matching                                                      */
  2747. /*-----------------------------------------------------------------------*/
  2748.  
  2749. static DWORD get_achar (        /* Get a character and advances ptr */
  2750.         const TCHAR** ptr               /* Pointer to pointer to the ANSI/OEM or Unicode string */
  2751. )
  2752. {
  2753.         DWORD chr;
  2754.  
  2755.  
  2756. #if FF_USE_LFN && FF_LFN_UNICODE >= 1   /* Unicode input */
  2757.         chr = tchar2uni(ptr);
  2758.         if (chr == 0xFFFFFFFF) chr = 0;         /* Wrong UTF encoding is recognized as end of the string */
  2759.         chr = ff_wtoupper(chr);
  2760.  
  2761. #else                                                                   /* ANSI/OEM input */
  2762.         chr = (BYTE)*(*ptr)++;                          /* Get a byte */
  2763.         if (IsLower(chr)) chr -= 0x20;          /* To upper ASCII char */
  2764. #if FF_CODE_PAGE == 0
  2765.         if (ExCvt && chr >= 0x80) chr = ExCvt[chr - 0x80];      /* To upper SBCS extended char */
  2766. #elif FF_CODE_PAGE < 900
  2767.         if (chr >= 0x80) chr = ExCvt[chr - 0x80];       /* To upper SBCS extended char */
  2768. #endif
  2769. #if FF_CODE_PAGE == 0 || FF_CODE_PAGE >= 900
  2770.         if (dbc_1st((BYTE)chr)) {       /* Get DBC 2nd byte if needed */
  2771.                 chr = dbc_2nd((BYTE)**ptr) ? chr << 8 | (BYTE)*(*ptr)++ : 0;
  2772.         }
  2773. #endif
  2774.  
  2775. #endif
  2776.         return chr;
  2777. }
  2778.  
  2779.  
  2780. static int pattern_matching (   /* 0:not matched, 1:matched */
  2781.         const TCHAR* pat,       /* Matching pattern */
  2782.         const TCHAR* nam,       /* String to be tested */
  2783.         int skip,                       /* Number of pre-skip chars (number of ?s) */
  2784.         int inf                         /* Infinite search (* specified) */
  2785. )
  2786. {
  2787.         const TCHAR *pp, *np;
  2788.         DWORD pc, nc;
  2789.         int nm, nx;
  2790.  
  2791.  
  2792.         while (skip--) {                                /* Pre-skip name chars */
  2793.                 if (!get_achar(&nam)) return 0; /* Branch mismatched if less name chars */
  2794.         }
  2795.         if (*pat == 0 && inf) return 1; /* (short circuit) */
  2796.  
  2797.         do {
  2798.                 pp = pat; np = nam;                     /* Top of pattern and name to match */
  2799.                 for (;;) {
  2800.                         if (*pp == '?' || *pp == '*') { /* Wildcard? */
  2801.                                 nm = nx = 0;
  2802.                                 do {                            /* Analyze the wildcard block */
  2803.                                         if (*pp++ == '?') nm++; else nx = 1;
  2804.                                 } while (*pp == '?' || *pp == '*');
  2805.                                 if (pattern_matching(pp, np, nm, nx)) return 1; /* Test new branch (recurs upto number of wildcard blocks in the pattern) */
  2806.                                 nc = *np; break;        /* Branch mismatched */
  2807.                         }
  2808.                         pc = get_achar(&pp);    /* Get a pattern char */
  2809.                         nc = get_achar(&np);    /* Get a name char */
  2810.                         if (pc != nc) break;    /* Branch mismatched? */
  2811.                         if (pc == 0) return 1;  /* Branch matched? (matched at end of both strings) */
  2812.                 }
  2813.                 get_achar(&nam);                        /* nam++ */
  2814.         } while (inf && nc);                    /* Retry until end of name if infinite search is specified */
  2815.  
  2816.         return 0;
  2817. }
  2818.  
  2819. #endif /* FF_USE_FIND && FF_FS_MINIMIZE <= 1 */
  2820.  
  2821.  
  2822.  
  2823. /*-----------------------------------------------------------------------*/
  2824. /* Pick a top segment and create the object name in directory form       */
  2825. /*-----------------------------------------------------------------------*/
  2826.  
  2827. static FRESULT create_name (    /* FR_OK: successful, FR_INVALID_NAME: could not create */
  2828.         DIR* dp,                                        /* Pointer to the directory object */
  2829.         const TCHAR** path                      /* Pointer to pointer to the segment in the path string */
  2830. )
  2831. {
  2832. #if FF_USE_LFN          /* LFN configuration */
  2833.         BYTE b, cf;
  2834.         WCHAR wc, *lfn;
  2835.         DWORD uc;
  2836.         UINT i, ni, si, di;
  2837.         const TCHAR *p;
  2838.  
  2839.  
  2840.         /* Create LFN into LFN working buffer */
  2841.         p = *path; lfn = dp->obj.fs->lfnbuf; di = 0;
  2842.         for (;;) {
  2843.                 uc = tchar2uni(&p);                     /* Get a character */
  2844.                 if (uc == 0xFFFFFFFF) return FR_INVALID_NAME;           /* Invalid code or UTF decode error */
  2845.                 if (uc >= 0x10000) lfn[di++] = (WCHAR)(uc >> 16);       /* Store high surrogate if needed */
  2846.                 wc = (WCHAR)uc;
  2847.                 if (wc < ' ' || wc == '/' || wc == '\\') break; /* Break if end of the path or a separator is found */
  2848.                 if (wc < 0x80 && chk_chr("\"*:<>\?|\x7F", wc)) return FR_INVALID_NAME;  /* Reject illegal characters for LFN */
  2849.                 if (di >= FF_MAX_LFN) return FR_INVALID_NAME;   /* Reject too long name */
  2850.                 lfn[di++] = wc;                                 /* Store the Unicode character */
  2851.         }
  2852.         while (*p == '/' || *p == '\\') p++;    /* Skip duplicated separators if exist */
  2853.         *path = p;                                                      /* Return pointer to the next segment */
  2854.         cf = (wc < ' ') ? NS_LAST : 0;          /* Set last segment flag if end of the path */
  2855.  
  2856. #if FF_FS_RPATH != 0
  2857.         if ((di == 1 && lfn[di - 1] == '.') ||
  2858.                 (di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) {        /* Is this segment a dot name? */
  2859.                 lfn[di] = 0;
  2860.                 for (i = 0; i < 11; i++) {              /* Create dot name for SFN entry */
  2861.                         dp->fn[i] = (i < di) ? '.' : ' ';
  2862.                 }
  2863.                 dp->fn[i] = cf | NS_DOT;                /* This is a dot entry */
  2864.                 return FR_OK;
  2865.         }
  2866. #endif
  2867.         while (di) {                                            /* Snip off trailing spaces and dots if exist */
  2868.                 wc = lfn[di - 1];
  2869.                 if (wc != ' ' && wc != '.') break;
  2870.                 di--;
  2871.         }
  2872.         lfn[di] = 0;                                                    /* LFN is created into the working buffer */
  2873.         if (di == 0) return FR_INVALID_NAME;    /* Reject null name */
  2874.  
  2875.         /* Create SFN in directory form */
  2876.         for (si = 0; lfn[si] == ' '; si++) ;    /* Remove leading spaces */
  2877.         if (si > 0 || lfn[si] == '.') cf |= NS_LOSS | NS_LFN;   /* Is there any leading space or dot? */
  2878.         while (di > 0 && lfn[di - 1] != '.') di--;      /* Find last dot (di<=si: no extension) */
  2879.  
  2880.         mem_set(dp->fn, ' ', 11);
  2881.         i = b = 0; ni = 8;
  2882.         for (;;) {
  2883.                 wc = lfn[si++];                                 /* Get an LFN character */
  2884.                 if (wc == 0) break;                             /* Break on end of the LFN */
  2885.                 if (wc == ' ' || (wc == '.' && si != di)) {     /* Remove embedded spaces and dots */
  2886.                         cf |= NS_LOSS | NS_LFN;
  2887.                         continue;
  2888.                 }
  2889.  
  2890.                 if (i >= ni || si == di) {              /* End of field? */
  2891.                         if (ni == 11) {                         /* Name extension overflow? */
  2892.                                 cf |= NS_LOSS | NS_LFN;
  2893.                                 break;
  2894.                         }
  2895.                         if (si != di) cf |= NS_LOSS | NS_LFN;   /* Name body overflow? */
  2896.                         if (si > di) break;                                             /* No name extension? */
  2897.                         si = di; i = 8; ni = 11; b <<= 2;               /* Enter name extension */
  2898.                         continue;
  2899.                 }
  2900.  
  2901.                 if (wc >= 0x80) {       /* Is this a non-ASCII character? */
  2902.                         cf |= NS_LFN;   /* LFN entry needs to be created */
  2903. #if FF_CODE_PAGE == 0
  2904.                         if (ExCvt) {    /* At SBCS */
  2905.                                 wc = ff_uni2oem(wc, CODEPAGE);                  /* Unicode ==> ANSI/OEM code */
  2906.                                 if (wc & 0x80) wc = ExCvt[wc & 0x7F];   /* Convert extended character to upper (SBCS) */
  2907.                         } else {                /* At DBCS */
  2908.                                 wc = ff_uni2oem(ff_wtoupper(wc), CODEPAGE);     /* Unicode ==> Upper convert ==> ANSI/OEM code */
  2909.                         }
  2910. #elif FF_CODE_PAGE < 900        /* SBCS cfg */
  2911.                         wc = ff_uni2oem(wc, CODEPAGE);                  /* Unicode ==> ANSI/OEM code */
  2912.                         if (wc & 0x80) wc = ExCvt[wc & 0x7F];   /* Convert extended character to upper (SBCS) */
  2913. #else                                           /* DBCS cfg */
  2914.                         wc = ff_uni2oem(ff_wtoupper(wc), CODEPAGE);     /* Unicode ==> Upper convert ==> ANSI/OEM code */
  2915. #endif
  2916.                 }
  2917.  
  2918.                 if (wc >= 0x100) {                              /* Is this a DBC? */
  2919.                         if (i >= ni - 1) {                      /* Field overflow? */
  2920.                                 cf |= NS_LOSS | NS_LFN;
  2921.                                 i = ni; continue;               /* Next field */
  2922.                         }
  2923.                         dp->fn[i++] = (BYTE)(wc >> 8);  /* Put 1st byte */
  2924.                 } else {                                                /* SBC */
  2925.                         if (wc == 0 || chk_chr("+,;=[]", wc)) { /* Replace illegal characters for SFN if needed */
  2926.                                 wc = '_'; cf |= NS_LOSS | NS_LFN;/* Lossy conversion */
  2927.                         } else {
  2928.                                 if (IsUpper(wc)) {              /* ASCII upper case? */
  2929.                                         b |= 2;
  2930.                                 }
  2931.                                 if (IsLower(wc)) {              /* ASCII lower case? */
  2932.                                         b |= 1; wc -= 0x20;
  2933.                                 }
  2934.                         }
  2935.                 }
  2936.                 dp->fn[i++] = (BYTE)wc;
  2937.         }
  2938.  
  2939.         if (dp->fn[0] == DDEM) dp->fn[0] = RDDEM;       /* If the first character collides with DDEM, replace it with RDDEM */
  2940.  
  2941.         if (ni == 8) b <<= 2;                           /* Shift capital flags if no extension */
  2942.         if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03) cf |= NS_LFN;     /* LFN entry needs to be created if composite capitals */
  2943.         if (!(cf & NS_LFN)) {                           /* When LFN is in 8.3 format without extended character, NT flags are created */
  2944.                 if (b & 0x01) cf |= NS_EXT;             /* NT flag (Extension has small capital letters only) */
  2945.                 if (b & 0x04) cf |= NS_BODY;    /* NT flag (Body has small capital letters only) */
  2946.         }
  2947.  
  2948.         dp->fn[NSFLAG] = cf;    /* SFN is created into dp->fn[] */
  2949.  
  2950.         return FR_OK;
  2951.  
  2952.  
  2953. #else   /* FF_USE_LFN : Non-LFN configuration */
  2954.         BYTE c, d, *sfn;
  2955.         UINT ni, si, i;
  2956.         const char *p;
  2957.  
  2958.         /* Create file name in directory form */
  2959.         p = *path; sfn = dp->fn;
  2960.         mem_set(sfn, ' ', 11);
  2961.         si = i = 0; ni = 8;
  2962. #if FF_FS_RPATH != 0
  2963.         if (p[si] == '.') { /* Is this a dot entry? */
  2964.                 for (;;) {
  2965.                         c = (BYTE)p[si++];
  2966.                         if (c != '.' || si >= 3) break;
  2967.                         sfn[i++] = c;
  2968.                 }
  2969.                 if (c != '/' && c != '\\' && c > ' ') return FR_INVALID_NAME;
  2970.                 *path = p + si;                                                         /* Return pointer to the next segment */
  2971.                 sfn[NSFLAG] = (c <= ' ') ? NS_LAST | NS_DOT : NS_DOT;   /* Set last segment flag if end of the path */
  2972.                 return FR_OK;
  2973.         }
  2974. #endif
  2975.         for (;;) {
  2976.                 c = (BYTE)p[si++];                              /* Get a byte */
  2977.                 if (c <= ' ') break;                    /* Break if end of the path name */
  2978.                 if (c == '/' || c == '\\') {    /* Break if a separator is found */
  2979.                         while (p[si] == '/' || p[si] == '\\') si++;     /* Skip duplicated separator if exist */
  2980.                         break;
  2981.                 }
  2982.                 if (c == '.' || i >= ni) {              /* End of body or field overflow? */
  2983.                         if (ni == 11 || c != '.') return FR_INVALID_NAME;       /* Field overflow or invalid dot? */
  2984.                         i = 8; ni = 11;                         /* Enter file extension field */
  2985.                         continue;
  2986.                 }
  2987. #if FF_CODE_PAGE == 0
  2988.                 if (ExCvt && c >= 0x80) {               /* Is SBC extended character? */
  2989.                         c = ExCvt[c & 0x7F];            /* To upper SBC extended character */
  2990.                 }
  2991. #elif FF_CODE_PAGE < 900
  2992.                 if (c >= 0x80) {                                /* Is SBC extended character? */
  2993.                         c = ExCvt[c & 0x7F];            /* To upper SBC extended character */
  2994.                 }
  2995. #endif
  2996.                 if (dbc_1st(c)) {                               /* Check if it is a DBC 1st byte */
  2997.                         d = (BYTE)p[si++];                      /* Get 2nd byte */
  2998.                         if (!dbc_2nd(d) || i >= ni - 1) return FR_INVALID_NAME; /* Reject invalid DBC */
  2999.                         sfn[i++] = c;
  3000.                         sfn[i++] = d;
  3001.                 } else {                                                /* SBC */
  3002.                         if (chk_chr("\"*+,:;<=>\?[]|\x7F", c)) return FR_INVALID_NAME;  /* Reject illegal chrs for SFN */
  3003.                         if (IsLower(c)) c -= 0x20;      /* To upper */
  3004.                         sfn[i++] = c;
  3005.                 }
  3006.         }
  3007.         *path = p + si;                                         /* Return pointer to the next segment */
  3008.         if (i == 0) return FR_INVALID_NAME;     /* Reject nul string */
  3009.  
  3010.         if (sfn[0] == DDEM) sfn[0] = RDDEM;     /* If the first character collides with DDEM, replace it with RDDEM */
  3011.         sfn[NSFLAG] = (c <= ' ') ? NS_LAST : 0;         /* Set last segment flag if end of the path */
  3012.  
  3013.         return FR_OK;
  3014. #endif /* FF_USE_LFN */
  3015. }
  3016.  
  3017.  
  3018.  
  3019.  
  3020. /*-----------------------------------------------------------------------*/
  3021. /* Follow a file path                                                    */
  3022. /*-----------------------------------------------------------------------*/
  3023.  
  3024. static FRESULT follow_path (    /* FR_OK(0): successful, !=0: error code */
  3025.         DIR* dp,                                        /* Directory object to return last directory and found object */
  3026.         const TCHAR* path                       /* Full-path string to find a file or directory */
  3027. )
  3028. {
  3029.         FRESULT res;
  3030.         BYTE ns;
  3031.         FATFS *fs = dp->obj.fs;
  3032.  
  3033.  
  3034. #if FF_FS_RPATH != 0
  3035.         if (*path != '/' && *path != '\\') {    /* Without heading separator */
  3036.                 dp->obj.sclust = fs->cdir;                              /* Start from current directory */
  3037.         } else
  3038. #endif
  3039.         {                                                                               /* With heading separator */
  3040.                 while (*path == '/' || *path == '\\') path++;   /* Strip heading separator */
  3041.                 dp->obj.sclust = 0;                                     /* Start from root directory */
  3042.         }
  3043. #if FF_FS_EXFAT
  3044.         dp->obj.n_frag = 0;     /* Invalidate last fragment counter of the object */
  3045. #if FF_FS_RPATH != 0
  3046.         if (fs->fs_type == FS_EXFAT && dp->obj.sclust) {        /* exFAT: Retrieve the sub-directory's status */
  3047.                 DIR dj;
  3048.  
  3049.                 dp->obj.c_scl = fs->cdc_scl;
  3050.                 dp->obj.c_size = fs->cdc_size;
  3051.                 dp->obj.c_ofs = fs->cdc_ofs;
  3052.                 res = load_obj_xdir(&dj, &dp->obj);
  3053.                 if (res != FR_OK) return res;
  3054.                 dp->obj.objsize = ld_dword(fs->dirbuf + XDIR_FileSize);
  3055.                 dp->obj.stat = fs->dirbuf[XDIR_GenFlags] & 2;
  3056.         }
  3057. #endif
  3058. #endif
  3059.  
  3060.         if ((UINT)*path < ' ') {                                /* Null path name is the origin directory itself */
  3061.                 dp->fn[NSFLAG] = NS_NONAME;
  3062.                 res = dir_sdi(dp, 0);
  3063.  
  3064.         } else {                                                                /* Follow path */
  3065.                 for (;;) {
  3066.                         res = create_name(dp, &path);   /* Get a segment name of the path */
  3067.                         if (res != FR_OK) break;
  3068.                         res = dir_find(dp);                             /* Find an object with the segment name */
  3069.                         ns = dp->fn[NSFLAG];
  3070.                         if (res != FR_OK) {                             /* Failed to find the object */
  3071.                                 if (res == FR_NO_FILE) {        /* Object is not found */
  3072.                                         if (FF_FS_RPATH && (ns & NS_DOT)) {     /* If dot entry is not exist, stay there */
  3073.                                                 if (!(ns & NS_LAST)) continue;  /* Continue to follow if not last segment */
  3074.                                                 dp->fn[NSFLAG] = NS_NONAME;
  3075.                                                 res = FR_OK;
  3076.                                         } else {                                                        /* Could not find the object */
  3077.                                                 if (!(ns & NS_LAST)) res = FR_NO_PATH;  /* Adjust error code if not last segment */
  3078.                                         }
  3079.                                 }
  3080.                                 break;
  3081.                         }
  3082.                         if (ns & NS_LAST) break;                        /* Last segment matched. Function completed. */
  3083.                         /* Get into the sub-directory */
  3084.                         if (!(dp->obj.attr & AM_DIR)) {         /* It is not a sub-directory and cannot follow */
  3085.                                 res = FR_NO_PATH; break;
  3086.                         }
  3087. #if FF_FS_EXFAT
  3088.                         if (fs->fs_type == FS_EXFAT) {          /* Save containing directory information for next dir */
  3089.                                 dp->obj.c_scl = dp->obj.sclust;
  3090.                                 dp->obj.c_size = ((DWORD)dp->obj.objsize & 0xFFFFFF00) | dp->obj.stat;
  3091.                                 dp->obj.c_ofs = dp->blk_ofs;
  3092.                                 init_alloc_info(fs, &dp->obj);  /* Open next directory */
  3093.                         } else
  3094. #endif
  3095.                         {
  3096.                                 dp->obj.sclust = ld_clust(fs, fs->win + dp->dptr % SS(fs));     /* Open next directory */
  3097.                         }
  3098.                 }
  3099.         }
  3100.  
  3101.         return res;
  3102. }
  3103.  
  3104.  
  3105.  
  3106.  
  3107. /*-----------------------------------------------------------------------*/
  3108. /* Get logical drive number from path name                               */
  3109. /*-----------------------------------------------------------------------*/
  3110.  
  3111. static int get_ldnumber (       /* Returns logical drive number (-1:invalid drive number or null pointer) */
  3112.         const TCHAR** path              /* Pointer to pointer to the path name */
  3113. )
  3114. {
  3115.         const TCHAR *tp, *tt;
  3116.         TCHAR tc;
  3117.         int i, vol = -1;
  3118. #if FF_STR_VOLUME_ID            /* Find string volume ID */
  3119.         const char *sp;
  3120.         char c;
  3121. #endif
  3122.  
  3123.         tt = tp = *path;
  3124.         if (!tp) return vol;    /* Invalid path name? */
  3125.         do tc = *tt++; while ((UINT)tc >= (FF_USE_LFN ? ' ' : '!') && tc != ':');       /* Find a colon in the path */
  3126.  
  3127.         if (tc == ':') {        /* DOS/Windows style volume ID? */
  3128.                 i = FF_VOLUMES;
  3129.                 if (IsDigit(*tp) && tp + 2 == tt) {     /* Is there a numeric volume ID + colon? */
  3130.                         i = (int)*tp - '0';     /* Get the LD number */
  3131.                 }
  3132. #if FF_STR_VOLUME_ID == 1       /* Arbitrary string is enabled */
  3133.                 else {
  3134.                         i = 0;
  3135.                         do {
  3136.                                 sp = VolumeStr[i]; tp = *path;  /* This string volume ID and path name */
  3137.                                 do {    /* Compare the volume ID with path name */
  3138.                                         c = *sp++; tc = *tp++;
  3139.                                         if (IsLower(c)) c -= 0x20;
  3140.                                         if (IsLower(tc)) tc -= 0x20;
  3141.                                 } while (c && (TCHAR)c == tc);
  3142.                         } while ((c || tp != tt) && ++i < FF_VOLUMES);  /* Repeat for each id until pattern match */
  3143.                 }
  3144. #endif
  3145.                 if (i < FF_VOLUMES) {   /* If a volume ID is found, get the drive number and strip it */
  3146.                         vol = i;                /* Drive number */
  3147.                         *path = tt;             /* Snip the drive prefix off */
  3148.                 }
  3149.                 return vol;
  3150.         }
  3151. #if FF_STR_VOLUME_ID == 2               /* Unix style volume ID is enabled */
  3152.         if (*tp == '/') {
  3153.                 i = 0;
  3154.                 do {
  3155.                         sp = VolumeStr[i]; tp = *path;  /* This string volume ID and path name */
  3156.                         do {    /* Compare the volume ID with path name */
  3157.                                 c = *sp++; tc = *(++tp);
  3158.                                 if (IsLower(c)) c -= 0x20;
  3159.                                 if (IsLower(tc)) tc -= 0x20;
  3160.                         } while (c && (TCHAR)c == tc);
  3161.                 } while ((c || (tc != '/' && (UINT)tc >= (FF_USE_LFN ? ' ' : '!'))) && ++i < FF_VOLUMES);       /* Repeat for each ID until pattern match */
  3162.                 if (i < FF_VOLUMES) {   /* If a volume ID is found, get the drive number and strip it */
  3163.                         vol = i;                /* Drive number */
  3164.                         *path = tp;             /* Snip the drive prefix off */
  3165.                         return vol;
  3166.                 }
  3167.         }
  3168. #endif
  3169.         /* No drive prefix is found */
  3170. #if FF_FS_RPATH != 0
  3171.         vol = CurrVol;  /* Default drive is current drive */
  3172. #else
  3173.         vol = 0;                /* Default drive is 0 */
  3174. #endif
  3175.         return vol;             /* Return the default drive */
  3176. }
  3177.  
  3178.  
  3179.  
  3180.  
  3181. /*-----------------------------------------------------------------------*/
  3182. /* Load a sector and check if it is an FAT VBR                           */
  3183. /*-----------------------------------------------------------------------*/
  3184.  
  3185. static BYTE check_fs (  /* 0:FAT, 1:exFAT, 2:Valid BS but not FAT, 3:Not a BS, 4:Disk error */
  3186.         FATFS* fs,                      /* Filesystem object */
  3187.         DWORD sect                      /* Sector# (lba) to load and check if it is an FAT-VBR or not */
  3188. )
  3189. {
  3190.         fs->wflag = 0; fs->winsect = 0xFFFFFFFF;                /* Invaidate window */
  3191.         if (move_window(fs, sect) != FR_OK) return 4;   /* Load boot record */
  3192.  
  3193.         if (ld_word(fs->win + BS_55AA) != 0xAA55) return 3;     /* Check boot record signature (always here regardless of the sector size) */
  3194.  
  3195. #if FF_FS_EXFAT
  3196.         if (!mem_cmp(fs->win + BS_JmpBoot, "\xEB\x76\x90" "EXFAT   ", 11)) return 1;    /* Check if exFAT VBR */
  3197. #endif
  3198.         if (fs->win[BS_JmpBoot] == 0xE9 || fs->win[BS_JmpBoot] == 0xEB || fs->win[BS_JmpBoot] == 0xE8) {        /* Valid JumpBoot code? */
  3199.                 if (!mem_cmp(fs->win + BS_FilSysType, "FAT", 3)) return 0;              /* Is it an FAT VBR? */
  3200.                 if (!mem_cmp(fs->win + BS_FilSysType32, "FAT32", 5)) return 0;  /* Is it an FAT32 VBR? */
  3201.         }
  3202.         return 2;       /* Valid BS but not FAT */
  3203. }
  3204.  
  3205.  
  3206.  
  3207.  
  3208. /*-----------------------------------------------------------------------*/
  3209. /* Determine logical drive number and mount the volume if needed         */
  3210. /*-----------------------------------------------------------------------*/
  3211.  
  3212. static FRESULT find_volume (    /* FR_OK(0): successful, !=0: an error occurred */
  3213.         const TCHAR** path,                     /* Pointer to pointer to the path name (drive number) */
  3214.         FATFS** rfs,                            /* Pointer to pointer to the found filesystem object */
  3215.         BYTE mode                                       /* !=0: Check write protection for write access */
  3216. )
  3217. {
  3218.         BYTE fmt, *pt;
  3219.         int vol;
  3220.         DSTATUS stat;
  3221.         DWORD bsect, fasize, tsect, sysect, nclst, szbfat, br[4];
  3222.         WORD nrsv;
  3223.         FATFS *fs;
  3224.         UINT i;
  3225.  
  3226.  
  3227.         /* Get logical drive number */
  3228.         *rfs = 0;
  3229.         vol = get_ldnumber(path);
  3230.         if (vol < 0) return FR_INVALID_DRIVE;
  3231.  
  3232.         /* Check if the filesystem object is valid or not */
  3233.         fs = FatFs[vol];                                        /* Get pointer to the filesystem object */
  3234.         if (!fs) return FR_NOT_ENABLED;         /* Is the filesystem object available? */
  3235. #if FF_FS_REENTRANT
  3236.         if (!lock_fs(fs)) return FR_TIMEOUT;    /* Lock the volume */
  3237. #endif
  3238.         *rfs = fs;                                                      /* Return pointer to the filesystem object */
  3239.  
  3240.         mode &= (BYTE)~FA_READ;                         /* Desired access mode, write access or not */
  3241.         if (fs->fs_type != 0) {                         /* If the volume has been mounted */
  3242.                 stat = disk_status(fs->pdrv);
  3243.                 if (!(stat & STA_NOINIT)) {             /* and the physical drive is kept initialized */
  3244.                         if (!FF_FS_READONLY && mode && (stat & STA_PROTECT)) {  /* Check write protection if needed */
  3245.                                 return FR_WRITE_PROTECTED;
  3246.                         }
  3247.                         return FR_OK;                           /* The filesystem object is valid */
  3248.                 }
  3249.         }
  3250.  
  3251.         /* The filesystem object is not valid. */
  3252.         /* Following code attempts to mount the volume. (analyze BPB and initialize the filesystem object) */
  3253.  
  3254.         fs->fs_type = 0;                                        /* Clear the filesystem object */
  3255.         fs->pdrv = LD2PD(vol);                          /* Bind the logical drive and a physical drive */
  3256.         stat = disk_initialize(fs->pdrv);       /* Initialize the physical drive */
  3257.         if (stat & STA_NOINIT) {                        /* Check if the initialization succeeded */
  3258.                 return FR_NOT_READY;                    /* Failed to initialize due to no medium or hard error */
  3259.         }
  3260.         if (!FF_FS_READONLY && mode && (stat & STA_PROTECT)) { /* Check disk write protection if needed */
  3261.                 return FR_WRITE_PROTECTED;
  3262.         }
  3263. #if FF_MAX_SS != FF_MIN_SS                              /* Get sector size (multiple sector size cfg only) */
  3264.         if (disk_ioctl(fs->pdrv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK) return FR_DISK_ERR;
  3265.         if (SS(fs) > FF_MAX_SS || SS(fs) < FF_MIN_SS || (SS(fs) & (SS(fs) - 1))) return FR_DISK_ERR;
  3266. #endif
  3267.  
  3268.         /* Find an FAT partition on the drive. Supports only generic partitioning rules, FDISK (MBR) and SFD (w/o partition). */
  3269.         bsect = 0;
  3270.         fmt = check_fs(fs, bsect);                      /* Load sector 0 and check if it is an FAT-VBR as SFD */
  3271.         if (fmt == 2 || (fmt < 2 && LD2PT(vol) != 0)) { /* Not an FAT-VBR or forced partition number */
  3272.                 for (i = 0; i < 4; i++) {               /* Get partition offset */
  3273.                         pt = fs->win + (MBR_Table + i * SZ_PTE);
  3274.                         br[i] = pt[PTE_System] ? ld_dword(pt + PTE_StLba) : 0;
  3275.                 }
  3276.                 i = LD2PT(vol);                                 /* Partition number: 0:auto, 1-4:forced */
  3277.                 if (i != 0) i--;
  3278.                 do {                                                    /* Find an FAT volume */
  3279.                         bsect = br[i];
  3280.                         fmt = bsect ? check_fs(fs, bsect) : 3;  /* Check the partition */
  3281.                 } while (LD2PT(vol) == 0 && fmt >= 2 && ++i < 4);
  3282.         }
  3283.         if (fmt == 4) return FR_DISK_ERR;               /* An error occured in the disk I/O layer */
  3284.         if (fmt >= 2) return FR_NO_FILESYSTEM;  /* No FAT volume is found */
  3285.  
  3286.         /* An FAT volume is found (bsect). Following code initializes the filesystem object */
  3287.  
  3288. #if FF_FS_EXFAT
  3289.         if (fmt == 1) {
  3290.                 QWORD maxlba;
  3291.                 DWORD so, cv, bcl;
  3292.  
  3293.                 for (i = BPB_ZeroedEx; i < BPB_ZeroedEx + 53 && fs->win[i] == 0; i++) ; /* Check zero filler */
  3294.                 if (i < BPB_ZeroedEx + 53) return FR_NO_FILESYSTEM;
  3295.  
  3296.                 if (ld_word(fs->win + BPB_FSVerEx) != 0x100) return FR_NO_FILESYSTEM;   /* Check exFAT version (must be version 1.0) */
  3297.  
  3298.                 if (1 << fs->win[BPB_BytsPerSecEx] != SS(fs)) { /* (BPB_BytsPerSecEx must be equal to the physical sector size) */
  3299.                         return FR_NO_FILESYSTEM;
  3300.                 }
  3301.  
  3302.                 maxlba = ld_qword(fs->win + BPB_TotSecEx) + bsect;      /* Last LBA + 1 of the volume */
  3303.                 if (maxlba >= 0x100000000) return FR_NO_FILESYSTEM;     /* (It cannot be handled in 32-bit LBA) */
  3304.  
  3305.                 fs->fsize = ld_dword(fs->win + BPB_FatSzEx);    /* Number of sectors per FAT */
  3306.  
  3307.                 fs->n_fats = fs->win[BPB_NumFATsEx];                    /* Number of FATs */
  3308.                 if (fs->n_fats != 1) return FR_NO_FILESYSTEM;   /* (Supports only 1 FAT) */
  3309.  
  3310.                 fs->csize = 1 << fs->win[BPB_SecPerClusEx];             /* Cluster size */
  3311.                 if (fs->csize == 0)     return FR_NO_FILESYSTEM;        /* (Must be 1..32768) */
  3312.  
  3313.                 nclst = ld_dword(fs->win + BPB_NumClusEx);              /* Number of clusters */
  3314.                 if (nclst > MAX_EXFAT) return FR_NO_FILESYSTEM; /* (Too many clusters) */
  3315.                 fs->n_fatent = nclst + 2;
  3316.  
  3317.                 /* Boundaries and Limits */
  3318.                 fs->volbase = bsect;
  3319.                 fs->database = bsect + ld_dword(fs->win + BPB_DataOfsEx);
  3320.                 fs->fatbase = bsect + ld_dword(fs->win + BPB_FatOfsEx);
  3321.                 if (maxlba < (QWORD)fs->database + nclst * fs->csize) return FR_NO_FILESYSTEM;  /* (Volume size must not be smaller than the size requiered) */
  3322.                 fs->dirbase = ld_dword(fs->win + BPB_RootClusEx);
  3323.  
  3324.                 /* Get bitmap location and check if it is contiguous (implementation assumption) */
  3325.                 so = i = 0;
  3326.                 for (;;) {      /* Find the bitmap entry in the root directory (in only first cluster) */
  3327.                         if (i == 0) {
  3328.                                 if (so >= fs->csize) return FR_NO_FILESYSTEM;   /* Not found? */
  3329.                                 if (move_window(fs, clst2sect(fs, fs->dirbase) + so) != FR_OK) return FR_DISK_ERR;
  3330.                                 so++;
  3331.                         }
  3332.                         if (fs->win[i] == ET_BITMAP) break;                             /* Is it a bitmap entry? */
  3333.                         i = (i + SZDIRE) % SS(fs);      /* Next entry */
  3334.                 }
  3335.                 bcl = ld_dword(fs->win + i + 20);                                       /* Bitmap cluster */
  3336.                 if (bcl < 2 || bcl >= fs->n_fatent) return FR_NO_FILESYSTEM;
  3337.                 fs->bitbase = fs->database + fs->csize * (bcl - 2);     /* Bitmap sector */
  3338.                 for (;;) {      /* Check if bitmap is contiguous */
  3339.                         if (move_window(fs, fs->fatbase + bcl / (SS(fs) / 4)) != FR_OK) return FR_DISK_ERR;
  3340.                         cv = ld_dword(fs->win + bcl % (SS(fs) / 4) * 4);
  3341.                         if (cv == 0xFFFFFFFF) break;                            /* Last link? */
  3342.                         if (cv != ++bcl) return FR_NO_FILESYSTEM;       /* Fragmented? */
  3343.                 }
  3344.  
  3345. #if !FF_FS_READONLY
  3346.                 fs->last_clst = fs->free_clst = 0xFFFFFFFF;             /* Initialize cluster allocation information */
  3347. #endif
  3348.                 fmt = FS_EXFAT;                 /* FAT sub-type */
  3349.         } else
  3350. #endif  /* FF_FS_EXFAT */
  3351.         {
  3352.                 if (ld_word(fs->win + BPB_BytsPerSec) != SS(fs)) return FR_NO_FILESYSTEM;       /* (BPB_BytsPerSec must be equal to the physical sector size) */
  3353.  
  3354.                 fasize = ld_word(fs->win + BPB_FATSz16);                /* Number of sectors per FAT */
  3355.                 if (fasize == 0) fasize = ld_dword(fs->win + BPB_FATSz32);
  3356.                 fs->fsize = fasize;
  3357.  
  3358.                 fs->n_fats = fs->win[BPB_NumFATs];                              /* Number of FATs */
  3359.                 if (fs->n_fats != 1 && fs->n_fats != 2) return FR_NO_FILESYSTEM;        /* (Must be 1 or 2) */
  3360.                 fasize *= fs->n_fats;                                                   /* Number of sectors for FAT area */
  3361.  
  3362.                 fs->csize = fs->win[BPB_SecPerClus];                    /* Cluster size */
  3363.                 if (fs->csize == 0 || (fs->csize & (fs->csize - 1))) return FR_NO_FILESYSTEM;   /* (Must be power of 2) */
  3364.  
  3365.                 fs->n_rootdir = ld_word(fs->win + BPB_RootEntCnt);      /* Number of root directory entries */
  3366.                 if (fs->n_rootdir % (SS(fs) / SZDIRE)) return FR_NO_FILESYSTEM; /* (Must be sector aligned) */
  3367.  
  3368.                 tsect = ld_word(fs->win + BPB_TotSec16);                /* Number of sectors on the volume */
  3369.                 if (tsect == 0) tsect = ld_dword(fs->win + BPB_TotSec32);
  3370.  
  3371.                 nrsv = ld_word(fs->win + BPB_RsvdSecCnt);               /* Number of reserved sectors */
  3372.                 if (nrsv == 0) return FR_NO_FILESYSTEM;                 /* (Must not be 0) */
  3373.  
  3374.                 /* Determine the FAT sub type */
  3375.                 sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZDIRE);     /* RSV + FAT + DIR */
  3376.                 if (tsect < sysect) return FR_NO_FILESYSTEM;    /* (Invalid volume size) */
  3377.                 nclst = (tsect - sysect) / fs->csize;                   /* Number of clusters */
  3378.                 if (nclst == 0) return FR_NO_FILESYSTEM;                /* (Invalid volume size) */
  3379.                 fmt = 0;
  3380.                 if (nclst <= MAX_FAT32) fmt = FS_FAT32;
  3381.                 if (nclst <= MAX_FAT16) fmt = FS_FAT16;
  3382.                 if (nclst <= MAX_FAT12) fmt = FS_FAT12;
  3383.                 if (fmt == 0) return FR_NO_FILESYSTEM;
  3384.  
  3385.                 /* Boundaries and Limits */
  3386.                 fs->n_fatent = nclst + 2;                                               /* Number of FAT entries */
  3387.                 fs->volbase = bsect;                                                    /* Volume start sector */
  3388.                 fs->fatbase = bsect + nrsv;                                     /* FAT start sector */
  3389.                 fs->database = bsect + sysect;                                  /* Data start sector */
  3390.                 if (fmt == FS_FAT32) {
  3391.                         if (ld_word(fs->win + BPB_FSVer32) != 0) return FR_NO_FILESYSTEM;       /* (Must be FAT32 revision 0.0) */
  3392.                         if (fs->n_rootdir != 0) return FR_NO_FILESYSTEM;        /* (BPB_RootEntCnt must be 0) */
  3393.                         fs->dirbase = ld_dword(fs->win + BPB_RootClus32);       /* Root directory start cluster */
  3394.                         szbfat = fs->n_fatent * 4;                                      /* (Needed FAT size) */
  3395.                 } else {
  3396.                         if (fs->n_rootdir == 0) return FR_NO_FILESYSTEM;        /* (BPB_RootEntCnt must not be 0) */
  3397.                         fs->dirbase = fs->fatbase + fasize;                     /* Root directory start sector */
  3398.                         szbfat = (fmt == FS_FAT16) ?                            /* (Needed FAT size) */
  3399.                                 fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1);
  3400.                 }
  3401.                 if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) return FR_NO_FILESYSTEM;      /* (BPB_FATSz must not be less than the size needed) */
  3402.  
  3403. #if !FF_FS_READONLY
  3404.                 /* Get FSInfo if available */
  3405.                 fs->last_clst = fs->free_clst = 0xFFFFFFFF;             /* Initialize cluster allocation information */
  3406.                 fs->fsi_flag = 0x80;
  3407. #if (FF_FS_NOFSINFO & 3) != 3
  3408.                 if (fmt == FS_FAT32                             /* Allow to update FSInfo only if BPB_FSInfo32 == 1 */
  3409.                         && ld_word(fs->win + BPB_FSInfo32) == 1
  3410.                         && move_window(fs, bsect + 1) == FR_OK)
  3411.                 {
  3412.                         fs->fsi_flag = 0;
  3413.                         if (ld_word(fs->win + BS_55AA) == 0xAA55        /* Load FSInfo data if available */
  3414.                                 && ld_dword(fs->win + FSI_LeadSig) == 0x41615252
  3415.                                 && ld_dword(fs->win + FSI_StrucSig) == 0x61417272)
  3416.                         {
  3417. #if (FF_FS_NOFSINFO & 1) == 0
  3418.                                 fs->free_clst = ld_dword(fs->win + FSI_Free_Count);
  3419. #endif
  3420. #if (FF_FS_NOFSINFO & 2) == 0
  3421.                                 fs->last_clst = ld_dword(fs->win + FSI_Nxt_Free);
  3422. #endif
  3423.                         }
  3424.                 }
  3425. #endif  /* (FF_FS_NOFSINFO & 3) != 3 */
  3426. #endif  /* !FF_FS_READONLY */
  3427.         }
  3428.  
  3429.         fs->fs_type = fmt;              /* FAT sub-type */
  3430.         fs->id = ++Fsid;                /* Volume mount ID */
  3431. #if FF_USE_LFN == 1
  3432.         fs->lfnbuf = LfnBuf;    /* Static LFN working buffer */
  3433. #if FF_FS_EXFAT
  3434.         fs->dirbuf = DirBuf;    /* Static directory block scratchpad buuffer */
  3435. #endif
  3436. #endif
  3437. #if FF_FS_RPATH != 0
  3438.         fs->cdir = 0;                   /* Initialize current directory */
  3439. #endif
  3440. #if FF_FS_LOCK != 0                     /* Clear file lock semaphores */
  3441.         clear_lock(fs);
  3442. #endif
  3443.         return FR_OK;
  3444. }
  3445.  
  3446.  
  3447.  
  3448.  
  3449. /*-----------------------------------------------------------------------*/
  3450. /* Check if the file/directory object is valid or not                    */
  3451. /*-----------------------------------------------------------------------*/
  3452.  
  3453. static FRESULT validate (       /* Returns FR_OK or FR_INVALID_OBJECT */
  3454.         FFOBJID* obj,                   /* Pointer to the FFOBJID, the 1st member in the FIL/DIR object, to check validity */
  3455.         FATFS** rfs                             /* Pointer to pointer to the owner filesystem object to return */
  3456. )
  3457. {
  3458.         FRESULT res = FR_INVALID_OBJECT;
  3459.  
  3460.  
  3461.         if (obj && obj->fs && obj->fs->fs_type && obj->id == obj->fs->id) {     /* Test if the object is valid */
  3462. #if FF_FS_REENTRANT
  3463.                 if (lock_fs(obj->fs)) { /* Obtain the filesystem object */
  3464.                         if (!(disk_status(obj->fs->pdrv) & STA_NOINIT)) { /* Test if the phsical drive is kept initialized */
  3465.                                 res = FR_OK;
  3466.                         } else {
  3467.                                 unlock_fs(obj->fs, FR_OK);
  3468.                         }
  3469.                 } else {
  3470.                         res = FR_TIMEOUT;
  3471.                 }
  3472. #else
  3473.                 if (!(disk_status(obj->fs->pdrv) & STA_NOINIT)) { /* Test if the phsical drive is kept initialized */
  3474.                         res = FR_OK;
  3475.                 }
  3476. #endif
  3477.         }
  3478.         *rfs = (res == FR_OK) ? obj->fs : 0;    /* Corresponding filesystem object */
  3479.         return res;
  3480. }
  3481.  
  3482.  
  3483.  
  3484.  
  3485. /*---------------------------------------------------------------------------
  3486.  
  3487.    Public Functions (FatFs API)
  3488.  
  3489. ----------------------------------------------------------------------------*/
  3490.  
  3491.  
  3492.  
  3493. /*-----------------------------------------------------------------------*/
  3494. /* Mount/Unmount a Logical Drive                                         */
  3495. /*-----------------------------------------------------------------------*/
  3496.  
  3497. FRESULT f_mount (
  3498.         FATFS* fs,                      /* Pointer to the filesystem object (NULL:unmount)*/
  3499.         const TCHAR* path,      /* Logical drive number to be mounted/unmounted */
  3500.         BYTE opt                        /* Mode option 0:Do not mount (delayed mount), 1:Mount immediately */
  3501. )
  3502. {
  3503.         FATFS *cfs;
  3504.         int vol;
  3505.         FRESULT res;
  3506.         const TCHAR *rp = path;
  3507.  
  3508.  
  3509.         /* Get logical drive number */
  3510.         vol = get_ldnumber(&rp);
  3511.         if (vol < 0) return FR_INVALID_DRIVE;
  3512.         cfs = FatFs[vol];                                       /* Pointer to fs object */
  3513.  
  3514.         if (cfs) {
  3515. #if FF_FS_LOCK != 0
  3516.                 clear_lock(cfs);
  3517. #endif
  3518. #if FF_FS_REENTRANT                                             /* Discard sync object of the current volume */
  3519.                 if (!ff_del_syncobj(cfs->sobj)) return FR_INT_ERR;
  3520. #endif
  3521.                 cfs->fs_type = 0;                               /* Clear old fs object */
  3522.         }
  3523.  
  3524.         if (fs) {
  3525.                 fs->fs_type = 0;                                /* Clear new fs object */
  3526. #if FF_FS_REENTRANT                                             /* Create sync object for the new volume */
  3527.                 if (!ff_cre_syncobj((BYTE)vol, &fs->sobj)) return FR_INT_ERR;
  3528. #endif
  3529.         }
  3530.         FatFs[vol] = fs;                                        /* Register new fs object */
  3531.  
  3532.         if (opt == 0) return FR_OK;                     /* Do not mount now, it will be mounted later */
  3533.  
  3534.         res = find_volume(&path, &fs, 0);       /* Force mounted the volume */
  3535.         LEAVE_FF(fs, res);
  3536. }
  3537.  
  3538.  
  3539.  
  3540.  
  3541. /*-----------------------------------------------------------------------*/
  3542. /* Open or Create a File                                                 */
  3543. /*-----------------------------------------------------------------------*/
  3544.  
  3545. FRESULT f_open (
  3546.         FIL* fp,                        /* Pointer to the blank file object */
  3547.         const TCHAR* path,      /* Pointer to the file name */
  3548.         BYTE mode                       /* Access mode and file open mode flags */
  3549. )
  3550. {
  3551.         FRESULT res;
  3552.         DIR dj;
  3553.         FATFS *fs;
  3554. #if !FF_FS_READONLY
  3555.         DWORD dw, cl, bcs, clst, sc;
  3556.         FSIZE_t ofs;
  3557. #endif
  3558.         DEF_NAMBUF
  3559.  
  3560.  
  3561.         if (!fp) return FR_INVALID_OBJECT;
  3562.  
  3563.         /* Get logical drive number */
  3564.         mode &= FF_FS_READONLY ? FA_READ : FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_CREATE_NEW | FA_OPEN_ALWAYS | FA_OPEN_APPEND;
  3565.         res = find_volume(&path, &fs, mode);
  3566.         if (res == FR_OK) {
  3567.                 dj.obj.fs = fs;
  3568.                 INIT_NAMBUF(fs);
  3569.                 res = follow_path(&dj, path);   /* Follow the file path */
  3570. #if !FF_FS_READONLY     /* Read/Write configuration */
  3571.                 if (res == FR_OK) {
  3572.                         if (dj.fn[NSFLAG] & NS_NONAME) {        /* Origin directory itself? */
  3573.                                 res = FR_INVALID_NAME;
  3574.                         }
  3575. #if FF_FS_LOCK != 0
  3576.                         else {
  3577.                                 res = chk_lock(&dj, (mode & ~FA_READ) ? 1 : 0);         /* Check if the file can be used */
  3578.                         }
  3579. #endif
  3580.                 }
  3581.                 /* Create or Open a file */
  3582.                 if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) {
  3583.                         if (res != FR_OK) {                                     /* No file, create new */
  3584.                                 if (res == FR_NO_FILE) {                /* There is no file to open, create a new entry */
  3585. #if FF_FS_LOCK != 0
  3586.                                         res = enq_lock() ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES;
  3587. #else
  3588.                                         res = dir_register(&dj);
  3589. #endif
  3590.                                 }
  3591.                                 mode |= FA_CREATE_ALWAYS;               /* File is created */
  3592.                         }
  3593.                         else {                                                          /* Any object with the same name is already existing */
  3594.                                 if (dj.obj.attr & (AM_RDO | AM_DIR)) {  /* Cannot overwrite it (R/O or DIR) */
  3595.                                         res = FR_DENIED;
  3596.                                 } else {
  3597.                                         if (mode & FA_CREATE_NEW) res = FR_EXIST;       /* Cannot create as new file */
  3598.                                 }
  3599.                         }
  3600.                         if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) {        /* Truncate the file if overwrite mode */
  3601. #if FF_FS_EXFAT
  3602.                                 if (fs->fs_type == FS_EXFAT) {
  3603.                                         /* Get current allocation info */
  3604.                                         fp->obj.fs = fs;
  3605.                                         init_alloc_info(fs, &fp->obj);
  3606.                                         /* Set directory entry block initial state */
  3607.                                         mem_set(fs->dirbuf + 2, 0, 30);         /* Clear 85 entry except for NumSec */
  3608.                                         mem_set(fs->dirbuf + 38, 0, 26);        /* Clear C0 entry except for NumName and NameHash */
  3609.                                         fs->dirbuf[XDIR_Attr] = AM_ARC;
  3610.                                         st_dword(fs->dirbuf + XDIR_CrtTime, GET_FATTIME());
  3611.                                         fs->dirbuf[XDIR_GenFlags] = 1;
  3612.                                         res = store_xdir(&dj);
  3613.                                         if (res == FR_OK && fp->obj.sclust != 0) {      /* Remove the cluster chain if exist */
  3614.                                                 res = remove_chain(&fp->obj, fp->obj.sclust, 0);
  3615.                                                 fs->last_clst = fp->obj.sclust - 1;             /* Reuse the cluster hole */
  3616.                                         }
  3617.                                 } else
  3618. #endif
  3619.                                 {
  3620.                                         /* Set directory entry initial state */
  3621.                                         cl = ld_clust(fs, dj.dir);                      /* Get current cluster chain */
  3622.                                         st_dword(dj.dir + DIR_CrtTime, GET_FATTIME());  /* Set created time */
  3623.                                         dj.dir[DIR_Attr] = AM_ARC;                      /* Reset attribute */
  3624.                                         st_clust(fs, dj.dir, 0);                        /* Reset file allocation info */
  3625.                                         st_dword(dj.dir + DIR_FileSize, 0);
  3626.                                         fs->wflag = 1;
  3627.                                         if (cl != 0) {                                          /* Remove the cluster chain if exist */
  3628.                                                 dw = fs->winsect;
  3629.                                                 res = remove_chain(&dj.obj, cl, 0);
  3630.                                                 if (res == FR_OK) {
  3631.                                                         res = move_window(fs, dw);
  3632.                                                         fs->last_clst = cl - 1;         /* Reuse the cluster hole */
  3633.                                                 }
  3634.                                         }
  3635.                                 }
  3636.                         }
  3637.                 }
  3638.                 else {  /* Open an existing file */
  3639.                         if (res == FR_OK) {                                     /* Is the object exsiting? */
  3640.                                 if (dj.obj.attr & AM_DIR) {             /* File open against a directory */
  3641.                                         res = FR_NO_FILE;
  3642.                                 } else {
  3643.                                         if ((mode & FA_WRITE) && (dj.obj.attr & AM_RDO)) { /* Write mode open against R/O file */
  3644.                                                 res = FR_DENIED;
  3645.                                         }
  3646.                                 }
  3647.                         }
  3648.                 }
  3649.                 if (res == FR_OK) {
  3650.                         if (mode & FA_CREATE_ALWAYS) mode |= FA_MODIFIED;       /* Set file change flag if created or overwritten */
  3651.                         fp->dir_sect = fs->winsect;                     /* Pointer to the directory entry */
  3652.                         fp->dir_ptr = dj.dir;
  3653. #if FF_FS_LOCK != 0
  3654.                         fp->obj.lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0);      /* Lock the file for this session */
  3655.                         if (fp->obj.lockid == 0) res = FR_INT_ERR;
  3656. #endif
  3657.                 }
  3658. #else           /* R/O configuration */
  3659.                 if (res == FR_OK) {
  3660.                         if (dj.fn[NSFLAG] & NS_NONAME) {        /* Is it origin directory itself? */
  3661.                                 res = FR_INVALID_NAME;
  3662.                         } else {
  3663.                                 if (dj.obj.attr & AM_DIR) {             /* Is it a directory? */
  3664.                                         res = FR_NO_FILE;
  3665.                                 }
  3666.                         }
  3667.                 }
  3668. #endif
  3669.  
  3670.                 if (res == FR_OK) {
  3671. #if FF_FS_EXFAT
  3672.                         if (fs->fs_type == FS_EXFAT) {
  3673.                                 fp->obj.c_scl = dj.obj.sclust;                                                  /* Get containing directory info */
  3674.                                 fp->obj.c_size = ((DWORD)dj.obj.objsize & 0xFFFFFF00) | dj.obj.stat;
  3675.                                 fp->obj.c_ofs = dj.blk_ofs;
  3676.                                 init_alloc_info(fs, &fp->obj);
  3677.                         } else
  3678. #endif
  3679.                         {
  3680.                                 fp->obj.sclust = ld_clust(fs, dj.dir);                                  /* Get object allocation info */
  3681.                                 fp->obj.objsize = ld_dword(dj.dir + DIR_FileSize);
  3682.                         }
  3683. #if FF_USE_FASTSEEK
  3684.                         fp->cltbl = 0;                  /* Disable fast seek mode */
  3685. #endif
  3686.                         fp->obj.fs = fs;                /* Validate the file object */
  3687.                         fp->obj.id = fs->id;
  3688.                         fp->flag = mode;                /* Set file access mode */
  3689.                         fp->err = 0;                    /* Clear error flag */
  3690.                         fp->sect = 0;                   /* Invalidate current data sector */
  3691.                         fp->fptr = 0;                   /* Set file pointer top of the file */
  3692. #if !FF_FS_READONLY
  3693. #if !FF_FS_TINY
  3694.                         mem_set(fp->buf, 0, sizeof fp->buf);    /* Clear sector buffer */
  3695. #endif
  3696.                         if ((mode & FA_SEEKEND) && fp->obj.objsize > 0) {       /* Seek to end of file if FA_OPEN_APPEND is specified */
  3697.                                 fp->fptr = fp->obj.objsize;                     /* Offset to seek */
  3698.                                 bcs = (DWORD)fs->csize * SS(fs);        /* Cluster size in byte */
  3699.                                 clst = fp->obj.sclust;                          /* Follow the cluster chain */
  3700.                                 for (ofs = fp->obj.objsize; res == FR_OK && ofs > bcs; ofs -= bcs) {
  3701.                                         clst = get_fat(&fp->obj, clst);
  3702.                                         if (clst <= 1) res = FR_INT_ERR;
  3703.                                         if (clst == 0xFFFFFFFF) res = FR_DISK_ERR;
  3704.                                 }
  3705.                                 fp->clust = clst;
  3706.                                 if (res == FR_OK && ofs % SS(fs)) {     /* Fill sector buffer if not on the sector boundary */
  3707.                                         if ((sc = clst2sect(fs, clst)) == 0) {
  3708.                                                 res = FR_INT_ERR;
  3709.                                         } else {
  3710.                                                 fp->sect = sc + (DWORD)(ofs / SS(fs));
  3711. #if !FF_FS_TINY
  3712.                                                 if (disk_read(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) res = FR_DISK_ERR;
  3713. #endif
  3714.                                         }
  3715.                                 }
  3716.                         }
  3717. #endif
  3718.                 }
  3719.  
  3720.                 FREE_NAMBUF();
  3721.         }
  3722.  
  3723.         if (res != FR_OK) fp->obj.fs = 0;       /* Invalidate file object on error */
  3724.  
  3725.         LEAVE_FF(fs, res);
  3726. }
  3727.  
  3728.  
  3729.  
  3730.  
  3731. /*-----------------------------------------------------------------------*/
  3732. /* Read File                                                             */
  3733. /*-----------------------------------------------------------------------*/
  3734.  
  3735. FRESULT f_read (
  3736.         FIL* fp,        /* Pointer to the file object */
  3737.         void* buff,     /* Pointer to data buffer */
  3738.         UINT btr,       /* Number of bytes to read */
  3739.         UINT* br        /* Pointer to number of bytes read */
  3740. )
  3741. {
  3742.         FRESULT res;
  3743.         FATFS *fs;
  3744.         DWORD clst, sect;
  3745.         FSIZE_t remain;
  3746.         UINT rcnt, cc, csect;
  3747.         BYTE *rbuff = (BYTE*)buff;
  3748.  
  3749.  
  3750.         *br = 0;        /* Clear read byte counter */
  3751.         res = validate(&fp->obj, &fs);                          /* Check validity of the file object */
  3752.         if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res);       /* Check validity */
  3753.         if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */
  3754.         remain = fp->obj.objsize - fp->fptr;
  3755.         if (btr > remain) btr = (UINT)remain;           /* Truncate btr by remaining bytes */
  3756.  
  3757.         for ( ;  btr;                                                           /* Repeat until btr bytes read */
  3758.                 btr -= rcnt, *br += rcnt, rbuff += rcnt, fp->fptr += rcnt) {
  3759.                 if (fp->fptr % SS(fs) == 0) {                   /* On the sector boundary? */
  3760.                         csect = (UINT)(fp->fptr / SS(fs) & (fs->csize - 1));    /* Sector offset in the cluster */
  3761.                         if (csect == 0) {                                       /* On the cluster boundary? */
  3762.                                 if (fp->fptr == 0) {                    /* On the top of the file? */
  3763.                                         clst = fp->obj.sclust;          /* Follow cluster chain from the origin */
  3764.                                 } else {                                                /* Middle or end of the file */
  3765. #if FF_USE_FASTSEEK
  3766.                                         if (fp->cltbl) {
  3767.                                                 clst = clmt_clust(fp, fp->fptr);        /* Get cluster# from the CLMT */
  3768.                                         } else
  3769. #endif
  3770.                                         {
  3771.                                                 clst = get_fat(&fp->obj, fp->clust);    /* Follow cluster chain on the FAT */
  3772.                                         }
  3773.                                 }
  3774.                                 if (clst < 2) ABORT(fs, FR_INT_ERR);
  3775.                                 if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR);
  3776.                                 fp->clust = clst;                               /* Update current cluster */
  3777.                         }
  3778.                         sect = clst2sect(fs, fp->clust);        /* Get current sector */
  3779.                         if (sect == 0) ABORT(fs, FR_INT_ERR);
  3780.                         sect += csect;
  3781.                         cc = btr / SS(fs);                                      /* When remaining bytes >= sector size, */
  3782.                         if (cc > 0) {                                           /* Read maximum contiguous sectors directly */
  3783.                                 if (csect + cc > fs->csize) {   /* Clip at cluster boundary */
  3784.                                         cc = fs->csize - csect;
  3785.                                 }
  3786.                                 if (disk_read(fs->pdrv, rbuff, sect, cc) != RES_OK) ABORT(fs, FR_DISK_ERR);
  3787. #if !FF_FS_READONLY && FF_FS_MINIMIZE <= 2              /* Replace one of the read sectors with cached data if it contains a dirty sector */
  3788. #if FF_FS_TINY
  3789.                                 if (fs->wflag && fs->winsect - sect < cc) {
  3790.                                         mem_cpy(rbuff + ((fs->winsect - sect) * SS(fs)), fs->win, SS(fs));
  3791.                                 }
  3792. #else
  3793.                                 if ((fp->flag & FA_DIRTY) && fp->sect - sect < cc) {
  3794.                                         mem_cpy(rbuff + ((fp->sect - sect) * SS(fs)), fp->buf, SS(fs));
  3795.                                 }
  3796. #endif
  3797. #endif
  3798.                                 rcnt = SS(fs) * cc;                             /* Number of bytes transferred */
  3799.                                 continue;
  3800.                         }
  3801. #if !FF_FS_TINY
  3802.                         if (fp->sect != sect) {                 /* Load data sector if not in cache */
  3803. #if !FF_FS_READONLY
  3804.                                 if (fp->flag & FA_DIRTY) {              /* Write-back dirty sector cache */
  3805.                                         if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);
  3806.                                         fp->flag &= (BYTE)~FA_DIRTY;
  3807.                                 }
  3808. #endif
  3809.                                 if (disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK)    ABORT(fs, FR_DISK_ERR); /* Fill sector cache */
  3810.                         }
  3811. #endif
  3812.                         fp->sect = sect;
  3813.                 }
  3814.                 rcnt = SS(fs) - (UINT)fp->fptr % SS(fs);        /* Number of bytes left in the sector */
  3815.                 if (rcnt > btr) rcnt = btr;                                     /* Clip it by btr if needed */
  3816. #if FF_FS_TINY
  3817.                 if (move_window(fs, fp->sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window */
  3818.                 mem_cpy(rbuff, fs->win + fp->fptr % SS(fs), rcnt);      /* Extract partial sector */
  3819. #else
  3820.                 mem_cpy(rbuff, fp->buf + fp->fptr % SS(fs), rcnt);      /* Extract partial sector */
  3821. #endif
  3822.         }
  3823.  
  3824.         LEAVE_FF(fs, FR_OK);
  3825. }
  3826.  
  3827.  
  3828.  
  3829.  
  3830. #if !FF_FS_READONLY
  3831. /*-----------------------------------------------------------------------*/
  3832. /* Write File                                                            */
  3833. /*-----------------------------------------------------------------------*/
  3834.  
  3835. FRESULT f_write (
  3836.         FIL* fp,                        /* Pointer to the file object */
  3837.         const void* buff,       /* Pointer to the data to be written */
  3838.         UINT btw,                       /* Number of bytes to write */
  3839.         UINT* bw                        /* Pointer to number of bytes written */
  3840. )
  3841. {
  3842.         FRESULT res;
  3843.         FATFS *fs;
  3844.         DWORD clst, sect;
  3845.         UINT wcnt, cc, csect;
  3846.         const BYTE *wbuff = (const BYTE*)buff;
  3847.  
  3848.  
  3849.         *bw = 0;        /* Clear write byte counter */
  3850.         res = validate(&fp->obj, &fs);                  /* Check validity of the file object */
  3851.         if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res);       /* Check validity */
  3852.         if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED);    /* Check access mode */
  3853.  
  3854.         /* Check fptr wrap-around (file size cannot reach 4 GiB at FAT volume) */
  3855.         if ((!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) && (DWORD)(fp->fptr + btw) < (DWORD)fp->fptr) {
  3856.                 btw = (UINT)(0xFFFFFFFF - (DWORD)fp->fptr);
  3857.         }
  3858.  
  3859.         for ( ;  btw;                                                   /* Repeat until all data written */
  3860.                 btw -= wcnt, *bw += wcnt, wbuff += wcnt, fp->fptr += wcnt, fp->obj.objsize = (fp->fptr > fp->obj.objsize) ? fp->fptr : fp->obj.objsize) {
  3861.                 if (fp->fptr % SS(fs) == 0) {           /* On the sector boundary? */
  3862.                         csect = (UINT)(fp->fptr / SS(fs)) & (fs->csize - 1);    /* Sector offset in the cluster */
  3863.                         if (csect == 0) {                               /* On the cluster boundary? */
  3864.                                 if (fp->fptr == 0) {            /* On the top of the file? */
  3865.                                         clst = fp->obj.sclust;  /* Follow from the origin */
  3866.                                         if (clst == 0) {                /* If no cluster is allocated, */
  3867.                                                 clst = create_chain(&fp->obj, 0);       /* create a new cluster chain */
  3868.                                         }
  3869.                                 } else {                                        /* On the middle or end of the file */
  3870. #if FF_USE_FASTSEEK
  3871.                                         if (fp->cltbl) {
  3872.                                                 clst = clmt_clust(fp, fp->fptr);        /* Get cluster# from the CLMT */
  3873.                                         } else
  3874. #endif
  3875.                                         {
  3876.                                                 clst = create_chain(&fp->obj, fp->clust);       /* Follow or stretch cluster chain on the FAT */
  3877.                                         }
  3878.                                 }
  3879.                                 if (clst == 0) break;           /* Could not allocate a new cluster (disk full) */
  3880.                                 if (clst == 1) ABORT(fs, FR_INT_ERR);
  3881.                                 if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR);
  3882.                                 fp->clust = clst;                       /* Update current cluster */
  3883.                                 if (fp->obj.sclust == 0) fp->obj.sclust = clst; /* Set start cluster if the first write */
  3884.                         }
  3885. #if FF_FS_TINY
  3886.                         if (fs->winsect == fp->sect && sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR);        /* Write-back sector cache */
  3887. #else
  3888.                         if (fp->flag & FA_DIRTY) {              /* Write-back sector cache */
  3889.                                 if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);
  3890.                                 fp->flag &= (BYTE)~FA_DIRTY;
  3891.                         }
  3892. #endif
  3893.                         sect = clst2sect(fs, fp->clust);        /* Get current sector */
  3894.                         if (sect == 0) ABORT(fs, FR_INT_ERR);
  3895.                         sect += csect;
  3896.                         cc = btw / SS(fs);                              /* When remaining bytes >= sector size, */
  3897.                         if (cc > 0) {                                   /* Write maximum contiguous sectors directly */
  3898.                                 if (csect + cc > fs->csize) {   /* Clip at cluster boundary */
  3899.                                         cc = fs->csize - csect;
  3900.                                 }
  3901.                                 if (disk_write(fs->pdrv, wbuff, sect, cc) != RES_OK) ABORT(fs, FR_DISK_ERR);
  3902. #if FF_FS_MINIMIZE <= 2
  3903. #if FF_FS_TINY
  3904.                                 if (fs->winsect - sect < cc) {  /* Refill sector cache if it gets invalidated by the direct write */
  3905.                                         mem_cpy(fs->win, wbuff + ((fs->winsect - sect) * SS(fs)), SS(fs));
  3906.                                         fs->wflag = 0;
  3907.                                 }
  3908. #else
  3909.                                 if (fp->sect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */
  3910.                                         mem_cpy(fp->buf, wbuff + ((fp->sect - sect) * SS(fs)), SS(fs));
  3911.                                         fp->flag &= (BYTE)~FA_DIRTY;
  3912.                                 }
  3913. #endif
  3914. #endif
  3915.                                 wcnt = SS(fs) * cc;             /* Number of bytes transferred */
  3916.                                 continue;
  3917.                         }
  3918. #if FF_FS_TINY
  3919.                         if (fp->fptr >= fp->obj.objsize) {      /* Avoid silly cache filling on the growing edge */
  3920.                                 if (sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR);
  3921.                                 fs->winsect = sect;
  3922.                         }
  3923. #else
  3924.                         if (fp->sect != sect &&                 /* Fill sector cache with file data */
  3925.                                 fp->fptr < fp->obj.objsize &&
  3926.                                 disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) {
  3927.                                         ABORT(fs, FR_DISK_ERR);
  3928.                         }
  3929. #endif
  3930.                         fp->sect = sect;
  3931.                 }
  3932.                 wcnt = SS(fs) - (UINT)fp->fptr % SS(fs);        /* Number of bytes left in the sector */
  3933.                 if (wcnt > btw) wcnt = btw;                                     /* Clip it by btw if needed */
  3934. #if FF_FS_TINY
  3935.                 if (move_window(fs, fp->sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window */
  3936.                 mem_cpy(fs->win + fp->fptr % SS(fs), wbuff, wcnt);      /* Fit data to the sector */
  3937.                 fs->wflag = 1;
  3938. #else
  3939.                 mem_cpy(fp->buf + fp->fptr % SS(fs), wbuff, wcnt);      /* Fit data to the sector */
  3940.                 fp->flag |= FA_DIRTY;
  3941. #endif
  3942.         }
  3943.  
  3944.         fp->flag |= FA_MODIFIED;                                /* Set file change flag */
  3945.  
  3946.         LEAVE_FF(fs, FR_OK);
  3947. }
  3948.  
  3949.  
  3950.  
  3951.  
  3952. /*-----------------------------------------------------------------------*/
  3953. /* Synchronize the File                                                  */
  3954. /*-----------------------------------------------------------------------*/
  3955.  
  3956. FRESULT f_sync (
  3957.         FIL* fp         /* Pointer to the file object */
  3958. )
  3959. {
  3960.         FRESULT res;
  3961.         FATFS *fs;
  3962.         DWORD tm;
  3963.         BYTE *dir;
  3964.  
  3965.  
  3966.         res = validate(&fp->obj, &fs);  /* Check validity of the file object */
  3967.         if (res == FR_OK) {
  3968.                 if (fp->flag & FA_MODIFIED) {   /* Is there any change to the file? */
  3969. #if !FF_FS_TINY
  3970.                         if (fp->flag & FA_DIRTY) {      /* Write-back cached data if needed */
  3971.                                 if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) LEAVE_FF(fs, FR_DISK_ERR);
  3972.                                 fp->flag &= (BYTE)~FA_DIRTY;
  3973.                         }
  3974. #endif
  3975.                         /* Update the directory entry */
  3976.                         tm = GET_FATTIME();                             /* Modified time */
  3977. #if FF_FS_EXFAT
  3978.                         if (fs->fs_type == FS_EXFAT) {
  3979.                                 res = fill_first_frag(&fp->obj);        /* Fill first fragment on the FAT if needed */
  3980.                                 if (res == FR_OK) {
  3981.                                         res = fill_last_frag(&fp->obj, fp->clust, 0xFFFFFFFF);  /* Fill last fragment on the FAT if needed */
  3982.                                 }
  3983.                                 if (res == FR_OK) {
  3984.                                         DIR dj;
  3985.                                         DEF_NAMBUF
  3986.  
  3987.                                         INIT_NAMBUF(fs);
  3988.                                         res = load_obj_xdir(&dj, &fp->obj);     /* Load directory entry block */
  3989.                                         if (res == FR_OK) {
  3990.                                                 fs->dirbuf[XDIR_Attr] |= AM_ARC;                                /* Set archive attribute to indicate that the file has been changed */
  3991.                                                 fs->dirbuf[XDIR_GenFlags] = fp->obj.stat | 1;   /* Update file allocation information */
  3992.                                                 st_dword(fs->dirbuf + XDIR_FstClus, fp->obj.sclust);
  3993.                                                 st_qword(fs->dirbuf + XDIR_FileSize, fp->obj.objsize);
  3994.                                                 st_qword(fs->dirbuf + XDIR_ValidFileSize, fp->obj.objsize);
  3995.                                                 st_dword(fs->dirbuf + XDIR_ModTime, tm);                /* Update modified time */
  3996.                                                 fs->dirbuf[XDIR_ModTime10] = 0;
  3997.                                                 st_dword(fs->dirbuf + XDIR_AccTime, 0);
  3998.                                                 res = store_xdir(&dj);  /* Restore it to the directory */
  3999.                                                 if (res == FR_OK) {
  4000.                                                         res = sync_fs(fs);
  4001.                                                         fp->flag &= (BYTE)~FA_MODIFIED;
  4002.                                                 }
  4003.                                         }
  4004.                                         FREE_NAMBUF();
  4005.                                 }
  4006.                         } else
  4007. #endif
  4008.                         {
  4009.                                 res = move_window(fs, fp->dir_sect);
  4010.                                 if (res == FR_OK) {
  4011.                                         dir = fp->dir_ptr;
  4012.                                         dir[DIR_Attr] |= AM_ARC;                                                /* Set archive attribute to indicate that the file has been changed */
  4013.                                         st_clust(fp->obj.fs, dir, fp->obj.sclust);              /* Update file allocation information  */
  4014.                                         st_dword(dir + DIR_FileSize, (DWORD)fp->obj.objsize);   /* Update file size */
  4015.                                         st_dword(dir + DIR_ModTime, tm);                                /* Update modified time */
  4016.                                         st_word(dir + DIR_LstAccDate, 0);
  4017.                                         fs->wflag = 1;
  4018.                                         res = sync_fs(fs);                                      /* Restore it to the directory */
  4019.                                         fp->flag &= (BYTE)~FA_MODIFIED;
  4020.                                 }
  4021.                         }
  4022.                 }
  4023.         }
  4024.  
  4025.         LEAVE_FF(fs, res);
  4026. }
  4027.  
  4028. #endif /* !FF_FS_READONLY */
  4029.  
  4030.  
  4031.  
  4032.  
  4033. /*-----------------------------------------------------------------------*/
  4034. /* Close File                                                            */
  4035. /*-----------------------------------------------------------------------*/
  4036.  
  4037. FRESULT f_close (
  4038.         FIL* fp         /* Pointer to the file object to be closed */
  4039. )
  4040. {
  4041.         FRESULT res;
  4042.         FATFS *fs;
  4043.  
  4044. #if !FF_FS_READONLY
  4045.         res = f_sync(fp);                                       /* Flush cached data */
  4046.         if (res == FR_OK)
  4047. #endif
  4048.         {
  4049.                 res = validate(&fp->obj, &fs);  /* Lock volume */
  4050.                 if (res == FR_OK) {
  4051. #if FF_FS_LOCK != 0
  4052.                         res = dec_lock(fp->obj.lockid);         /* Decrement file open counter */
  4053.                         if (res == FR_OK) fp->obj.fs = 0;       /* Invalidate file object */
  4054. #else
  4055.                         fp->obj.fs = 0; /* Invalidate file object */
  4056. #endif
  4057. #if FF_FS_REENTRANT
  4058.                         unlock_fs(fs, FR_OK);           /* Unlock volume */
  4059. #endif
  4060.                 }
  4061.         }
  4062.         return res;
  4063. }
  4064.  
  4065.  
  4066.  
  4067.  
  4068. #if FF_FS_RPATH >= 1
  4069. /*-----------------------------------------------------------------------*/
  4070. /* Change Current Directory or Current Drive, Get Current Directory      */
  4071. /*-----------------------------------------------------------------------*/
  4072.  
  4073. FRESULT f_chdrive (
  4074.         const TCHAR* path               /* Drive number to set */
  4075. )
  4076. {
  4077.         int vol;
  4078.  
  4079.  
  4080.         /* Get logical drive number */
  4081.         vol = get_ldnumber(&path);
  4082.         if (vol < 0) return FR_INVALID_DRIVE;
  4083.         CurrVol = (BYTE)vol;    /* Set it as current volume */
  4084.  
  4085.         return FR_OK;
  4086. }
  4087.  
  4088.  
  4089.  
  4090. FRESULT f_chdir (
  4091.         const TCHAR* path       /* Pointer to the directory path */
  4092. )
  4093. {
  4094. #if FF_STR_VOLUME_ID == 2
  4095.         UINT i;
  4096. #endif
  4097.         FRESULT res;
  4098.         DIR dj;
  4099.         FATFS *fs;
  4100.         DEF_NAMBUF
  4101.  
  4102.  
  4103.         /* Get logical drive */
  4104.         res = find_volume(&path, &fs, 0);
  4105.         if (res == FR_OK) {
  4106.                 dj.obj.fs = fs;
  4107.                 INIT_NAMBUF(fs);
  4108.                 res = follow_path(&dj, path);           /* Follow the path */
  4109.                 if (res == FR_OK) {                                     /* Follow completed */
  4110.                         if (dj.fn[NSFLAG] & NS_NONAME) {        /* Is it the start directory itself? */
  4111.                                 fs->cdir = dj.obj.sclust;
  4112. #if FF_FS_EXFAT
  4113.                                 if (fs->fs_type == FS_EXFAT) {
  4114.                                         fs->cdc_scl = dj.obj.c_scl;
  4115.                                         fs->cdc_size = dj.obj.c_size;
  4116.                                         fs->cdc_ofs = dj.obj.c_ofs;
  4117.                                 }
  4118. #endif
  4119.                         } else {
  4120.                                 if (dj.obj.attr & AM_DIR) {     /* It is a sub-directory */
  4121. #if FF_FS_EXFAT
  4122.                                         if (fs->fs_type == FS_EXFAT) {
  4123.                                                 fs->cdir = ld_dword(fs->dirbuf + XDIR_FstClus);         /* Sub-directory cluster */
  4124.                                                 fs->cdc_scl = dj.obj.sclust;                                            /* Save containing directory information */
  4125.                                                 fs->cdc_size = ((DWORD)dj.obj.objsize & 0xFFFFFF00) | dj.obj.stat;
  4126.                                                 fs->cdc_ofs = dj.blk_ofs;
  4127.                                         } else
  4128. #endif
  4129.                                         {
  4130.                                                 fs->cdir = ld_clust(fs, dj.dir);                                        /* Sub-directory cluster */
  4131.                                         }
  4132.                                 } else {
  4133.                                         res = FR_NO_PATH;               /* Reached but a file */
  4134.                                 }
  4135.                         }
  4136.                 }
  4137.                 FREE_NAMBUF();
  4138.                 if (res == FR_NO_FILE) res = FR_NO_PATH;
  4139. #if FF_STR_VOLUME_ID == 2       /* Also current drive is changed at Unix style volume ID */
  4140.                 if (res == FR_OK) {
  4141.                         for (i = FF_VOLUMES - 1; i && fs != FatFs[i]; i--) ;    /* Set current drive */
  4142.                         CurrVol = (BYTE)i;
  4143.                 }
  4144. #endif
  4145.         }
  4146.  
  4147.         LEAVE_FF(fs, res);
  4148. }
  4149.  
  4150.  
  4151. #if FF_FS_RPATH >= 2
  4152. FRESULT f_getcwd (
  4153.         TCHAR* buff,    /* Pointer to the directory path */
  4154.         UINT len                /* Size of buff in unit of TCHAR */
  4155. )
  4156. {
  4157.         FRESULT res;
  4158.         DIR dj;
  4159.         FATFS *fs;
  4160.         UINT i, n;
  4161.         DWORD ccl;
  4162.         TCHAR *tp = buff;
  4163. #if FF_VOLUMES >= 2
  4164.         UINT vl;
  4165. #endif
  4166. #if FF_STR_VOLUME_ID
  4167.         const char *vp;
  4168. #endif
  4169.         FILINFO fno;
  4170.         DEF_NAMBUF
  4171.  
  4172.  
  4173.         /* Get logical drive */
  4174.         buff[0] = 0;    /* Set null string to get current volume */
  4175.         res = find_volume((const TCHAR**)&buff, &fs, 0);        /* Get current volume */
  4176.         if (res == FR_OK) {
  4177.                 dj.obj.fs = fs;
  4178.                 INIT_NAMBUF(fs);
  4179.  
  4180.                 /* Follow parent directories and create the path */
  4181.                 i = len;                        /* Bottom of buffer (directory stack base) */
  4182.                 if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) {  /* (Cannot do getcwd on exFAT and returns root path) */
  4183.                         dj.obj.sclust = fs->cdir;                               /* Start to follow upper directory from current directory */
  4184.                         while ((ccl = dj.obj.sclust) != 0) {    /* Repeat while current directory is a sub-directory */
  4185.                                 res = dir_sdi(&dj, 1 * SZDIRE); /* Get parent directory */
  4186.                                 if (res != FR_OK) break;
  4187.                                 res = move_window(fs, dj.sect);
  4188.                                 if (res != FR_OK) break;
  4189.                                 dj.obj.sclust = ld_clust(fs, dj.dir);   /* Goto parent directory */
  4190.                                 res = dir_sdi(&dj, 0);
  4191.                                 if (res != FR_OK) break;
  4192.                                 do {                                                    /* Find the entry links to the child directory */
  4193.                                         res = DIR_READ_FILE(&dj);
  4194.                                         if (res != FR_OK) break;
  4195.                                         if (ccl == ld_clust(fs, dj.dir)) break; /* Found the entry */
  4196.                                         res = dir_next(&dj, 0);
  4197.                                 } while (res == FR_OK);
  4198.                                 if (res == FR_NO_FILE) res = FR_INT_ERR;/* It cannot be 'not found'. */
  4199.                                 if (res != FR_OK) break;
  4200.                                 get_fileinfo(&dj, &fno);                /* Get the directory name and push it to the buffer */
  4201.                                 for (n = 0; fno.fname[n]; n++) ;        /* Name length */
  4202.                                 if (i < n + 1) {        /* Insufficient space to store the path name? */
  4203.                                         res = FR_NOT_ENOUGH_CORE; break;
  4204.                                 }
  4205.                                 while (n) buff[--i] = fno.fname[--n];   /* Stack the name */
  4206.                                 buff[--i] = '/';
  4207.                         }
  4208.                 }
  4209.                 if (res == FR_OK) {
  4210.                         if (i == len) buff[--i] = '/';  /* Is it the root-directory? */
  4211. #if FF_VOLUMES >= 2                     /* Put drive prefix */
  4212.                         vl = 0;
  4213. #if FF_STR_VOLUME_ID >= 1       /* String volume ID */
  4214.                         for (n = 0, vp = (const char*)VolumeStr[CurrVol]; vp[n]; n++) ;
  4215.                         if (i >= n + 2) {
  4216.                                 if (FF_STR_VOLUME_ID == 2) *tp++ = (TCHAR)'/';
  4217.                                 for (vl = 0; vl < n; *tp++ = (TCHAR)vp[vl], vl++) ;
  4218.                                 if (FF_STR_VOLUME_ID == 1) *tp++ = (TCHAR)':';
  4219.                                 vl++;
  4220.                         }
  4221. #else                                           /* Numeric volume ID */
  4222.                         if (i >= 3) {
  4223.                                 *tp++ = (TCHAR)'0' + CurrVol;
  4224.                                 *tp++ = (TCHAR)':';
  4225.                                 vl = 2;
  4226.                         }
  4227. #endif
  4228.                         if (vl == 0) res = FR_NOT_ENOUGH_CORE;
  4229. #endif
  4230.                         /* Add current directory path */
  4231.                         if (res == FR_OK) {
  4232.                                 do *tp++ = buff[i++]; while (i < len);  /* Copy stacked path string */
  4233.                         }
  4234.                 }
  4235.                 FREE_NAMBUF();
  4236.         }
  4237.  
  4238.         *tp = 0;
  4239.         LEAVE_FF(fs, res);
  4240. }
  4241.  
  4242. #endif /* FF_FS_RPATH >= 2 */
  4243. #endif /* FF_FS_RPATH >= 1 */
  4244.  
  4245.  
  4246.  
  4247. #if FF_FS_MINIMIZE <= 2
  4248. /*-----------------------------------------------------------------------*/
  4249. /* Seek File Read/Write Pointer                                          */
  4250. /*-----------------------------------------------------------------------*/
  4251.  
  4252. FRESULT f_lseek (
  4253.         FIL* fp,                /* Pointer to the file object */
  4254.         FSIZE_t ofs             /* File pointer from top of file */
  4255. )
  4256. {
  4257.         FRESULT res;
  4258.         FATFS *fs;
  4259.         DWORD clst, bcs, nsect;
  4260.         FSIZE_t ifptr;
  4261. #if FF_USE_FASTSEEK
  4262.         DWORD cl, pcl, ncl, tcl, dsc, tlen, ulen, *tbl;
  4263. #endif
  4264.  
  4265.         res = validate(&fp->obj, &fs);          /* Check validity of the file object */
  4266.         if (res == FR_OK) res = (FRESULT)fp->err;
  4267. #if FF_FS_EXFAT && !FF_FS_READONLY
  4268.         if (res == FR_OK && fs->fs_type == FS_EXFAT) {
  4269.                 res = fill_last_frag(&fp->obj, fp->clust, 0xFFFFFFFF);  /* Fill last fragment on the FAT if needed */
  4270.         }
  4271. #endif
  4272.         if (res != FR_OK) LEAVE_FF(fs, res);
  4273.  
  4274. #if FF_USE_FASTSEEK
  4275.         if (fp->cltbl) {        /* Fast seek */
  4276.                 if (ofs == CREATE_LINKMAP) {    /* Create CLMT */
  4277.                         tbl = fp->cltbl;
  4278.                         tlen = *tbl++; ulen = 2;        /* Given table size and required table size */
  4279.                         cl = fp->obj.sclust;            /* Origin of the chain */
  4280.                         if (cl != 0) {
  4281.                                 do {
  4282.                                         /* Get a fragment */
  4283.                                         tcl = cl; ncl = 0; ulen += 2;   /* Top, length and used items */
  4284.                                         do {
  4285.                                                 pcl = cl; ncl++;
  4286.                                                 cl = get_fat(&fp->obj, cl);
  4287.                                                 if (cl <= 1) ABORT(fs, FR_INT_ERR);
  4288.                                                 if (cl == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR);
  4289.                                         } while (cl == pcl + 1);
  4290.                                         if (ulen <= tlen) {             /* Store the length and top of the fragment */
  4291.                                                 *tbl++ = ncl; *tbl++ = tcl;
  4292.                                         }
  4293.                                 } while (cl < fs->n_fatent);    /* Repeat until end of chain */
  4294.                         }
  4295.                         *fp->cltbl = ulen;      /* Number of items used */
  4296.                         if (ulen <= tlen) {
  4297.                                 *tbl = 0;               /* Terminate table */
  4298.                         } else {
  4299.                                 res = FR_NOT_ENOUGH_CORE;       /* Given table size is smaller than required */
  4300.                         }
  4301.                 } else {                                                /* Fast seek */
  4302.                         if (ofs > fp->obj.objsize) ofs = fp->obj.objsize;       /* Clip offset at the file size */
  4303.                         fp->fptr = ofs;                         /* Set file pointer */
  4304.                         if (ofs > 0) {
  4305.                                 fp->clust = clmt_clust(fp, ofs - 1);
  4306.                                 dsc = clst2sect(fs, fp->clust);
  4307.                                 if (dsc == 0) ABORT(fs, FR_INT_ERR);
  4308.                                 dsc += (DWORD)((ofs - 1) / SS(fs)) & (fs->csize - 1);
  4309.                                 if (fp->fptr % SS(fs) && dsc != fp->sect) {     /* Refill sector cache if needed */
  4310. #if !FF_FS_TINY
  4311. #if !FF_FS_READONLY
  4312.                                         if (fp->flag & FA_DIRTY) {              /* Write-back dirty sector cache */
  4313.                                                 if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);
  4314.                                                 fp->flag &= (BYTE)~FA_DIRTY;
  4315.                                         }
  4316. #endif
  4317.                                         if (disk_read(fs->pdrv, fp->buf, dsc, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);     /* Load current sector */
  4318. #endif
  4319.                                         fp->sect = dsc;
  4320.                                 }
  4321.                         }
  4322.                 }
  4323.         } else
  4324. #endif
  4325.  
  4326.         /* Normal Seek */
  4327.         {
  4328. #if FF_FS_EXFAT
  4329.                 if (fs->fs_type != FS_EXFAT && ofs >= 0x100000000) ofs = 0xFFFFFFFF;    /* Clip at 4 GiB - 1 if at FATxx */
  4330. #endif
  4331.                 if (ofs > fp->obj.objsize && (FF_FS_READONLY || !(fp->flag & FA_WRITE))) {      /* In read-only mode, clip offset with the file size */
  4332.                         ofs = fp->obj.objsize;
  4333.                 }
  4334.                 ifptr = fp->fptr;
  4335.                 fp->fptr = nsect = 0;
  4336.                 if (ofs > 0) {
  4337.                         bcs = (DWORD)fs->csize * SS(fs);        /* Cluster size (byte) */
  4338.                         if (ifptr > 0 &&
  4339.                                 (ofs - 1) / bcs >= (ifptr - 1) / bcs) { /* When seek to same or following cluster, */
  4340.                                 fp->fptr = (ifptr - 1) & ~(FSIZE_t)(bcs - 1);   /* start from the current cluster */
  4341.                                 ofs -= fp->fptr;
  4342.                                 clst = fp->clust;
  4343.                         } else {                                                                        /* When seek to back cluster, */
  4344.                                 clst = fp->obj.sclust;                                  /* start from the first cluster */
  4345. #if !FF_FS_READONLY
  4346.                                 if (clst == 0) {                                                /* If no cluster chain, create a new chain */
  4347.                                         clst = create_chain(&fp->obj, 0);
  4348.                                         if (clst == 1) ABORT(fs, FR_INT_ERR);
  4349.                                         if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR);
  4350.                                         fp->obj.sclust = clst;
  4351.                                 }
  4352. #endif
  4353.                                 fp->clust = clst;
  4354.                         }
  4355.                         if (clst != 0) {
  4356.                                 while (ofs > bcs) {                                             /* Cluster following loop */
  4357.                                         ofs -= bcs; fp->fptr += bcs;
  4358. #if !FF_FS_READONLY
  4359.                                         if (fp->flag & FA_WRITE) {                      /* Check if in write mode or not */
  4360.                                                 if (FF_FS_EXFAT && fp->fptr > fp->obj.objsize) {        /* No FAT chain object needs correct objsize to generate FAT value */
  4361.                                                         fp->obj.objsize = fp->fptr;
  4362.                                                         fp->flag |= FA_MODIFIED;
  4363.                                                 }
  4364.                                                 clst = create_chain(&fp->obj, clst);    /* Follow chain with forceed stretch */
  4365.                                                 if (clst == 0) {                                /* Clip file size in case of disk full */
  4366.                                                         ofs = 0; break;
  4367.                                                 }
  4368.                                         } else
  4369. #endif
  4370.                                         {
  4371.                                                 clst = get_fat(&fp->obj, clst); /* Follow cluster chain if not in write mode */
  4372.                                         }
  4373.                                         if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR);
  4374.                                         if (clst <= 1 || clst >= fs->n_fatent) ABORT(fs, FR_INT_ERR);
  4375.                                         fp->clust = clst;
  4376.                                 }
  4377.                                 fp->fptr += ofs;
  4378.                                 if (ofs % SS(fs)) {
  4379.                                         nsect = clst2sect(fs, clst);    /* Current sector */
  4380.                                         if (nsect == 0) ABORT(fs, FR_INT_ERR);
  4381.                                         nsect += (DWORD)(ofs / SS(fs));
  4382.                                 }
  4383.                         }
  4384.                 }
  4385.                 if (!FF_FS_READONLY && fp->fptr > fp->obj.objsize) {    /* Set file change flag if the file size is extended */
  4386.                         fp->obj.objsize = fp->fptr;
  4387.                         fp->flag |= FA_MODIFIED;
  4388.                 }
  4389.                 if (fp->fptr % SS(fs) && nsect != fp->sect) {   /* Fill sector cache if needed */
  4390. #if !FF_FS_TINY
  4391. #if !FF_FS_READONLY
  4392.                         if (fp->flag & FA_DIRTY) {                      /* Write-back dirty sector cache */
  4393.                                 if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);
  4394.                                 fp->flag &= (BYTE)~FA_DIRTY;
  4395.                         }
  4396. #endif
  4397.                         if (disk_read(fs->pdrv, fp->buf, nsect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);   /* Fill sector cache */
  4398. #endif
  4399.                         fp->sect = nsect;
  4400.                 }
  4401.         }
  4402.  
  4403.         LEAVE_FF(fs, res);
  4404. }
  4405.  
  4406.  
  4407.  
  4408. #if FF_FS_MINIMIZE <= 1
  4409. /*-----------------------------------------------------------------------*/
  4410. /* Create a Directory Object                                             */
  4411. /*-----------------------------------------------------------------------*/
  4412.  
  4413. FRESULT f_opendir (
  4414.         DIR* dp,                        /* Pointer to directory object to create */
  4415.         const TCHAR* path       /* Pointer to the directory path */
  4416. )
  4417. {
  4418.         FRESULT res;
  4419.         FATFS *fs;
  4420.         DEF_NAMBUF
  4421.  
  4422.  
  4423.         if (!dp) return FR_INVALID_OBJECT;
  4424.  
  4425.         /* Get logical drive */
  4426.         res = find_volume(&path, &fs, 0);
  4427.         if (res == FR_OK) {
  4428.                 dp->obj.fs = fs;
  4429.                 INIT_NAMBUF(fs);
  4430.                 res = follow_path(dp, path);                    /* Follow the path to the directory */
  4431.                 if (res == FR_OK) {                                             /* Follow completed */
  4432.                         if (!(dp->fn[NSFLAG] & NS_NONAME)) {    /* It is not the origin directory itself */
  4433.                                 if (dp->obj.attr & AM_DIR) {            /* This object is a sub-directory */
  4434. #if FF_FS_EXFAT
  4435.                                         if (fs->fs_type == FS_EXFAT) {
  4436.                                                 dp->obj.c_scl = dp->obj.sclust;                                                 /* Get containing directory inforamation */
  4437.                                                 dp->obj.c_size = ((DWORD)dp->obj.objsize & 0xFFFFFF00) | dp->obj.stat;
  4438.                                                 dp->obj.c_ofs = dp->blk_ofs;
  4439.                                                 init_alloc_info(fs, &dp->obj);  /* Get object allocation info */
  4440.                                         } else
  4441. #endif
  4442.                                         {
  4443.                                                 dp->obj.sclust = ld_clust(fs, dp->dir); /* Get object allocation info */
  4444.                                         }
  4445.                                 } else {                                                /* This object is a file */
  4446.                                         res = FR_NO_PATH;
  4447.                                 }
  4448.                         }
  4449.                         if (res == FR_OK) {
  4450.                                 dp->obj.id = fs->id;
  4451.                                 res = dir_sdi(dp, 0);                   /* Rewind directory */
  4452. #if FF_FS_LOCK != 0
  4453.                                 if (res == FR_OK) {
  4454.                                         if (dp->obj.sclust != 0) {
  4455.                                                 dp->obj.lockid = inc_lock(dp, 0);       /* Lock the sub directory */
  4456.                                                 if (!dp->obj.lockid) res = FR_TOO_MANY_OPEN_FILES;
  4457.                                         } else {
  4458.                                                 dp->obj.lockid = 0;     /* Root directory need not to be locked */
  4459.                                         }
  4460.                                 }
  4461. #endif
  4462.                         }
  4463.                 }
  4464.                 FREE_NAMBUF();
  4465.                 if (res == FR_NO_FILE) res = FR_NO_PATH;
  4466.         }
  4467.         if (res != FR_OK) dp->obj.fs = 0;               /* Invalidate the directory object if function faild */
  4468.  
  4469.         LEAVE_FF(fs, res);
  4470. }
  4471.  
  4472.  
  4473.  
  4474.  
  4475. /*-----------------------------------------------------------------------*/
  4476. /* Close Directory                                                       */
  4477. /*-----------------------------------------------------------------------*/
  4478.  
  4479. FRESULT f_closedir (
  4480.         DIR *dp         /* Pointer to the directory object to be closed */
  4481. )
  4482. {
  4483.         FRESULT res;
  4484.         FATFS *fs;
  4485.  
  4486.  
  4487.         res = validate(&dp->obj, &fs);  /* Check validity of the file object */
  4488.         if (res == FR_OK) {
  4489. #if FF_FS_LOCK != 0
  4490.                 if (dp->obj.lockid) res = dec_lock(dp->obj.lockid);     /* Decrement sub-directory open counter */
  4491.                 if (res == FR_OK) dp->obj.fs = 0;       /* Invalidate directory object */
  4492. #else
  4493.                 dp->obj.fs = 0; /* Invalidate directory object */
  4494. #endif
  4495. #if FF_FS_REENTRANT
  4496.                 unlock_fs(fs, FR_OK);           /* Unlock volume */
  4497. #endif
  4498.         }
  4499.         return res;
  4500. }
  4501.  
  4502.  
  4503.  
  4504.  
  4505. /*-----------------------------------------------------------------------*/
  4506. /* Read Directory Entries in Sequence                                    */
  4507. /*-----------------------------------------------------------------------*/
  4508.  
  4509. FRESULT f_readdir (
  4510.         DIR* dp,                        /* Pointer to the open directory object */
  4511.         FILINFO* fno            /* Pointer to file information to return */
  4512. )
  4513. {
  4514.         FRESULT res;
  4515.         FATFS *fs;
  4516.         DEF_NAMBUF
  4517.  
  4518.  
  4519.         res = validate(&dp->obj, &fs);  /* Check validity of the directory object */
  4520.         if (res == FR_OK) {
  4521.                 if (!fno) {
  4522.                         res = dir_sdi(dp, 0);                   /* Rewind the directory object */
  4523.                 } else {
  4524.                         INIT_NAMBUF(fs);
  4525.                         res = DIR_READ_FILE(dp);                /* Read an item */
  4526.                         if (res == FR_NO_FILE) res = FR_OK;     /* Ignore end of directory */
  4527.                         if (res == FR_OK) {                             /* A valid entry is found */
  4528.                                 get_fileinfo(dp, fno);          /* Get the object information */
  4529.                                 res = dir_next(dp, 0);          /* Increment index for next */
  4530.                                 if (res == FR_NO_FILE) res = FR_OK;     /* Ignore end of directory now */
  4531.                         }
  4532.                         FREE_NAMBUF();
  4533.                 }
  4534.         }
  4535.         LEAVE_FF(fs, res);
  4536. }
  4537.  
  4538.  
  4539.  
  4540. #if FF_USE_FIND
  4541. /*-----------------------------------------------------------------------*/
  4542. /* Find Next File                                                        */
  4543. /*-----------------------------------------------------------------------*/
  4544.  
  4545. FRESULT f_findnext (
  4546.         DIR* dp,                /* Pointer to the open directory object */
  4547.         FILINFO* fno    /* Pointer to the file information structure */
  4548. )
  4549. {
  4550.         FRESULT res;
  4551.  
  4552.  
  4553.         for (;;) {
  4554.                 res = f_readdir(dp, fno);               /* Get a directory item */
  4555.                 if (res != FR_OK || !fno || !fno->fname[0]) break;      /* Terminate if any error or end of directory */
  4556.                 if (pattern_matching(dp->pat, fno->fname, 0, 0)) break;         /* Test for the file name */
  4557. #if FF_USE_LFN && FF_USE_FIND == 2
  4558.                 if (pattern_matching(dp->pat, fno->altname, 0, 0)) break;       /* Test for alternative name if exist */
  4559. #endif
  4560.         }
  4561.         return res;
  4562. }
  4563.  
  4564.  
  4565.  
  4566. /*-----------------------------------------------------------------------*/
  4567. /* Find First File                                                       */
  4568. /*-----------------------------------------------------------------------*/
  4569.  
  4570. FRESULT f_findfirst (
  4571.         DIR* dp,                                /* Pointer to the blank directory object */
  4572.         FILINFO* fno,                   /* Pointer to the file information structure */
  4573.         const TCHAR* path,              /* Pointer to the directory to open */
  4574.         const TCHAR* pattern    /* Pointer to the matching pattern */
  4575. )
  4576. {
  4577.         FRESULT res;
  4578.  
  4579.  
  4580.         dp->pat = pattern;              /* Save pointer to pattern string */
  4581.         res = f_opendir(dp, path);              /* Open the target directory */
  4582.         if (res == FR_OK) {
  4583.                 res = f_findnext(dp, fno);      /* Find the first item */
  4584.         }
  4585.         return res;
  4586. }
  4587.  
  4588. #endif  /* FF_USE_FIND */
  4589.  
  4590.  
  4591.  
  4592. #if FF_FS_MINIMIZE == 0
  4593. /*-----------------------------------------------------------------------*/
  4594. /* Get File Status                                                       */
  4595. /*-----------------------------------------------------------------------*/
  4596.  
  4597. FRESULT f_stat (
  4598.         const TCHAR* path,      /* Pointer to the file path */
  4599.         FILINFO* fno            /* Pointer to file information to return */
  4600. )
  4601. {
  4602.         FRESULT res;
  4603.         DIR dj;
  4604.         DEF_NAMBUF
  4605.  
  4606.  
  4607.         /* Get logical drive */
  4608.         res = find_volume(&path, &dj.obj.fs, 0);
  4609.         if (res == FR_OK) {
  4610.                 INIT_NAMBUF(dj.obj.fs);
  4611.                 res = follow_path(&dj, path);   /* Follow the file path */
  4612.                 if (res == FR_OK) {                             /* Follow completed */
  4613.                         if (dj.fn[NSFLAG] & NS_NONAME) {        /* It is origin directory */
  4614.                                 res = FR_INVALID_NAME;
  4615.                         } else {                                                        /* Found an object */
  4616.                                 if (fno) get_fileinfo(&dj, fno);
  4617.                         }
  4618.                 }
  4619.                 FREE_NAMBUF();
  4620.         }
  4621.  
  4622.         LEAVE_FF(dj.obj.fs, res);
  4623. }
  4624.  
  4625.  
  4626.  
  4627. #if !FF_FS_READONLY
  4628. /*-----------------------------------------------------------------------*/
  4629. /* Get Number of Free Clusters                                           */
  4630. /*-----------------------------------------------------------------------*/
  4631.  
  4632. FRESULT f_getfree (
  4633.         const TCHAR* path,      /* Logical drive number */
  4634.         DWORD* nclst,           /* Pointer to a variable to return number of free clusters */
  4635.         FATFS** fatfs           /* Pointer to return pointer to corresponding filesystem object */
  4636. )
  4637. {
  4638.         FRESULT res;
  4639.         FATFS *fs;
  4640.         DWORD nfree, clst, sect, stat;
  4641.         UINT i;
  4642.         FFOBJID obj;
  4643.  
  4644.  
  4645.         /* Get logical drive */
  4646.         res = find_volume(&path, &fs, 0);
  4647.         if (res == FR_OK) {
  4648.                 *fatfs = fs;                            /* Return ptr to the fs object */
  4649.                 /* If free_clst is valid, return it without full FAT scan */
  4650.                 if (fs->free_clst <= fs->n_fatent - 2) {
  4651.                         *nclst = fs->free_clst;
  4652.                 } else {
  4653.                         /* Scan FAT to obtain number of free clusters */
  4654.                         nfree = 0;
  4655.                         if (fs->fs_type == FS_FAT12) {  /* FAT12: Scan bit field FAT entries */
  4656.                                 clst = 2; obj.fs = fs;
  4657.                                 do {
  4658.                                         stat = get_fat(&obj, clst);
  4659.                                         if (stat == 0xFFFFFFFF) { res = FR_DISK_ERR; break; }
  4660.                                         if (stat == 1) { res = FR_INT_ERR; break; }
  4661.                                         if (stat == 0) nfree++;
  4662.                                 } while (++clst < fs->n_fatent);
  4663.                         } else {
  4664. #if FF_FS_EXFAT
  4665.                                 if (fs->fs_type == FS_EXFAT) {  /* exFAT: Scan allocation bitmap */
  4666.                                         BYTE bm;
  4667.                                         UINT b;
  4668.  
  4669.                                         clst = fs->n_fatent - 2;        /* Number of clusters */
  4670.                                         sect = fs->bitbase;                     /* Bitmap sector */
  4671.                                         i = 0;                                          /* Offset in the sector */
  4672.                                         do {    /* Counts numbuer of bits with zero in the bitmap */
  4673.                                                 if (i == 0) {
  4674.                                                         res = move_window(fs, sect++);
  4675.                                                         if (res != FR_OK) break;
  4676.                                                 }
  4677.                                                 for (b = 8, bm = fs->win[i]; b && clst; b--, clst--) {
  4678.                                                         if (!(bm & 1)) nfree++;
  4679.                                                         bm >>= 1;
  4680.                                                 }
  4681.                                                 i = (i + 1) % SS(fs);
  4682.                                         } while (clst);
  4683.                                 } else
  4684. #endif
  4685.                                 {       /* FAT16/32: Scan WORD/DWORD FAT entries */
  4686.                                         clst = fs->n_fatent;    /* Number of entries */
  4687.                                         sect = fs->fatbase;             /* Top of the FAT */
  4688.                                         i = 0;                                  /* Offset in the sector */
  4689.                                         do {    /* Counts numbuer of entries with zero in the FAT */
  4690.                                                 if (i == 0) {
  4691.                                                         res = move_window(fs, sect++);
  4692.                                                         if (res != FR_OK) break;
  4693.                                                 }
  4694.                                                 if (fs->fs_type == FS_FAT16) {
  4695.                                                         if (ld_word(fs->win + i) == 0) nfree++;
  4696.                                                         i += 2;
  4697.                                                 } else {
  4698.                                                         if ((ld_dword(fs->win + i) & 0x0FFFFFFF) == 0) nfree++;
  4699.                                                         i += 4;
  4700.                                                 }
  4701.                                                 i %= SS(fs);
  4702.                                         } while (--clst);
  4703.                                 }
  4704.                         }
  4705.                         *nclst = nfree;                 /* Return the free clusters */
  4706.                         fs->free_clst = nfree;  /* Now free_clst is valid */
  4707.                         fs->fsi_flag |= 1;              /* FAT32: FSInfo is to be updated */
  4708.                 }
  4709.         }
  4710.  
  4711.         LEAVE_FF(fs, res);
  4712. }
  4713.  
  4714.  
  4715.  
  4716.  
  4717. /*-----------------------------------------------------------------------*/
  4718. /* Truncate File                                                         */
  4719. /*-----------------------------------------------------------------------*/
  4720.  
  4721. FRESULT f_truncate (
  4722.         FIL* fp         /* Pointer to the file object */
  4723. )
  4724. {
  4725.         FRESULT res;
  4726.         FATFS *fs;
  4727.         DWORD ncl;
  4728.  
  4729.  
  4730.         res = validate(&fp->obj, &fs);  /* Check validity of the file object */
  4731.         if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res);
  4732.         if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED);    /* Check access mode */
  4733.  
  4734.         if (fp->fptr < fp->obj.objsize) {       /* Process when fptr is not on the eof */
  4735.                 if (fp->fptr == 0) {    /* When set file size to zero, remove entire cluster chain */
  4736.                         res = remove_chain(&fp->obj, fp->obj.sclust, 0);
  4737.                         fp->obj.sclust = 0;
  4738.                 } else {                                /* When truncate a part of the file, remove remaining clusters */
  4739.                         ncl = get_fat(&fp->obj, fp->clust);
  4740.                         res = FR_OK;
  4741.                         if (ncl == 0xFFFFFFFF) res = FR_DISK_ERR;
  4742.                         if (ncl == 1) res = FR_INT_ERR;
  4743.                         if (res == FR_OK && ncl < fs->n_fatent) {
  4744.                                 res = remove_chain(&fp->obj, ncl, fp->clust);
  4745.                         }
  4746.                 }
  4747.                 fp->obj.objsize = fp->fptr;     /* Set file size to current read/write point */
  4748.                 fp->flag |= FA_MODIFIED;
  4749. #if !FF_FS_TINY
  4750.                 if (res == FR_OK && (fp->flag & FA_DIRTY)) {
  4751.                         if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) {
  4752.                                 res = FR_DISK_ERR;
  4753.                         } else {
  4754.                                 fp->flag &= (BYTE)~FA_DIRTY;
  4755.                         }
  4756.                 }
  4757. #endif
  4758.                 if (res != FR_OK) ABORT(fs, res);
  4759.         }
  4760.  
  4761.         LEAVE_FF(fs, res);
  4762. }
  4763.  
  4764.  
  4765.  
  4766.  
  4767. /*-----------------------------------------------------------------------*/
  4768. /* Delete a File/Directory                                               */
  4769. /*-----------------------------------------------------------------------*/
  4770.  
  4771. FRESULT f_unlink (
  4772.         const TCHAR* path               /* Pointer to the file or directory path */
  4773. )
  4774. {
  4775.         FRESULT res;
  4776.         DIR dj, sdj;
  4777.         DWORD dclst = 0;
  4778.         FATFS *fs;
  4779. #if FF_FS_EXFAT
  4780.         FFOBJID obj;
  4781. #endif
  4782.         DEF_NAMBUF
  4783.  
  4784.  
  4785.         /* Get logical drive */
  4786.         res = find_volume(&path, &fs, FA_WRITE);
  4787.         if (res == FR_OK) {
  4788.                 dj.obj.fs = fs;
  4789.                 INIT_NAMBUF(fs);
  4790.                 res = follow_path(&dj, path);           /* Follow the file path */
  4791.                 if (FF_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) {
  4792.                         res = FR_INVALID_NAME;                  /* Cannot remove dot entry */
  4793.                 }
  4794. #if FF_FS_LOCK != 0
  4795.                 if (res == FR_OK) res = chk_lock(&dj, 2);       /* Check if it is an open object */
  4796. #endif
  4797.                 if (res == FR_OK) {                                     /* The object is accessible */
  4798.                         if (dj.fn[NSFLAG] & NS_NONAME) {
  4799.                                 res = FR_INVALID_NAME;          /* Cannot remove the origin directory */
  4800.                         } else {
  4801.                                 if (dj.obj.attr & AM_RDO) {
  4802.                                         res = FR_DENIED;                /* Cannot remove R/O object */
  4803.                                 }
  4804.                         }
  4805.                         if (res == FR_OK) {
  4806. #if FF_FS_EXFAT
  4807.                                 obj.fs = fs;
  4808.                                 if (fs->fs_type == FS_EXFAT) {
  4809.                                         init_alloc_info(fs, &obj);
  4810.                                         dclst = obj.sclust;
  4811.                                 } else
  4812. #endif
  4813.                                 {
  4814.                                         dclst = ld_clust(fs, dj.dir);
  4815.                                 }
  4816.                                 if (dj.obj.attr & AM_DIR) {                     /* Is it a sub-directory? */
  4817. #if FF_FS_RPATH != 0
  4818.                                         if (dclst == fs->cdir) {                        /* Is it the current directory? */
  4819.                                                 res = FR_DENIED;
  4820.                                         } else
  4821. #endif
  4822.                                         {
  4823.                                                 sdj.obj.fs = fs;                                /* Open the sub-directory */
  4824.                                                 sdj.obj.sclust = dclst;
  4825. #if FF_FS_EXFAT
  4826.                                                 if (fs->fs_type == FS_EXFAT) {
  4827.                                                         sdj.obj.objsize = obj.objsize;
  4828.                                                         sdj.obj.stat = obj.stat;
  4829.                                                 }
  4830. #endif
  4831.                                                 res = dir_sdi(&sdj, 0);
  4832.                                                 if (res == FR_OK) {
  4833.                                                         res = DIR_READ_FILE(&sdj);                      /* Test if the directory is empty */
  4834.                                                         if (res == FR_OK) res = FR_DENIED;      /* Not empty? */
  4835.                                                         if (res == FR_NO_FILE) res = FR_OK;     /* Empty? */
  4836.                                                 }
  4837.                                         }
  4838.                                 }
  4839.                         }
  4840.                         if (res == FR_OK) {
  4841.                                 res = dir_remove(&dj);                  /* Remove the directory entry */
  4842.                                 if (res == FR_OK && dclst != 0) {       /* Remove the cluster chain if exist */
  4843. #if FF_FS_EXFAT
  4844.                                         res = remove_chain(&obj, dclst, 0);
  4845. #else
  4846.                                         res = remove_chain(&dj.obj, dclst, 0);
  4847. #endif
  4848.                                 }
  4849.                                 if (res == FR_OK) res = sync_fs(fs);
  4850.                         }
  4851.                 }
  4852.                 FREE_NAMBUF();
  4853.         }
  4854.  
  4855.         LEAVE_FF(fs, res);
  4856. }
  4857.  
  4858.  
  4859.  
  4860.  
  4861. /*-----------------------------------------------------------------------*/
  4862. /* Create a Directory                                                    */
  4863. /*-----------------------------------------------------------------------*/
  4864.  
  4865. FRESULT f_mkdir (
  4866.         const TCHAR* path               /* Pointer to the directory path */
  4867. )
  4868. {
  4869.         FRESULT res;
  4870.         DIR dj;
  4871.         FFOBJID sobj;
  4872.         FATFS *fs;
  4873.         DWORD dcl, pcl, tm;
  4874.         DEF_NAMBUF
  4875.  
  4876.  
  4877.         res = find_volume(&path, &fs, FA_WRITE);        /* Get logical drive */
  4878.         if (res == FR_OK) {
  4879.                 dj.obj.fs = fs;
  4880.                 INIT_NAMBUF(fs);
  4881.                 res = follow_path(&dj, path);                   /* Follow the file path */
  4882.                 if (res == FR_OK) res = FR_EXIST;               /* Name collision? */
  4883.                 if (FF_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) {     /* Invalid name? */
  4884.                         res = FR_INVALID_NAME;
  4885.                 }
  4886.                 if (res == FR_NO_FILE) {                                /* It is clear to create a new directory */
  4887.                         sobj.fs = fs;                                           /* New object id to create a new chain */
  4888.                         dcl = create_chain(&sobj, 0);           /* Allocate a cluster for the new directory */
  4889.                         res = FR_OK;
  4890.                         if (dcl == 0) res = FR_DENIED;          /* No space to allocate a new cluster? */
  4891.                         if (dcl == 1) res = FR_INT_ERR;         /* Any insanity? */
  4892.                         if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR;       /* Disk error? */
  4893.                         tm = GET_FATTIME();
  4894.                         if (res == FR_OK) {
  4895.                                 res = dir_clear(fs, dcl);               /* Clean up the new table */
  4896.                                 if (res == FR_OK) {
  4897.                                         if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) {  /* Create dot entries (FAT only) */
  4898.                                                 mem_set(fs->win + DIR_Name, ' ', 11);   /* Create "." entry */
  4899.                                                 fs->win[DIR_Name] = '.';
  4900.                                                 fs->win[DIR_Attr] = AM_DIR;
  4901.                                                 st_dword(fs->win + DIR_ModTime, tm);
  4902.                                                 st_clust(fs, fs->win, dcl);
  4903.                                                 mem_cpy(fs->win + SZDIRE, fs->win, SZDIRE); /* Create ".." entry */
  4904.                                                 fs->win[SZDIRE + 1] = '.'; pcl = dj.obj.sclust;
  4905.                                                 st_clust(fs, fs->win + SZDIRE, pcl);
  4906.                                                 fs->wflag = 1;
  4907.                                         }
  4908.                                         res = dir_register(&dj);        /* Register the object to the parent directoy */
  4909.                                 }
  4910.                         }
  4911.                         if (res == FR_OK) {
  4912. #if FF_FS_EXFAT
  4913.                                 if (fs->fs_type == FS_EXFAT) {  /* Initialize directory entry block */
  4914.                                         st_dword(fs->dirbuf + XDIR_ModTime, tm);        /* Created time */
  4915.                                         st_dword(fs->dirbuf + XDIR_FstClus, dcl);       /* Table start cluster */
  4916.                                         st_dword(fs->dirbuf + XDIR_FileSize, (DWORD)fs->csize * SS(fs));        /* File size needs to be valid */
  4917.                                         st_dword(fs->dirbuf + XDIR_ValidFileSize, (DWORD)fs->csize * SS(fs));
  4918.                                         fs->dirbuf[XDIR_GenFlags] = 3;                          /* Initialize the object flag */
  4919.                                         fs->dirbuf[XDIR_Attr] = AM_DIR;                         /* Attribute */
  4920.                                         res = store_xdir(&dj);
  4921.                                 } else
  4922. #endif
  4923.                                 {
  4924.                                         st_dword(dj.dir + DIR_ModTime, tm);     /* Created time */
  4925.                                         st_clust(fs, dj.dir, dcl);                      /* Table start cluster */
  4926.                                         dj.dir[DIR_Attr] = AM_DIR;                      /* Attribute */
  4927.                                         fs->wflag = 1;
  4928.                                 }
  4929.                                 if (res == FR_OK) {
  4930.                                         res = sync_fs(fs);
  4931.                                 }
  4932.                         } else {
  4933.                                 remove_chain(&sobj, dcl, 0);            /* Could not register, remove the allocated cluster */
  4934.                         }
  4935.                 }
  4936.                 FREE_NAMBUF();
  4937.         }
  4938.  
  4939.         LEAVE_FF(fs, res);
  4940. }
  4941.  
  4942.  
  4943.  
  4944.  
  4945. /*-----------------------------------------------------------------------*/
  4946. /* Rename a File/Directory                                               */
  4947. /*-----------------------------------------------------------------------*/
  4948.  
  4949. FRESULT f_rename (
  4950.         const TCHAR* path_old,  /* Pointer to the object name to be renamed */
  4951.         const TCHAR* path_new   /* Pointer to the new name */
  4952. )
  4953. {
  4954.         FRESULT res;
  4955.         DIR djo, djn;
  4956.         FATFS *fs;
  4957.         BYTE buf[FF_FS_EXFAT ? SZDIRE * 2 : SZDIRE], *dir;
  4958.         DWORD dw;
  4959.         DEF_NAMBUF
  4960.  
  4961.  
  4962.         get_ldnumber(&path_new);                                                /* Snip the drive number of new name off */
  4963.         res = find_volume(&path_old, &fs, FA_WRITE);    /* Get logical drive of the old object */
  4964.         if (res == FR_OK) {
  4965.                 djo.obj.fs = fs;
  4966.                 INIT_NAMBUF(fs);
  4967.                 res = follow_path(&djo, path_old);              /* Check old object */
  4968.                 if (res == FR_OK && (djo.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME;     /* Check validity of name */
  4969. #if FF_FS_LOCK != 0
  4970.                 if (res == FR_OK) {
  4971.                         res = chk_lock(&djo, 2);
  4972.                 }
  4973. #endif
  4974.                 if (res == FR_OK) {                                             /* Object to be renamed is found */
  4975. #if FF_FS_EXFAT
  4976.                         if (fs->fs_type == FS_EXFAT) {  /* At exFAT volume */
  4977.                                 BYTE nf, nn;
  4978.                                 WORD nh;
  4979.  
  4980.                                 mem_cpy(buf, fs->dirbuf, SZDIRE * 2);   /* Save 85+C0 entry of old object */
  4981.                                 mem_cpy(&djn, &djo, sizeof djo);
  4982.                                 res = follow_path(&djn, path_new);              /* Make sure if new object name is not in use */
  4983.                                 if (res == FR_OK) {                                             /* Is new name already in use by any other object? */
  4984.                                         res = (djn.obj.sclust == djo.obj.sclust && djn.dptr == djo.dptr) ? FR_NO_FILE : FR_EXIST;
  4985.                                 }
  4986.                                 if (res == FR_NO_FILE) {                                /* It is a valid path and no name collision */
  4987.                                         res = dir_register(&djn);                       /* Register the new entry */
  4988.                                         if (res == FR_OK) {
  4989.                                                 nf = fs->dirbuf[XDIR_NumSec]; nn = fs->dirbuf[XDIR_NumName];
  4990.                                                 nh = ld_word(fs->dirbuf + XDIR_NameHash);
  4991.                                                 mem_cpy(fs->dirbuf, buf, SZDIRE * 2);   /* Restore 85+C0 entry */
  4992.                                                 fs->dirbuf[XDIR_NumSec] = nf; fs->dirbuf[XDIR_NumName] = nn;
  4993.                                                 st_word(fs->dirbuf + XDIR_NameHash, nh);
  4994.                                                 if (!(fs->dirbuf[XDIR_Attr] & AM_DIR)) fs->dirbuf[XDIR_Attr] |= AM_ARC; /* Set archive attribute if it is a file */
  4995. /* Start of critical section where an interruption can cause a cross-link */
  4996.                                                 res = store_xdir(&djn);
  4997.                                         }
  4998.                                 }
  4999.                         } else
  5000. #endif
  5001.                         {       /* At FAT/FAT32 volume */
  5002.                                 mem_cpy(buf, djo.dir, SZDIRE);                  /* Save directory entry of the object */
  5003.                                 mem_cpy(&djn, &djo, sizeof (DIR));              /* Duplicate the directory object */
  5004.                                 res = follow_path(&djn, path_new);              /* Make sure if new object name is not in use */
  5005.                                 if (res == FR_OK) {                                             /* Is new name already in use by any other object? */
  5006.                                         res = (djn.obj.sclust == djo.obj.sclust && djn.dptr == djo.dptr) ? FR_NO_FILE : FR_EXIST;
  5007.                                 }
  5008.                                 if (res == FR_NO_FILE) {                                /* It is a valid path and no name collision */
  5009.                                         res = dir_register(&djn);                       /* Register the new entry */
  5010.                                         if (res == FR_OK) {
  5011.                                                 dir = djn.dir;                                  /* Copy directory entry of the object except name */
  5012.                                                 mem_cpy(dir + 13, buf + 13, SZDIRE - 13);
  5013.                                                 dir[DIR_Attr] = buf[DIR_Attr];
  5014.                                                 if (!(dir[DIR_Attr] & AM_DIR)) dir[DIR_Attr] |= AM_ARC; /* Set archive attribute if it is a file */
  5015.                                                 fs->wflag = 1;
  5016.                                                 if ((dir[DIR_Attr] & AM_DIR) && djo.obj.sclust != djn.obj.sclust) {     /* Update .. entry in the sub-directory if needed */
  5017.                                                         dw = clst2sect(fs, ld_clust(fs, dir));
  5018.                                                         if (dw == 0) {
  5019.                                                                 res = FR_INT_ERR;
  5020.                                                         } else {
  5021. /* Start of critical section where an interruption can cause a cross-link */
  5022.                                                                 res = move_window(fs, dw);
  5023.                                                                 dir = fs->win + SZDIRE * 1;     /* Ptr to .. entry */
  5024.                                                                 if (res == FR_OK && dir[1] == '.') {
  5025.                                                                         st_clust(fs, dir, djn.obj.sclust);
  5026.                                                                         fs->wflag = 1;
  5027.                                                                 }
  5028.                                                         }
  5029.                                                 }
  5030.                                         }
  5031.                                 }
  5032.                         }
  5033.                         if (res == FR_OK) {
  5034.                                 res = dir_remove(&djo);         /* Remove old entry */
  5035.                                 if (res == FR_OK) {
  5036.                                         res = sync_fs(fs);
  5037.                                 }
  5038.                         }
  5039. /* End of the critical section */
  5040.                 }
  5041.                 FREE_NAMBUF();
  5042.         }
  5043.  
  5044.         LEAVE_FF(fs, res);
  5045. }
  5046.  
  5047. #endif /* !FF_FS_READONLY */
  5048. #endif /* FF_FS_MINIMIZE == 0 */
  5049. #endif /* FF_FS_MINIMIZE <= 1 */
  5050. #endif /* FF_FS_MINIMIZE <= 2 */
  5051.  
  5052.  
  5053.  
  5054. #if FF_USE_CHMOD && !FF_FS_READONLY
  5055. /*-----------------------------------------------------------------------*/
  5056. /* Change Attribute                                                      */
  5057. /*-----------------------------------------------------------------------*/
  5058.  
  5059. FRESULT f_chmod (
  5060.         const TCHAR* path,      /* Pointer to the file path */
  5061.         BYTE attr,                      /* Attribute bits */
  5062.         BYTE mask                       /* Attribute mask to change */
  5063. )
  5064. {
  5065.         FRESULT res;
  5066.         DIR dj;
  5067.         FATFS *fs;
  5068.         DEF_NAMBUF
  5069.  
  5070.  
  5071.         res = find_volume(&path, &fs, FA_WRITE);        /* Get logical drive */
  5072.         if (res == FR_OK) {
  5073.                 dj.obj.fs = fs;
  5074.                 INIT_NAMBUF(fs);
  5075.                 res = follow_path(&dj, path);   /* Follow the file path */
  5076.                 if (res == FR_OK && (dj.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME;      /* Check object validity */
  5077.                 if (res == FR_OK) {
  5078.                         mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC;    /* Valid attribute mask */
  5079. #if FF_FS_EXFAT
  5080.                         if (fs->fs_type == FS_EXFAT) {
  5081.                                 fs->dirbuf[XDIR_Attr] = (attr & mask) | (fs->dirbuf[XDIR_Attr] & (BYTE)~mask);  /* Apply attribute change */
  5082.                                 res = store_xdir(&dj);
  5083.                         } else
  5084. #endif
  5085.                         {
  5086.                                 dj.dir[DIR_Attr] = (attr & mask) | (dj.dir[DIR_Attr] & (BYTE)~mask);    /* Apply attribute change */
  5087.                                 fs->wflag = 1;
  5088.                         }
  5089.                         if (res == FR_OK) {
  5090.                                 res = sync_fs(fs);
  5091.                         }
  5092.                 }
  5093.                 FREE_NAMBUF();
  5094.         }
  5095.  
  5096.         LEAVE_FF(fs, res);
  5097. }
  5098.  
  5099.  
  5100.  
  5101.  
  5102. /*-----------------------------------------------------------------------*/
  5103. /* Change Timestamp                                                      */
  5104. /*-----------------------------------------------------------------------*/
  5105.  
  5106. FRESULT f_utime (
  5107.         const TCHAR* path,      /* Pointer to the file/directory name */
  5108.         const FILINFO* fno      /* Pointer to the timestamp to be set */
  5109. )
  5110. {
  5111.         FRESULT res;
  5112.         DIR dj;
  5113.         FATFS *fs;
  5114.         DEF_NAMBUF
  5115.  
  5116.  
  5117.         res = find_volume(&path, &fs, FA_WRITE);        /* Get logical drive */
  5118.         if (res == FR_OK) {
  5119.                 dj.obj.fs = fs;
  5120.                 INIT_NAMBUF(fs);
  5121.                 res = follow_path(&dj, path);   /* Follow the file path */
  5122.                 if (res == FR_OK && (dj.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME;      /* Check object validity */
  5123.                 if (res == FR_OK) {
  5124. #if FF_FS_EXFAT
  5125.                         if (fs->fs_type == FS_EXFAT) {
  5126.                                 st_dword(fs->dirbuf + XDIR_ModTime, (DWORD)fno->fdate << 16 | fno->ftime);
  5127.                                 res = store_xdir(&dj);
  5128.                         } else
  5129. #endif
  5130.                         {
  5131.                                 st_dword(dj.dir + DIR_ModTime, (DWORD)fno->fdate << 16 | fno->ftime);
  5132.                                 fs->wflag = 1;
  5133.                         }
  5134.                         if (res == FR_OK) {
  5135.                                 res = sync_fs(fs);
  5136.                         }
  5137.                 }
  5138.                 FREE_NAMBUF();
  5139.         }
  5140.  
  5141.         LEAVE_FF(fs, res);
  5142. }
  5143.  
  5144. #endif  /* FF_USE_CHMOD && !FF_FS_READONLY */
  5145.  
  5146.  
  5147.  
  5148. #if FF_USE_LABEL
  5149. /*-----------------------------------------------------------------------*/
  5150. /* Get Volume Label                                                      */
  5151. /*-----------------------------------------------------------------------*/
  5152.  
  5153. FRESULT f_getlabel (
  5154.         const TCHAR* path,      /* Logical drive number */
  5155.         TCHAR* label,           /* Buffer to store the volume label */
  5156.         DWORD* vsn                      /* Variable to store the volume serial number */
  5157. )
  5158. {
  5159.         FRESULT res;
  5160.         DIR dj;
  5161.         FATFS *fs;
  5162.         UINT si, di;
  5163.         WCHAR wc;
  5164.  
  5165.         /* Get logical drive */
  5166.         res = find_volume(&path, &fs, 0);
  5167.  
  5168.         /* Get volume label */
  5169.         if (res == FR_OK && label) {
  5170.                 dj.obj.fs = fs; dj.obj.sclust = 0;      /* Open root directory */
  5171.                 res = dir_sdi(&dj, 0);
  5172.                 if (res == FR_OK) {
  5173.                         res = DIR_READ_LABEL(&dj);              /* Find a volume label entry */
  5174.                         if (res == FR_OK) {
  5175. #if FF_FS_EXFAT
  5176.                                 if (fs->fs_type == FS_EXFAT) {
  5177.                                         WCHAR hs;
  5178.  
  5179.                                         for (si = di = hs = 0; si < dj.dir[XDIR_NumLabel]; si++) {      /* Extract volume label from 83 entry */
  5180.                                                 wc = ld_word(dj.dir + XDIR_Label + si * 2);
  5181.                                                 if (hs == 0 && IsSurrogate(wc)) {       /* Is the code a surrogate? */
  5182.                                                         hs = wc; continue;
  5183.                                                 }
  5184.                                                 wc = put_utf((DWORD)hs << 16 | wc, &label[di], 4);
  5185.                                                 if (wc == 0) { di = 0; break; }
  5186.                                                 di += wc;
  5187.                                                 hs = 0;
  5188.                                         }
  5189.                                         if (hs != 0) di = 0;    /* Broken surrogate pair? */
  5190.                                         label[di] = 0;
  5191.                                 } else
  5192. #endif
  5193.                                 {
  5194.                                         si = di = 0;            /* Extract volume label from AM_VOL entry */
  5195.                                         while (si < 11) {
  5196.                                                 wc = dj.dir[si++];
  5197. #if FF_USE_LFN && FF_LFN_UNICODE >= 1   /* Unicode output */
  5198.                                                 if (dbc_1st((BYTE)wc) && si < 11) wc = wc << 8 | dj.dir[si++];  /* Is it a DBC? */
  5199.                                                 wc = ff_oem2uni(wc, CODEPAGE);                                  /* Convert it into Unicode */
  5200.                                                 if (wc != 0) wc = put_utf(wc, &label[di], 4);   /* Put it in Unicode */
  5201.                                                 if (wc == 0) { di = 0; break; }
  5202.                                                 di += wc;
  5203. #else                                                                   /* ANSI/OEM output */
  5204.                                                 label[di++] = (TCHAR)wc;
  5205. #endif
  5206.                                         }
  5207.                                         do {                            /* Truncate trailing spaces */
  5208.                                                 label[di] = 0;
  5209.                                                 if (di == 0) break;
  5210.                                         } while (label[--di] == ' ');
  5211.                                 }
  5212.                         }
  5213.                 }
  5214.                 if (res == FR_NO_FILE) {        /* No label entry and return nul string */
  5215.                         label[0] = 0;
  5216.                         res = FR_OK;
  5217.                 }
  5218.         }
  5219.  
  5220.         /* Get volume serial number */
  5221.         if (res == FR_OK && vsn) {
  5222.                 res = move_window(fs, fs->volbase);
  5223.                 if (res == FR_OK) {
  5224.                         switch (fs->fs_type) {
  5225.                         case FS_EXFAT:
  5226.                                 di = BPB_VolIDEx; break;
  5227.  
  5228.                         case FS_FAT32:
  5229.                                 di = BS_VolID32; break;
  5230.  
  5231.                         default:
  5232.                                 di = BS_VolID;
  5233.                         }
  5234.                         *vsn = ld_dword(fs->win + di);
  5235.                 }
  5236.         }
  5237.  
  5238.         LEAVE_FF(fs, res);
  5239. }
  5240.  
  5241.  
  5242.  
  5243. #if !FF_FS_READONLY
  5244. /*-----------------------------------------------------------------------*/
  5245. /* Set Volume Label                                                      */
  5246. /*-----------------------------------------------------------------------*/
  5247.  
  5248. FRESULT f_setlabel (
  5249.         const TCHAR* label      /* Volume label to set with heading logical drive number */
  5250. )
  5251. {
  5252.         FRESULT res;
  5253.         DIR dj;
  5254.         FATFS *fs;
  5255.         BYTE dirvn[22];
  5256.         UINT di;
  5257.         WCHAR wc;
  5258.         static const char badchr[] = "+.,;=[]/\\\"*:<>\?|\x7F"; /* [0..] for FAT, [7..] for exFAT */
  5259. #if FF_USE_LFN
  5260.         DWORD dc;
  5261. #endif
  5262.  
  5263.         /* Get logical drive */
  5264.         res = find_volume(&label, &fs, FA_WRITE);
  5265.         if (res != FR_OK) LEAVE_FF(fs, res);
  5266.  
  5267. #if FF_FS_EXFAT
  5268.         if (fs->fs_type == FS_EXFAT) {  /* On the exFAT volume */
  5269.                 mem_set(dirvn, 0, 22);
  5270.                 di = 0;
  5271.                 while ((UINT)*label >= ' ') {   /* Create volume label */
  5272.                         dc = tchar2uni(&label); /* Get a Unicode character */
  5273.                         if (dc >= 0x10000) {
  5274.                                 if (dc == 0xFFFFFFFF || di >= 10) {     /* Wrong surrogate or buffer overflow */
  5275.                                         dc = 0;
  5276.                                 } else {
  5277.                                         st_word(dirvn + di * 2, (WCHAR)(dc >> 16)); di++;
  5278.                                 }
  5279.                         }
  5280.                         if (dc == 0 || chk_chr(badchr + 7, (int)dc) || di >= 11) {      /* Check validity of the volume label */
  5281.                                 LEAVE_FF(fs, FR_INVALID_NAME);
  5282.                         }
  5283.                         st_word(dirvn + di * 2, (WCHAR)dc); di++;
  5284.                 }
  5285.         } else
  5286. #endif
  5287.         {       /* On the FAT/FAT32 volume */
  5288.                 mem_set(dirvn, ' ', 11);
  5289.                 di = 0;
  5290.                 while ((UINT)*label >= ' ') {   /* Create volume label */
  5291. #if FF_USE_LFN
  5292.                         dc = tchar2uni(&label);
  5293.                         wc = (dc < 0x10000) ? ff_uni2oem(ff_wtoupper(dc), CODEPAGE) : 0;
  5294. #else                                                                   /* ANSI/OEM input */
  5295.                         wc = (BYTE)*label++;
  5296.                         if (dbc_1st((BYTE)wc)) wc = dbc_2nd((BYTE)*label) ? wc << 8 | (BYTE)*label++ : 0;
  5297.                         if (IsLower(wc)) wc -= 0x20;            /* To upper ASCII characters */
  5298. #if FF_CODE_PAGE == 0
  5299.                         if (ExCvt && wc >= 0x80) wc = ExCvt[wc - 0x80]; /* To upper extended characters (SBCS cfg) */
  5300. #elif FF_CODE_PAGE < 900
  5301.                         if (wc >= 0x80) wc = ExCvt[wc - 0x80];  /* To upper extended characters (SBCS cfg) */
  5302. #endif
  5303. #endif
  5304.                         if (wc == 0 || chk_chr(badchr + 0, (int)wc) || di >= (UINT)((wc >= 0x100) ? 10 : 11)) { /* Reject invalid characters for volume label */
  5305.                                 LEAVE_FF(fs, FR_INVALID_NAME);
  5306.                         }
  5307.                         if (wc >= 0x100) dirvn[di++] = (BYTE)(wc >> 8);
  5308.                         dirvn[di++] = (BYTE)wc;
  5309.                 }
  5310.                 if (dirvn[0] == DDEM) LEAVE_FF(fs, FR_INVALID_NAME);    /* Reject illegal name (heading DDEM) */
  5311.                 while (di && dirvn[di - 1] == ' ') di--;                                /* Snip trailing spaces */
  5312.         }
  5313.  
  5314.         /* Set volume label */
  5315.         dj.obj.fs = fs; dj.obj.sclust = 0;      /* Open root directory */
  5316.         res = dir_sdi(&dj, 0);
  5317.         if (res == FR_OK) {
  5318.                 res = DIR_READ_LABEL(&dj);      /* Get volume label entry */
  5319.                 if (res == FR_OK) {
  5320.                         if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) {
  5321.                                 dj.dir[XDIR_NumLabel] = (BYTE)di;       /* Change the volume label */
  5322.                                 mem_cpy(dj.dir + XDIR_Label, dirvn, 22);
  5323.                         } else {
  5324.                                 if (di != 0) {
  5325.                                         mem_cpy(dj.dir, dirvn, 11);     /* Change the volume label */
  5326.                                 } else {
  5327.                                         dj.dir[DIR_Name] = DDEM;        /* Remove the volume label */
  5328.                                 }
  5329.                         }
  5330.                         fs->wflag = 1;
  5331.                         res = sync_fs(fs);
  5332.                 } else {                        /* No volume label entry or an error */
  5333.                         if (res == FR_NO_FILE) {
  5334.                                 res = FR_OK;
  5335.                                 if (di != 0) {  /* Create a volume label entry */
  5336.                                         res = dir_alloc(&dj, 1);        /* Allocate an entry */
  5337.                                         if (res == FR_OK) {
  5338.                                                 mem_set(dj.dir, 0, SZDIRE);     /* Clean the entry */
  5339.                                                 if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) {
  5340.                                                         dj.dir[XDIR_Type] = ET_VLABEL;  /* Create volume label entry */
  5341.                                                         dj.dir[XDIR_NumLabel] = (BYTE)di;
  5342.                                                         mem_cpy(dj.dir + XDIR_Label, dirvn, 22);
  5343.                                                 } else {
  5344.                                                         dj.dir[DIR_Attr] = AM_VOL;              /* Create volume label entry */
  5345.                                                         mem_cpy(dj.dir, dirvn, 11);
  5346.                                                 }
  5347.                                                 fs->wflag = 1;
  5348.                                                 res = sync_fs(fs);
  5349.                                         }
  5350.                                 }
  5351.                         }
  5352.                 }
  5353.         }
  5354.  
  5355.         LEAVE_FF(fs, res);
  5356. }
  5357.  
  5358. #endif /* !FF_FS_READONLY */
  5359. #endif /* FF_USE_LABEL */
  5360.  
  5361.  
  5362.  
  5363. #if FF_USE_EXPAND && !FF_FS_READONLY
  5364. /*-----------------------------------------------------------------------*/
  5365. /* Allocate a Contiguous Blocks to the File                              */
  5366. /*-----------------------------------------------------------------------*/
  5367.  
  5368. FRESULT f_expand (
  5369.         FIL* fp,                /* Pointer to the file object */
  5370.         FSIZE_t fsz,    /* File size to be expanded to */
  5371.         BYTE opt                /* Operation mode 0:Find and prepare or 1:Find and allocate */
  5372. )
  5373. {
  5374.         FRESULT res;
  5375.         FATFS *fs;
  5376.         DWORD n, clst, stcl, scl, ncl, tcl, lclst;
  5377.  
  5378.  
  5379.         res = validate(&fp->obj, &fs);          /* Check validity of the file object */
  5380.         if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res);
  5381.         if (fsz == 0 || fp->obj.objsize != 0 || !(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED);
  5382. #if FF_FS_EXFAT
  5383.         if (fs->fs_type != FS_EXFAT && fsz >= 0x100000000) LEAVE_FF(fs, FR_DENIED);     /* Check if in size limit */
  5384. #endif
  5385.         n = (DWORD)fs->csize * SS(fs);  /* Cluster size */
  5386.         tcl = (DWORD)(fsz / n) + ((fsz & (n - 1)) ? 1 : 0);     /* Number of clusters required */
  5387.         stcl = fs->last_clst; lclst = 0;
  5388.         if (stcl < 2 || stcl >= fs->n_fatent) stcl = 2;
  5389.  
  5390. #if FF_FS_EXFAT
  5391.         if (fs->fs_type == FS_EXFAT) {
  5392.                 scl = find_bitmap(fs, stcl, tcl);                       /* Find a contiguous cluster block */
  5393.                 if (scl == 0) res = FR_DENIED;                          /* No contiguous cluster block was found */
  5394.                 if (scl == 0xFFFFFFFF) res = FR_DISK_ERR;
  5395.                 if (res == FR_OK) {     /* A contiguous free area is found */
  5396.                         if (opt) {              /* Allocate it now */
  5397.                                 res = change_bitmap(fs, scl, tcl, 1);   /* Mark the cluster block 'in use' */
  5398.                                 lclst = scl + tcl - 1;
  5399.                         } else {                /* Set it as suggested point for next allocation */
  5400.                                 lclst = scl - 1;
  5401.                         }
  5402.                 }
  5403.         } else
  5404. #endif
  5405.         {
  5406.                 scl = clst = stcl; ncl = 0;
  5407.                 for (;;) {      /* Find a contiguous cluster block */
  5408.                         n = get_fat(&fp->obj, clst);
  5409.                         if (++clst >= fs->n_fatent) clst = 2;
  5410.                         if (n == 1) { res = FR_INT_ERR; break; }
  5411.                         if (n == 0xFFFFFFFF) { res = FR_DISK_ERR; break; }
  5412.                         if (n == 0) {   /* Is it a free cluster? */
  5413.                                 if (++ncl == tcl) break;        /* Break if a contiguous cluster block is found */
  5414.                         } else {
  5415.                                 scl = clst; ncl = 0;            /* Not a free cluster */
  5416.                         }
  5417.                         if (clst == stcl) { res = FR_DENIED; break; }   /* No contiguous cluster? */
  5418.                 }
  5419.                 if (res == FR_OK) {     /* A contiguous free area is found */
  5420.                         if (opt) {              /* Allocate it now */
  5421.                                 for (clst = scl, n = tcl; n; clst++, n--) {     /* Create a cluster chain on the FAT */
  5422.                                         res = put_fat(fs, clst, (n == 1) ? 0xFFFFFFFF : clst + 1);
  5423.                                         if (res != FR_OK) break;
  5424.                                         lclst = clst;
  5425.                                 }
  5426.                         } else {                /* Set it as suggested point for next allocation */
  5427.                                 lclst = scl - 1;
  5428.                         }
  5429.                 }
  5430.         }
  5431.  
  5432.         if (res == FR_OK) {
  5433.                 fs->last_clst = lclst;          /* Set suggested start cluster to start next */
  5434.                 if (opt) {      /* Is it allocated now? */
  5435.                         fp->obj.sclust = scl;           /* Update object allocation information */
  5436.                         fp->obj.objsize = fsz;
  5437.                         if (FF_FS_EXFAT) fp->obj.stat = 2;      /* Set status 'contiguous chain' */
  5438.                         fp->flag |= FA_MODIFIED;
  5439.                         if (fs->free_clst <= fs->n_fatent - 2) {        /* Update FSINFO */
  5440.                                 fs->free_clst -= tcl;
  5441.                                 fs->fsi_flag |= 1;
  5442.                         }
  5443.                 }
  5444.         }
  5445.  
  5446.         LEAVE_FF(fs, res);
  5447. }
  5448.  
  5449. #endif /* FF_USE_EXPAND && !FF_FS_READONLY */
  5450.  
  5451.  
  5452.  
  5453. #if FF_USE_FORWARD
  5454. /*-----------------------------------------------------------------------*/
  5455. /* Forward Data to the Stream Directly                                   */
  5456. /*-----------------------------------------------------------------------*/
  5457.  
  5458. FRESULT f_forward (
  5459.         FIL* fp,                                                /* Pointer to the file object */
  5460.         UINT (*func)(const BYTE*,UINT), /* Pointer to the streaming function */
  5461.         UINT btf,                                               /* Number of bytes to forward */
  5462.         UINT* bf                                                /* Pointer to number of bytes forwarded */
  5463. )
  5464. {
  5465.         FRESULT res;
  5466.         FATFS *fs;
  5467.         DWORD clst, sect;
  5468.         FSIZE_t remain;
  5469.         UINT rcnt, csect;
  5470.         BYTE *dbuf;
  5471.  
  5472.  
  5473.         *bf = 0;        /* Clear transfer byte counter */
  5474.         res = validate(&fp->obj, &fs);          /* Check validity of the file object */
  5475.         if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res);
  5476.         if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED);     /* Check access mode */
  5477.  
  5478.         remain = fp->obj.objsize - fp->fptr;
  5479.         if (btf > remain) btf = (UINT)remain;                   /* Truncate btf by remaining bytes */
  5480.  
  5481.         for ( ;  btf && (*func)(0, 0);                                  /* Repeat until all data transferred or stream goes busy */
  5482.                 fp->fptr += rcnt, *bf += rcnt, btf -= rcnt) {
  5483.                 csect = (UINT)(fp->fptr / SS(fs) & (fs->csize - 1));    /* Sector offset in the cluster */
  5484.                 if (fp->fptr % SS(fs) == 0) {                           /* On the sector boundary? */
  5485.                         if (csect == 0) {                                               /* On the cluster boundary? */
  5486.                                 clst = (fp->fptr == 0) ?                        /* On the top of the file? */
  5487.                                         fp->obj.sclust : get_fat(&fp->obj, fp->clust);
  5488.                                 if (clst <= 1) ABORT(fs, FR_INT_ERR);
  5489.                                 if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR);
  5490.                                 fp->clust = clst;                                       /* Update current cluster */
  5491.                         }
  5492.                 }
  5493.                 sect = clst2sect(fs, fp->clust);                        /* Get current data sector */
  5494.                 if (sect == 0) ABORT(fs, FR_INT_ERR);
  5495.                 sect += csect;
  5496. #if FF_FS_TINY
  5497.                 if (move_window(fs, sect) != FR_OK) ABORT(fs, FR_DISK_ERR);     /* Move sector window to the file data */
  5498.                 dbuf = fs->win;
  5499. #else
  5500.                 if (fp->sect != sect) {         /* Fill sector cache with file data */
  5501. #if !FF_FS_READONLY
  5502.                         if (fp->flag & FA_DIRTY) {              /* Write-back dirty sector cache */
  5503.                                 if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);
  5504.                                 fp->flag &= (BYTE)~FA_DIRTY;
  5505.                         }
  5506. #endif
  5507.                         if (disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);
  5508.                 }
  5509.                 dbuf = fp->buf;
  5510. #endif
  5511.                 fp->sect = sect;
  5512.                 rcnt = SS(fs) - (UINT)fp->fptr % SS(fs);        /* Number of bytes left in the sector */
  5513.                 if (rcnt > btf) rcnt = btf;                                     /* Clip it by btr if needed */
  5514.                 rcnt = (*func)(dbuf + ((UINT)fp->fptr % SS(fs)), rcnt); /* Forward the file data */
  5515.                 if (rcnt == 0) ABORT(fs, FR_INT_ERR);
  5516.         }
  5517.  
  5518.         LEAVE_FF(fs, FR_OK);
  5519. }
  5520. #endif /* FF_USE_FORWARD */
  5521.  
  5522.  
  5523.  
  5524. #if FF_USE_MKFS && !FF_FS_READONLY
  5525. /*-----------------------------------------------------------------------*/
  5526. /* Create an FAT/exFAT volume                                            */
  5527. /*-----------------------------------------------------------------------*/
  5528.  
  5529. FRESULT f_mkfs (
  5530.         const TCHAR* path,      /* Logical drive number */
  5531.         BYTE opt,                       /* Format option */
  5532.         DWORD au,                       /* Size of allocation unit (cluster) [byte] */
  5533.         void* work,                     /* Pointer to working buffer (null: use heap memory) */
  5534.         UINT len                        /* Size of working buffer [byte] */
  5535. )
  5536. {
  5537.         const UINT n_fats = 1;          /* Number of FATs for FAT/FAT32 volume (1 or 2) */
  5538.         const UINT n_rootdir = 512;     /* Number of root directory entries for FAT volume */
  5539.         static const WORD cst[] = {1, 4, 16, 64, 256, 512, 0};  /* Cluster size boundary for FAT volume (4Ks unit) */
  5540.         static const WORD cst32[] = {1, 2, 4, 8, 16, 32, 0};    /* Cluster size boundary for FAT32 volume (128Ks unit) */
  5541.         BYTE fmt, sys, *buf, *pte, pdrv, part;
  5542.         WORD ss;        /* Sector size */
  5543.         DWORD szb_buf, sz_buf, sz_blk, n_clst, pau, sect, nsect, n;
  5544.         DWORD b_vol, b_fat, b_data;                             /* Base LBA for volume, fat, data */
  5545.         DWORD sz_vol, sz_rsv, sz_fat, sz_dir;   /* Size for volume, fat, dir, data */
  5546.         UINT i;
  5547.         int vol;
  5548.         DSTATUS stat;
  5549. #if FF_USE_TRIM || FF_FS_EXFAT
  5550.         DWORD tbl[3];
  5551. #endif
  5552.  
  5553.  
  5554.         /* Check mounted drive and clear work area */
  5555.         vol = get_ldnumber(&path);                                      /* Get target logical drive */
  5556.         if (vol < 0) return FR_INVALID_DRIVE;
  5557.         if (FatFs[vol]) FatFs[vol]->fs_type = 0;        /* Clear the volume if mounted */
  5558.         pdrv = LD2PD(vol);      /* Physical drive */
  5559.         part = LD2PT(vol);      /* Partition (0:create as new, 1-4:get from partition table) */
  5560.  
  5561.         /* Check physical drive status */
  5562.         stat = disk_initialize(pdrv);
  5563.         if (stat & STA_NOINIT) return FR_NOT_READY;
  5564.         if (stat & STA_PROTECT) return FR_WRITE_PROTECTED;
  5565.         if (disk_ioctl(pdrv, GET_BLOCK_SIZE, &sz_blk) != RES_OK || !sz_blk || sz_blk > 32768 || (sz_blk & (sz_blk - 1))) sz_blk = 1;    /* Erase block to align data area */
  5566. #if FF_MAX_SS != FF_MIN_SS              /* Get sector size of the medium if variable sector size cfg. */
  5567.         if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &ss) != RES_OK) return FR_DISK_ERR;
  5568.         if (ss > FF_MAX_SS || ss < FF_MIN_SS || (ss & (ss - 1))) return FR_DISK_ERR;
  5569. #else
  5570.         ss = FF_MAX_SS;
  5571. #endif
  5572.         if ((au != 0 && au < ss) || au > 0x1000000 || (au & (au - 1))) return FR_INVALID_PARAMETER;     /* Check if au is valid */
  5573.         au /= ss;       /* Cluster size in unit of sector */
  5574.  
  5575.         /* Get working buffer */
  5576. #if FF_USE_LFN == 3
  5577.         if (!work) {    /* Use heap memory for working buffer */
  5578.                 for (szb_buf = MAX_MALLOC, buf = 0; szb_buf >= ss && (buf = ff_memalloc(szb_buf)) == 0; szb_buf /= 2) ;
  5579.                 sz_buf = szb_buf / ss;          /* Size of working buffer (sector) */
  5580.         } else
  5581. #endif
  5582.         {
  5583.                 buf = (BYTE*)work;              /* Working buffer */
  5584.                 sz_buf = len / ss;              /* Size of working buffer (sector) */
  5585.                 szb_buf = sz_buf * ss;  /* Size of working buffer (byte) */
  5586.         }
  5587.         if (!buf || sz_buf == 0) return FR_NOT_ENOUGH_CORE;
  5588.  
  5589.         /* Determine where the volume to be located (b_vol, sz_vol) */
  5590.         if (FF_MULTI_PARTITION && part != 0) {
  5591.                 /* Get partition information from partition table in the MBR */
  5592.                 if (disk_read(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);      /* Load MBR */
  5593.                 if (ld_word(buf + BS_55AA) != 0xAA55) LEAVE_MKFS(FR_MKFS_ABORTED);      /* Check if MBR is valid */
  5594.                 pte = buf + (MBR_Table + (part - 1) * SZ_PTE);
  5595.                 if (pte[PTE_System] == 0) LEAVE_MKFS(FR_MKFS_ABORTED);  /* No partition? */
  5596.                 b_vol = ld_dword(pte + PTE_StLba);              /* Get volume start sector */
  5597.                 sz_vol = ld_dword(pte + PTE_SizLba);    /* Get volume size */
  5598.         } else {
  5599.                 /* Create a single-partition in this function */
  5600.                 if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_vol) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);
  5601.                 b_vol = (opt & FM_SFD) ? 0 : 63;                /* Volume start sector */
  5602.                 if (sz_vol < b_vol) LEAVE_MKFS(FR_MKFS_ABORTED);
  5603.                 sz_vol -= b_vol;                                                /* Volume size */
  5604.         }
  5605.         if (sz_vol < 128) LEAVE_MKFS(FR_MKFS_ABORTED);  /* Check if volume size is >=128s */
  5606.  
  5607.         /* Pre-determine the FAT type */
  5608.         do {
  5609.                 if (FF_FS_EXFAT && (opt & FM_EXFAT)) {  /* exFAT possible? */
  5610.                         if ((opt & FM_ANY) == FM_EXFAT || sz_vol >= 0x4000000 || au > 128) {    /* exFAT only, vol >= 64Ms or au > 128s ? */
  5611.                                 fmt = FS_EXFAT; break;
  5612.                         }
  5613.                 }
  5614.                 if (au > 128) LEAVE_MKFS(FR_INVALID_PARAMETER); /* Too large au for FAT/FAT32 */
  5615.                 if (opt & FM_FAT32) {   /* FAT32 possible? */
  5616.                         if ((opt & FM_ANY) == FM_FAT32 || !(opt & FM_FAT)) {    /* FAT32 only or no-FAT? */
  5617.                                 fmt = FS_FAT32; break;
  5618.                         }
  5619.                 }
  5620.                 if (!(opt & FM_FAT)) LEAVE_MKFS(FR_INVALID_PARAMETER);  /* no-FAT? */
  5621.                 fmt = FS_FAT16;
  5622.         } while (0);
  5623.  
  5624. #if FF_FS_EXFAT
  5625.         if (fmt == FS_EXFAT) {  /* Create an exFAT volume */
  5626.                 DWORD szb_bit, szb_case, sum, nb, cl;
  5627.                 WCHAR ch, si;
  5628.                 UINT j, st;
  5629.                 BYTE b;
  5630.  
  5631.                 if (sz_vol < 0x1000) LEAVE_MKFS(FR_MKFS_ABORTED);       /* Too small volume? */
  5632. #if FF_USE_TRIM
  5633.                 tbl[0] = b_vol; tbl[1] = b_vol + sz_vol - 1;    /* Inform the device the volume area may be erased */
  5634.                 disk_ioctl(pdrv, CTRL_TRIM, tbl);
  5635. #endif
  5636.                 /* Determine FAT location, data location and number of clusters */
  5637.                 if (au == 0) {  /* au auto-selection */
  5638.                         au = 8;
  5639.                         if (sz_vol >= 0x80000) au = 64;         /* >= 512Ks */
  5640.                         if (sz_vol >= 0x4000000) au = 256;      /* >= 64Ms */
  5641.                 }
  5642.                 b_fat = b_vol + 32;                                                                             /* FAT start at offset 32 */
  5643.                 sz_fat = ((sz_vol / au + 2) * 4 + ss - 1) / ss;                 /* Number of FAT sectors */
  5644.                 b_data = (b_fat + sz_fat + sz_blk - 1) & ~(sz_blk - 1); /* Align data area to the erase block boundary */
  5645.                 if (b_data >= sz_vol / 2) LEAVE_MKFS(FR_MKFS_ABORTED);  /* Too small volume? */
  5646.                 n_clst = (sz_vol - (b_data - b_vol)) / au;                              /* Number of clusters */
  5647.                 if (n_clst <16) LEAVE_MKFS(FR_MKFS_ABORTED);                    /* Too few clusters? */
  5648.                 if (n_clst > MAX_EXFAT) LEAVE_MKFS(FR_MKFS_ABORTED);    /* Too many clusters? */
  5649.  
  5650.                 szb_bit = (n_clst + 7) / 8;                                             /* Size of allocation bitmap */
  5651.                 tbl[0] = (szb_bit + au * ss - 1) / (au * ss);   /* Number of allocation bitmap clusters */
  5652.  
  5653.                 /* Create a compressed up-case table */
  5654.                 sect = b_data + au * tbl[0];    /* Table start sector */
  5655.                 sum = 0;                                                /* Table checksum to be stored in the 82 entry */
  5656.                 st = 0; si = 0; i = 0; j = 0; szb_case = 0;
  5657.                 do {
  5658.                         switch (st) {
  5659.                         case 0:
  5660.                                 ch = (WCHAR)ff_wtoupper(si);    /* Get an up-case char */
  5661.                                 if (ch != si) {
  5662.                                         si++; break;            /* Store the up-case char if exist */
  5663.                                 }
  5664.                                 for (j = 1; (WCHAR)(si + j) && (WCHAR)(si + j) == ff_wtoupper((WCHAR)(si + j)); j++) ;  /* Get run length of no-case block */
  5665.                                 if (j >= 128) {
  5666.                                         ch = 0xFFFF; st = 2; break;     /* Compress the no-case block if run is >= 128 */
  5667.                                 }
  5668.                                 st = 1;                 /* Do not compress short run */
  5669.                                 /* go to next case */
  5670.                         case 1:
  5671.                                 ch = si++;              /* Fill the short run */
  5672.                                 if (--j == 0) st = 0;
  5673.                                 break;
  5674.  
  5675.                         default:
  5676.                                 ch = (WCHAR)j; si += (WCHAR)j;  /* Number of chars to skip */
  5677.                                 st = 0;
  5678.                         }
  5679.                         sum = xsum32(buf[i + 0] = (BYTE)ch, sum);               /* Put it into the write buffer */
  5680.                         sum = xsum32(buf[i + 1] = (BYTE)(ch >> 8), sum);
  5681.                         i += 2; szb_case += 2;
  5682.                         if (si == 0 || i == szb_buf) {          /* Write buffered data when buffer full or end of process */
  5683.                                 n = (i + ss - 1) / ss;
  5684.                                 if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);
  5685.                                 sect += n; i = 0;
  5686.                         }
  5687.                 } while (si);
  5688.                 tbl[1] = (szb_case + au * ss - 1) / (au * ss);  /* Number of up-case table clusters */
  5689.                 tbl[2] = 1;                                                                             /* Number of root dir clusters */
  5690.  
  5691.                 /* Initialize the allocation bitmap */
  5692.                 sect = b_data; nsect = (szb_bit + ss - 1) / ss; /* Start of bitmap and number of sectors */
  5693.                 nb = tbl[0] + tbl[1] + tbl[2];                                  /* Number of clusters in-use by system */
  5694.                 do {
  5695.                         mem_set(buf, 0, szb_buf);
  5696.                         for (i = 0; nb >= 8 && i < szb_buf; buf[i++] = 0xFF, nb -= 8) ;
  5697.                         for (b = 1; nb != 0 && i < szb_buf; buf[i] |= b, b <<= 1, nb--) ;
  5698.                         n = (nsect > sz_buf) ? sz_buf : nsect;          /* Write the buffered data */
  5699.                         if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);
  5700.                         sect += n; nsect -= n;
  5701.                 } while (nsect);
  5702.  
  5703.                 /* Initialize the FAT */
  5704.                 sect = b_fat; nsect = sz_fat;   /* Start of FAT and number of FAT sectors */
  5705.                 j = nb = cl = 0;
  5706.                 do {
  5707.                         mem_set(buf, 0, szb_buf); i = 0;        /* Clear work area and reset write index */
  5708.                         if (cl == 0) {  /* Set entry 0 and 1 */
  5709.                                 st_dword(buf + i, 0xFFFFFFF8); i += 4; cl++;
  5710.                                 st_dword(buf + i, 0xFFFFFFFF); i += 4; cl++;
  5711.                         }
  5712.                         do {                    /* Create chains of bitmap, up-case and root dir */
  5713.                                 while (nb != 0 && i < szb_buf) {                        /* Create a chain */
  5714.                                         st_dword(buf + i, (nb > 1) ? cl + 1 : 0xFFFFFFFF);
  5715.                                         i += 4; cl++; nb--;
  5716.                                 }
  5717.                                 if (nb == 0 && j < 3) nb = tbl[j++];    /* Next chain */
  5718.                         } while (nb != 0 && i < szb_buf);
  5719.                         n = (nsect > sz_buf) ? sz_buf : nsect;  /* Write the buffered data */
  5720.                         if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);
  5721.                         sect += n; nsect -= n;
  5722.                 } while (nsect);
  5723.  
  5724.                 /* Initialize the root directory */
  5725.                 mem_set(buf, 0, szb_buf);
  5726.                 buf[SZDIRE * 0 + 0] = ET_VLABEL;                /* Volume label entry */
  5727.                 buf[SZDIRE * 1 + 0] = ET_BITMAP;                /* Bitmap entry */
  5728.                 st_dword(buf + SZDIRE * 1 + 20, 2);                             /* cluster */
  5729.                 st_dword(buf + SZDIRE * 1 + 24, szb_bit);               /* size */
  5730.                 buf[SZDIRE * 2 + 0] = ET_UPCASE;                /* Up-case table entry */
  5731.                 st_dword(buf + SZDIRE * 2 + 4, sum);                    /* sum */
  5732.                 st_dword(buf + SZDIRE * 2 + 20, 2 + tbl[0]);    /* cluster */
  5733.                 st_dword(buf + SZDIRE * 2 + 24, szb_case);              /* size */
  5734.                 sect = b_data + au * (tbl[0] + tbl[1]); nsect = au;     /* Start of the root directory and number of sectors */
  5735.                 do {    /* Fill root directory sectors */
  5736.                         n = (nsect > sz_buf) ? sz_buf : nsect;
  5737.                         if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);
  5738.                         mem_set(buf, 0, ss);
  5739.                         sect += n; nsect -= n;
  5740.                 } while (nsect);
  5741.  
  5742.                 /* Create two set of the exFAT VBR blocks */
  5743.                 sect = b_vol;
  5744.                 for (n = 0; n < 2; n++) {
  5745.                         /* Main record (+0) */
  5746.                         mem_set(buf, 0, ss);
  5747.                         mem_cpy(buf + BS_JmpBoot, "\xEB\x76\x90" "EXFAT   ", 11);       /* Boot jump code (x86), OEM name */
  5748.                         st_dword(buf + BPB_VolOfsEx, b_vol);                                    /* Volume offset in the physical drive [sector] */
  5749.                         st_dword(buf + BPB_TotSecEx, sz_vol);                                   /* Volume size [sector] */
  5750.                         st_dword(buf + BPB_FatOfsEx, b_fat - b_vol);                    /* FAT offset [sector] */
  5751.                         st_dword(buf + BPB_FatSzEx, sz_fat);                                    /* FAT size [sector] */
  5752.                         st_dword(buf + BPB_DataOfsEx, b_data - b_vol);                  /* Data offset [sector] */
  5753.                         st_dword(buf + BPB_NumClusEx, n_clst);                                  /* Number of clusters */
  5754.                         st_dword(buf + BPB_RootClusEx, 2 + tbl[0] + tbl[1]);    /* Root dir cluster # */
  5755.                         st_dword(buf + BPB_VolIDEx, GET_FATTIME());                             /* VSN */
  5756.                         st_word(buf + BPB_FSVerEx, 0x100);                                              /* Filesystem version (1.00) */
  5757.                         for (buf[BPB_BytsPerSecEx] = 0, i = ss; i >>= 1; buf[BPB_BytsPerSecEx]++) ;     /* Log2 of sector size [byte] */
  5758.                         for (buf[BPB_SecPerClusEx] = 0, i = au; i >>= 1; buf[BPB_SecPerClusEx]++) ;     /* Log2 of cluster size [sector] */
  5759.                         buf[BPB_NumFATsEx] = 1;                                 /* Number of FATs */
  5760.                         buf[BPB_DrvNumEx] = 0x80;                               /* Drive number (for int13) */
  5761.                         st_word(buf + BS_BootCodeEx, 0xFEEB);   /* Boot code (x86) */
  5762.                         st_word(buf + BS_55AA, 0xAA55);                 /* Signature (placed here regardless of sector size) */
  5763.                         for (i = sum = 0; i < ss; i++) {                /* VBR checksum */
  5764.                                 if (i != BPB_VolFlagEx && i != BPB_VolFlagEx + 1 && i != BPB_PercInUseEx) sum = xsum32(buf[i], sum);
  5765.                         }
  5766.                         if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);
  5767.                         /* Extended bootstrap record (+1..+8) */
  5768.                         mem_set(buf, 0, ss);
  5769.                         st_word(buf + ss - 2, 0xAA55);  /* Signature (placed at end of sector) */
  5770.                         for (j = 1; j < 9; j++) {
  5771.                                 for (i = 0; i < ss; sum = xsum32(buf[i++], sum)) ;      /* VBR checksum */
  5772.                                 if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);
  5773.                         }
  5774.                         /* OEM/Reserved record (+9..+10) */
  5775.                         mem_set(buf, 0, ss);
  5776.                         for ( ; j < 11; j++) {
  5777.                                 for (i = 0; i < ss; sum = xsum32(buf[i++], sum)) ;      /* VBR checksum */
  5778.                                 if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);
  5779.                         }
  5780.                         /* Sum record (+11) */
  5781.                         for (i = 0; i < ss; i += 4) st_dword(buf + i, sum);             /* Fill with checksum value */
  5782.                         if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);
  5783.                 }
  5784.  
  5785.         } else
  5786. #endif  /* FF_FS_EXFAT */
  5787.         {       /* Create an FAT/FAT32 volume */
  5788.                 do {
  5789.                         pau = au;
  5790.                         /* Pre-determine number of clusters and FAT sub-type */
  5791.                         if (fmt == FS_FAT32) {  /* FAT32 volume */
  5792.                                 if (pau == 0) { /* au auto-selection */
  5793.                                         n = sz_vol / 0x20000;   /* Volume size in unit of 128KS */
  5794.                                         for (i = 0, pau = 1; cst32[i] && cst32[i] <= n; i++, pau <<= 1) ;       /* Get from table */
  5795.                                 }
  5796.                                 n_clst = sz_vol / pau;  /* Number of clusters */
  5797.                                 sz_fat = (n_clst * 4 + 8 + ss - 1) / ss;        /* FAT size [sector] */
  5798.                                 sz_rsv = 32;    /* Number of reserved sectors */
  5799.                                 sz_dir = 0;             /* No static directory */
  5800.                                 if (n_clst <= MAX_FAT16 || n_clst > MAX_FAT32) LEAVE_MKFS(FR_MKFS_ABORTED);
  5801.                         } else {                                /* FAT volume */
  5802.                                 if (pau == 0) { /* au auto-selection */
  5803.                                         n = sz_vol / 0x1000;    /* Volume size in unit of 4KS */
  5804.                                         for (i = 0, pau = 1; cst[i] && cst[i] <= n; i++, pau <<= 1) ;   /* Get from table */
  5805.                                 }
  5806.                                 n_clst = sz_vol / pau;
  5807.                                 if (n_clst > MAX_FAT12) {
  5808.                                         n = n_clst * 2 + 4;             /* FAT size [byte] */
  5809.                                 } else {
  5810.                                         fmt = FS_FAT12;
  5811.                                         n = (n_clst * 3 + 1) / 2 + 3;   /* FAT size [byte] */
  5812.                                 }
  5813.                                 sz_fat = (n + ss - 1) / ss;             /* FAT size [sector] */
  5814.                                 sz_rsv = 1;                                             /* Number of reserved sectors */
  5815.                                 sz_dir = (DWORD)n_rootdir * SZDIRE / ss;        /* Rootdir size [sector] */
  5816.                         }
  5817.                         b_fat = b_vol + sz_rsv;                                         /* FAT base */
  5818.                         b_data = b_fat + sz_fat * n_fats + sz_dir;      /* Data base */
  5819.  
  5820.                         /* Align data base to erase block boundary (for flash memory media) */
  5821.                         n = ((b_data + sz_blk - 1) & ~(sz_blk - 1)) - b_data;   /* Next nearest erase block from current data base */
  5822.                         if (fmt == FS_FAT32) {          /* FAT32: Move FAT base */
  5823.                                 sz_rsv += n; b_fat += n;
  5824.                         } else {                                        /* FAT: Expand FAT size */
  5825.                                 sz_fat += n / n_fats;
  5826.                         }
  5827.  
  5828.                         /* Determine number of clusters and final check of validity of the FAT sub-type */
  5829.                         if (sz_vol < b_data + pau * 16 - b_vol) LEAVE_MKFS(FR_MKFS_ABORTED);    /* Too small volume */
  5830.                         n_clst = (sz_vol - sz_rsv - sz_fat * n_fats - sz_dir) / pau;
  5831.                         if (fmt == FS_FAT32) {
  5832.                                 if (n_clst <= MAX_FAT16) {      /* Too few clusters for FAT32 */
  5833.                                         if (au == 0 && (au = pau / 2) != 0) continue;   /* Adjust cluster size and retry */
  5834.                                         LEAVE_MKFS(FR_MKFS_ABORTED);
  5835.                                 }
  5836.                         }
  5837.                         if (fmt == FS_FAT16) {
  5838.                                 if (n_clst > MAX_FAT16) {       /* Too many clusters for FAT16 */
  5839.                                         if (au == 0 && (pau * 2) <= 64) {
  5840.                                                 au = pau * 2; continue;         /* Adjust cluster size and retry */
  5841.                                         }
  5842.                                         if ((opt & FM_FAT32)) {
  5843.                                                 fmt = FS_FAT32; continue;       /* Switch type to FAT32 and retry */
  5844.                                         }
  5845.                                         if (au == 0 && (au = pau * 2) <= 128) continue; /* Adjust cluster size and retry */
  5846.                                         LEAVE_MKFS(FR_MKFS_ABORTED);
  5847.                                 }
  5848.                                 if  (n_clst <= MAX_FAT12) {     /* Too few clusters for FAT16 */
  5849.                                         if (au == 0 && (au = pau * 2) <= 128) continue; /* Adjust cluster size and retry */
  5850.                                         LEAVE_MKFS(FR_MKFS_ABORTED);
  5851.                                 }
  5852.                         }
  5853.                         if (fmt == FS_FAT12 && n_clst > MAX_FAT12) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too many clusters for FAT12 */
  5854.  
  5855.                         /* Ok, it is the valid cluster configuration */
  5856.                         break;
  5857.                 } while (1);
  5858.  
  5859. #if FF_USE_TRIM
  5860.                 tbl[0] = b_vol; tbl[1] = b_vol + sz_vol - 1;    /* Inform the device the volume area can be erased */
  5861.                 disk_ioctl(pdrv, CTRL_TRIM, tbl);
  5862. #endif
  5863.                 /* Create FAT VBR */
  5864.                 mem_set(buf, 0, ss);
  5865.                 mem_cpy(buf + BS_JmpBoot, "\xEB\xFE\x90" "MSDOS5.0", 11);/* Boot jump code (x86), OEM name */
  5866.                 st_word(buf + BPB_BytsPerSec, ss);                              /* Sector size [byte] */
  5867.                 buf[BPB_SecPerClus] = (BYTE)pau;                                /* Cluster size [sector] */
  5868.                 st_word(buf + BPB_RsvdSecCnt, (WORD)sz_rsv);    /* Size of reserved area */
  5869.                 buf[BPB_NumFATs] = (BYTE)n_fats;                                /* Number of FATs */
  5870.                 st_word(buf + BPB_RootEntCnt, (WORD)((fmt == FS_FAT32) ? 0 : n_rootdir));       /* Number of root directory entries */
  5871.                 if (sz_vol < 0x10000) {
  5872.                         st_word(buf + BPB_TotSec16, (WORD)sz_vol);      /* Volume size in 16-bit LBA */
  5873.                 } else {
  5874.                         st_dword(buf + BPB_TotSec32, sz_vol);           /* Volume size in 32-bit LBA */
  5875.                 }
  5876.                 buf[BPB_Media] = 0xF8;                                                  /* Media descriptor byte */
  5877.                 st_word(buf + BPB_SecPerTrk, 63);                               /* Number of sectors per track (for int13) */
  5878.                 st_word(buf + BPB_NumHeads, 255);                               /* Number of heads (for int13) */
  5879.                 st_dword(buf + BPB_HiddSec, b_vol);                             /* Volume offset in the physical drive [sector] */
  5880.                 if (fmt == FS_FAT32) {
  5881.                         st_dword(buf + BS_VolID32, GET_FATTIME());      /* VSN */
  5882.                         st_dword(buf + BPB_FATSz32, sz_fat);            /* FAT size [sector] */
  5883.                         st_dword(buf + BPB_RootClus32, 2);                      /* Root directory cluster # (2) */
  5884.                         st_word(buf + BPB_FSInfo32, 1);                         /* Offset of FSINFO sector (VBR + 1) */
  5885.                         st_word(buf + BPB_BkBootSec32, 6);                      /* Offset of backup VBR (VBR + 6) */
  5886.                         buf[BS_DrvNum32] = 0x80;                                        /* Drive number (for int13) */
  5887.                         buf[BS_BootSig32] = 0x29;                                       /* Extended boot signature */
  5888.                         mem_cpy(buf + BS_VolLab32, "NO NAME    " "FAT32   ", 19);       /* Volume label, FAT signature */
  5889.                 } else {
  5890.                         st_dword(buf + BS_VolID, GET_FATTIME());        /* VSN */
  5891.                         st_word(buf + BPB_FATSz16, (WORD)sz_fat);       /* FAT size [sector] */
  5892.                         buf[BS_DrvNum] = 0x80;                                          /* Drive number (for int13) */
  5893.                         buf[BS_BootSig] = 0x29;                                         /* Extended boot signature */
  5894.                         mem_cpy(buf + BS_VolLab, "NO NAME    " "FAT     ", 19); /* Volume label, FAT signature */
  5895.                 }
  5896.                 st_word(buf + BS_55AA, 0xAA55);                                 /* Signature (offset is fixed here regardless of sector size) */
  5897.                 if (disk_write(pdrv, buf, b_vol, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Write it to the VBR sector */
  5898.  
  5899.                 /* Create FSINFO record if needed */
  5900.                 if (fmt == FS_FAT32) {
  5901.                         disk_write(pdrv, buf, b_vol + 6, 1);            /* Write backup VBR (VBR + 6) */
  5902.                         mem_set(buf, 0, ss);
  5903.                         st_dword(buf + FSI_LeadSig, 0x41615252);
  5904.                         st_dword(buf + FSI_StrucSig, 0x61417272);
  5905.                         st_dword(buf + FSI_Free_Count, n_clst - 1);     /* Number of free clusters */
  5906.                         st_dword(buf + FSI_Nxt_Free, 2);                        /* Last allocated cluster# */
  5907.                         st_word(buf + BS_55AA, 0xAA55);
  5908.                         disk_write(pdrv, buf, b_vol + 7, 1);            /* Write backup FSINFO (VBR + 7) */
  5909.                         disk_write(pdrv, buf, b_vol + 1, 1);            /* Write original FSINFO (VBR + 1) */
  5910.                 }
  5911.  
  5912.                 /* Initialize FAT area */
  5913.                 mem_set(buf, 0, (UINT)szb_buf);
  5914.                 sect = b_fat;           /* FAT start sector */
  5915.                 for (i = 0; i < n_fats; i++) {                  /* Initialize FATs each */
  5916.                         if (fmt == FS_FAT32) {
  5917.                                 st_dword(buf + 0, 0xFFFFFFF8);  /* Entry 0 */
  5918.                                 st_dword(buf + 4, 0xFFFFFFFF);  /* Entry 1 */
  5919.                                 st_dword(buf + 8, 0x0FFFFFFF);  /* Entry 2 (root directory) */
  5920.                         } else {
  5921.                                 st_dword(buf + 0, (fmt == FS_FAT12) ? 0xFFFFF8 : 0xFFFFFFF8);   /* Entry 0 and 1 */
  5922.                         }
  5923.                         nsect = sz_fat;         /* Number of FAT sectors */
  5924.                         do {    /* Fill FAT sectors */
  5925.                                 n = (nsect > sz_buf) ? sz_buf : nsect;
  5926.                                 if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);
  5927.                                 mem_set(buf, 0, ss);
  5928.                                 sect += n; nsect -= n;
  5929.                         } while (nsect);
  5930.                 }
  5931.  
  5932.                 /* Initialize root directory (fill with zero) */
  5933.                 nsect = (fmt == FS_FAT32) ? pau : sz_dir;       /* Number of root directory sectors */
  5934.                 do {
  5935.                         n = (nsect > sz_buf) ? sz_buf : nsect;
  5936.                         if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);
  5937.                         sect += n; nsect -= n;
  5938.                 } while (nsect);
  5939.         }
  5940.  
  5941.         /* Determine system ID in the partition table */
  5942.         if (FF_FS_EXFAT && fmt == FS_EXFAT) {
  5943.                 sys = 0x07;                     /* HPFS/NTFS/exFAT */
  5944.         } else {
  5945.                 if (fmt == FS_FAT32) {
  5946.                         sys = 0x0C;             /* FAT32X */
  5947.                 } else {
  5948.                         if (sz_vol >= 0x10000) {
  5949.                                 sys = 0x06;     /* FAT12/16 (large) */
  5950.                         } else {
  5951.                                 sys = (fmt == FS_FAT16) ? 0x04 : 0x01;  /* FAT16 : FAT12 */
  5952.                         }
  5953.                 }
  5954.         }
  5955.  
  5956.         /* Update partition information */
  5957.         if (FF_MULTI_PARTITION && part != 0) {  /* Created in the existing partition */
  5958.                 /* Update system ID in the partition table */
  5959.                 if (disk_read(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);      /* Read the MBR */
  5960.                 buf[MBR_Table + (part - 1) * SZ_PTE + PTE_System] = sys;                /* Set system ID */
  5961.                 if (disk_write(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);     /* Write it back to the MBR */
  5962.         } else {                                                                /* Created as a new single partition */
  5963.                 if (!(opt & FM_SFD)) {  /* Create partition table if in FDISK format */
  5964.                         mem_set(buf, 0, ss);
  5965.                         st_word(buf + BS_55AA, 0xAA55);         /* MBR signature */
  5966.                         pte = buf + MBR_Table;                          /* Create partition table for single partition in the drive */
  5967.                         pte[PTE_Boot] = 0;                                      /* Boot indicator */
  5968.                         pte[PTE_StHead] = 1;                            /* Start head */
  5969.                         pte[PTE_StSec] = 1;                                     /* Start sector */
  5970.                         pte[PTE_StCyl] = 0;                                     /* Start cylinder */
  5971.                         pte[PTE_System] = sys;                          /* System type */
  5972.                         n = (b_vol + sz_vol) / (63 * 255);      /* (End CHS may be invalid) */
  5973.                         pte[PTE_EdHead] = 254;                          /* End head */
  5974.                         pte[PTE_EdSec] = (BYTE)(((n >> 2) & 0xC0) | 63);        /* End sector */
  5975.                         pte[PTE_EdCyl] = (BYTE)n;                       /* End cylinder */
  5976.                         st_dword(pte + PTE_StLba, b_vol);       /* Start offset in LBA */
  5977.                         st_dword(pte + PTE_SizLba, sz_vol);     /* Size in sectors */
  5978.                         if (disk_write(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);     /* Write it to the MBR */
  5979.                 }
  5980.         }
  5981.  
  5982.         if (disk_ioctl(pdrv, CTRL_SYNC, 0) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);
  5983.  
  5984.         LEAVE_MKFS(FR_OK);
  5985. }
  5986.  
  5987.  
  5988.  
  5989. #if FF_MULTI_PARTITION
  5990. /*-----------------------------------------------------------------------*/
  5991. /* Create Partition Table on the Physical Drive                          */
  5992. /*-----------------------------------------------------------------------*/
  5993.  
  5994. FRESULT f_fdisk (
  5995.         BYTE pdrv,                      /* Physical drive number */
  5996.         const DWORD* szt,       /* Pointer to the size table for each partitions */
  5997.         void* work                      /* Pointer to the working buffer (null: use heap memory) */
  5998. )
  5999. {
  6000.         UINT i, n, sz_cyl, tot_cyl, b_cyl, e_cyl, p_cyl;
  6001.         BYTE s_hd, e_hd, *p, *buf = (BYTE*)work;
  6002.         DSTATUS stat;
  6003.         DWORD sz_disk, sz_part, s_part;
  6004.         FRESULT res;
  6005.  
  6006.  
  6007.         stat = disk_initialize(pdrv);
  6008.         if (stat & STA_NOINIT) return FR_NOT_READY;
  6009.         if (stat & STA_PROTECT) return FR_WRITE_PROTECTED;
  6010.         if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_disk)) return FR_DISK_ERR;
  6011.  
  6012.         buf = (BYTE*)work;
  6013. #if FF_USE_LFN == 3
  6014.         if (!buf) buf = ff_memalloc(FF_MAX_SS); /* Use heap memory for working buffer */
  6015. #endif
  6016.         if (!buf) return FR_NOT_ENOUGH_CORE;
  6017.  
  6018.         /* Determine the CHS without any consideration of the drive geometry */
  6019.         for (n = 16; n < 256 && sz_disk / n / 63 > 1024; n *= 2) ;
  6020.         if (n == 256) n--;
  6021.         e_hd = (BYTE)(n - 1);
  6022.         sz_cyl = 63 * n;
  6023.         tot_cyl = sz_disk / sz_cyl;
  6024.  
  6025.         /* Create partition table */
  6026.         mem_set(buf, 0, FF_MAX_SS);
  6027.         p = buf + MBR_Table; b_cyl = 0;
  6028.         for (i = 0; i < 4; i++, p += SZ_PTE) {
  6029.                 p_cyl = (szt[i] <= 100U) ? (DWORD)tot_cyl * szt[i] / 100 : szt[i] / sz_cyl;     /* Number of cylinders */
  6030.                 if (p_cyl == 0) continue;
  6031.                 s_part = (DWORD)sz_cyl * b_cyl;
  6032.                 sz_part = (DWORD)sz_cyl * p_cyl;
  6033.                 if (i == 0) {   /* Exclude first track of cylinder 0 */
  6034.                         s_hd = 1;
  6035.                         s_part += 63; sz_part -= 63;
  6036.                 } else {
  6037.                         s_hd = 0;
  6038.                 }
  6039.                 e_cyl = b_cyl + p_cyl - 1;      /* End cylinder */
  6040.                 if (e_cyl >= tot_cyl) LEAVE_MKFS(FR_INVALID_PARAMETER);
  6041.  
  6042.                 /* Set partition table */
  6043.                 p[1] = s_hd;                                            /* Start head */
  6044.                 p[2] = (BYTE)(((b_cyl >> 2) & 0xC0) | 1);       /* Start sector */
  6045.                 p[3] = (BYTE)b_cyl;                                     /* Start cylinder */
  6046.                 p[4] = 0x07;                                            /* System type (temporary setting) */
  6047.                 p[5] = e_hd;                                            /* End head */
  6048.                 p[6] = (BYTE)(((e_cyl >> 2) & 0xC0) | 63);      /* End sector */
  6049.                 p[7] = (BYTE)e_cyl;                                     /* End cylinder */
  6050.                 st_dword(p + 8, s_part);                        /* Start sector in LBA */
  6051.                 st_dword(p + 12, sz_part);                      /* Number of sectors */
  6052.  
  6053.                 /* Next partition */
  6054.                 b_cyl += p_cyl;
  6055.         }
  6056.         st_word(p, 0xAA55);             /* MBR signature (always at offset 510) */
  6057.  
  6058.         /* Write it to the MBR */
  6059.         res = (disk_write(pdrv, buf, 0, 1) == RES_OK && disk_ioctl(pdrv, CTRL_SYNC, 0) == RES_OK) ? FR_OK : FR_DISK_ERR;
  6060.         LEAVE_MKFS(res);
  6061. }
  6062.  
  6063. #endif /* FF_MULTI_PARTITION */
  6064. #endif /* FF_USE_MKFS && !FF_FS_READONLY */
  6065.  
  6066.  
  6067.  
  6068.  
  6069. #if FF_USE_STRFUNC
  6070. #if FF_USE_LFN && FF_LFN_UNICODE && (FF_STRF_ENCODE < 0 || FF_STRF_ENCODE > 3)
  6071. #error Wrong FF_STRF_ENCODE setting
  6072. #endif
  6073. /*-----------------------------------------------------------------------*/
  6074. /* Get a String from the File                                            */
  6075. /*-----------------------------------------------------------------------*/
  6076.  
  6077. TCHAR* f_gets (
  6078.         TCHAR* buff,    /* Pointer to the string buffer to read */
  6079.         int len,                /* Size of string buffer (items) */
  6080.         FIL* fp                 /* Pointer to the file object */
  6081. )
  6082. {
  6083.         int nc = 0;
  6084.         TCHAR *p = buff;
  6085.         BYTE s[4];
  6086.         UINT rc;
  6087.         DWORD dc;
  6088. #if FF_USE_LFN && FF_LFN_UNICODE && FF_STRF_ENCODE <= 2
  6089.         WCHAR wc;
  6090. #endif
  6091. #if FF_USE_LFN && FF_LFN_UNICODE && FF_STRF_ENCODE == 3
  6092.         UINT ct;
  6093. #endif
  6094.  
  6095. #if FF_USE_LFN && FF_LFN_UNICODE                        /* With code conversion (Unicode API) */
  6096.         /* Make a room for the character and terminator  */
  6097.         if (FF_LFN_UNICODE == 1) len -= (FF_STRF_ENCODE == 0) ? 1 : 2;
  6098.         if (FF_LFN_UNICODE == 2) len -= (FF_STRF_ENCODE == 0) ? 3 : 4;
  6099.         if (FF_LFN_UNICODE == 3) len -= 1;
  6100.         while (nc < len) {
  6101. #if FF_STRF_ENCODE == 0         /* Read a character in ANSI/OEM */
  6102.                 f_read(fp, s, 1, &rc);
  6103.                 if (rc != 1) break;
  6104.                 wc = s[0];
  6105.                 if (dbc_1st((BYTE)wc)) {
  6106.                         f_read(fp, s, 1, &rc);
  6107.                         if (rc != 1 || !dbc_2nd(s[0])) continue;
  6108.                         wc = wc << 8 | s[0];
  6109.                 }
  6110.                 dc = ff_oem2uni(wc, CODEPAGE);
  6111.                 if (dc == 0) continue;
  6112. #elif FF_STRF_ENCODE == 1 || FF_STRF_ENCODE == 2        /* Read a character in UTF-16LE/BE */
  6113.                 f_read(fp, s, 2, &rc);
  6114.                 if (rc != 2) break;
  6115.                 dc = (FF_STRF_ENCODE == 1) ? ld_word(s) : s[0] << 8 | s[1];
  6116.                 if (IsSurrogateL(dc)) continue;
  6117.                 if (IsSurrogateH(dc)) {
  6118.                         f_read(fp, s, 2, &rc);
  6119.                         if (rc != 2) break;
  6120.                         wc = (FF_STRF_ENCODE == 1) ? ld_word(s) : s[0] << 8 | s[1];
  6121.                         if (!IsSurrogateL(wc)) continue;
  6122.                         dc = ((dc & 0x3FF) + 0x40) << 10 | (wc & 0x3FF);
  6123.                 }
  6124. #else   /* Read a character in UTF-8 */
  6125.                 f_read(fp, s, 1, &rc);
  6126.                 if (rc != 1) break;
  6127.                 dc = s[0];
  6128.                 if (dc >= 0x80) {       /* Multi-byte character? */
  6129.                         ct = 0;
  6130.                         if ((dc & 0xE0) == 0xC0) { dc &= 0x1F; ct = 1; }        /* 2-byte? */
  6131.                         if ((dc & 0xF0) == 0xE0) { dc &= 0x0F; ct = 2; }        /* 3-byte? */
  6132.                         if ((dc & 0xF8) == 0xF0) { dc &= 0x07; ct = 3; }        /* 4-byte? */
  6133.                         if (ct == 0) continue;
  6134.                         f_read(fp, s, ct, &rc);         /* Get trailing bytes */
  6135.                         if (rc != ct) break;
  6136.                         rc = 0;
  6137.                         do {    /* Merge trailing bytes */
  6138.                                 if ((s[rc] & 0xC0) != 0x80) break;
  6139.                                 dc = dc << 6 | (s[rc] & 0x3F);
  6140.                         } while (++rc < ct);
  6141.                         if (rc != ct || dc < 0x80 || IsSurrogate(dc) || dc >= 0x110000) continue;       /* Wrong encoding? */
  6142.                 }
  6143. #endif
  6144.                 if (FF_USE_STRFUNC == 2 && dc == '\r') continue;        /* Strip \r off if needed */
  6145. #if FF_LFN_UNICODE == 1 || FF_LFN_UNICODE == 3  /* Output it in UTF-16/32 encoding */
  6146.                 if (FF_LFN_UNICODE == 1 && dc >= 0x10000) {     /* Out of BMP at UTF-16? */
  6147.                         *p++ = (TCHAR)(0xD800 | ((dc >> 10) - 0x40)); nc++;     /* Make and output high surrogate */
  6148.                         dc = 0xDC00 | (dc & 0x3FF);             /* Make low surrogate */
  6149.                 }
  6150.                 *p++ = (TCHAR)dc; nc++;
  6151.                 if (dc == '\n') break;  /* End of line? */
  6152. #elif FF_LFN_UNICODE == 2               /* Output it in UTF-8 encoding */
  6153.                 if (dc < 0x80) {        /* 1-byte */
  6154.                         *p++ = (TCHAR)dc;
  6155.                         nc++;
  6156.                         if (dc == '\n') break;  /* End of line? */
  6157.                 } else {
  6158.                         if (dc < 0x800) {               /* 2-byte */
  6159.                                 *p++ = (TCHAR)(0xC0 | (dc >> 6 & 0x1F));
  6160.                                 *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F));
  6161.                                 nc += 2;
  6162.                         } else {
  6163.                                 if (dc < 0x10000) {     /* 3-byte */
  6164.                                         *p++ = (TCHAR)(0xE0 | (dc >> 12 & 0x0F));
  6165.                                         *p++ = (TCHAR)(0x80 | (dc >> 6 & 0x3F));
  6166.                                         *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F));
  6167.                                         nc += 3;
  6168.                                 } else {                        /* 4-byte */
  6169.                                         *p++ = (TCHAR)(0xF0 | (dc >> 18 & 0x07));
  6170.                                         *p++ = (TCHAR)(0x80 | (dc >> 12 & 0x3F));
  6171.                                         *p++ = (TCHAR)(0x80 | (dc >> 6 & 0x3F));
  6172.                                         *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F));
  6173.                                         nc += 4;
  6174.                                 }
  6175.                         }
  6176.                 }
  6177. #endif
  6178.         }
  6179.  
  6180. #else                   /* Byte-by-byte without any conversion (ANSI/OEM API) */
  6181.         len -= 1;       /* Make a room for the terminator */
  6182.         while (nc < len) {
  6183.                 f_read(fp, s, 1, &rc);
  6184.                 if (rc != 1) break;
  6185.                 dc = s[0];
  6186.                 if (FF_USE_STRFUNC == 2 && dc == '\r') continue;
  6187.                 *p++ = (TCHAR)dc; nc++;
  6188.                 if (dc == '\n') break;
  6189.         }
  6190. #endif
  6191.  
  6192.         *p = 0;         /* Terminate the string */
  6193.         return nc ? buff : 0;   /* When no data read due to EOF or error, return with error. */
  6194. }
  6195.  
  6196.  
  6197.  
  6198.  
  6199. #if !FF_FS_READONLY
  6200. #include <stdarg.h>
  6201. /*-----------------------------------------------------------------------*/
  6202. /* Put a Character to the File                                           */
  6203. /*-----------------------------------------------------------------------*/
  6204.  
  6205. typedef struct {        /* Putchar output buffer and work area */
  6206.         FIL *fp;                /* Ptr to the writing file */
  6207.         int idx, nchr;  /* Write index of buf[] (-1:error), number of encoding units written */
  6208. #if FF_USE_LFN && FF_LFN_UNICODE == 1
  6209.         WCHAR hs;
  6210. #elif FF_USE_LFN && FF_LFN_UNICODE == 2
  6211.         BYTE bs[4];
  6212.         UINT wi, ct;
  6213. #endif
  6214.         BYTE buf[64];   /* Write buffer */
  6215. } putbuff;
  6216.  
  6217.  
  6218. static void putc_bfd (          /* Buffered write with code conversion */
  6219.         putbuff* pb,
  6220.         TCHAR c
  6221. )
  6222. {
  6223.         UINT n;
  6224.         int i, nc;
  6225. #if FF_USE_LFN && FF_LFN_UNICODE
  6226.         WCHAR hs, wc;
  6227. #if FF_LFN_UNICODE == 2
  6228.         DWORD dc;
  6229.         TCHAR *tp;
  6230. #endif
  6231. #endif
  6232.  
  6233.         if (FF_USE_STRFUNC == 2 && c == '\n') {  /* LF -> CRLF conversion */
  6234.                 putc_bfd(pb, '\r');
  6235.         }
  6236.  
  6237.         i = pb->idx;                    /* Write index of pb->buf[] */
  6238.         if (i < 0) return;
  6239.         nc = pb->nchr;                  /* Write unit counter */
  6240.  
  6241. #if FF_USE_LFN && FF_LFN_UNICODE
  6242. #if FF_LFN_UNICODE == 1         /* UTF-16 input */
  6243.         if (IsSurrogateH(c)) {
  6244.                 pb->hs = c; return;
  6245.         }
  6246.         hs = pb->hs; pb->hs = 0;
  6247.         if (hs != 0) {
  6248.                 if (!IsSurrogateL(c)) hs = 0;
  6249.         } else {
  6250.                 if (IsSurrogateL(c)) return;
  6251.         }
  6252.         wc = c;
  6253. #elif FF_LFN_UNICODE == 2       /* UTF-8 input */
  6254.         for (;;) {
  6255.                 if (pb->ct == 0) {      /* Out of multi-byte sequence? */
  6256.                         pb->bs[pb->wi = 0] = (BYTE)c;   /* Save 1st byte */
  6257.                         if ((BYTE)c < 0x80) break;                                      /* 1-byte? */
  6258.                         if (((BYTE)c & 0xE0) == 0xC0) pb->ct = 1;       /* 2-byte? */
  6259.                         if (((BYTE)c & 0xF0) == 0xE0) pb->ct = 2;       /* 3-byte? */
  6260.                         if (((BYTE)c & 0xF1) == 0xF0) pb->ct = 3;       /* 4-byte? */
  6261.                         return;
  6262.                 } else {                                /* In the multi-byte sequence */
  6263.                         if (((BYTE)c & 0xC0) != 0x80) { /* Broken sequence? */
  6264.                                 pb->ct = 0; continue;
  6265.                         }
  6266.                         pb->bs[++pb->wi] = (BYTE)c;     /* Save the trailing byte */
  6267.                         if (--pb->ct == 0) break;       /* End of multi-byte sequence? */
  6268.                         return;
  6269.                 }
  6270.         }
  6271.         tp = (TCHAR*)pb->bs;
  6272.         dc = tchar2uni(&tp);    /* UTF-8 ==> UTF-16 */
  6273.         if (dc == 0xFFFFFFFF) return;
  6274.         wc = (WCHAR)dc;
  6275.         hs = (WCHAR)(dc >> 16);
  6276. #elif FF_LFN_UNICODE == 3       /* UTF-32 input */
  6277.         if (IsSurrogate(c) || c >= 0x110000) return;
  6278.         if (c >= 0x10000) {
  6279.                 hs = (WCHAR)(0xD800 | ((c >> 10) - 0x40));      /* Make high surrogate */
  6280.                 wc = 0xDC00 | (c & 0x3FF);                                      /* Make low surrogate */
  6281.         } else {
  6282.                 hs = 0;
  6283.                 wc = (WCHAR)c;
  6284.         }
  6285. #endif
  6286.  
  6287. #if FF_STRF_ENCODE == 1         /* Write a character in UTF-16LE */
  6288.         if (hs != 0) {
  6289.                 st_word(&pb->buf[i], hs);
  6290.                 i += 2;
  6291.                 nc++;
  6292.         }
  6293.         st_word(&pb->buf[i], wc);
  6294.         i += 2;
  6295. #elif FF_STRF_ENCODE == 2       /* Write a character in UTF-16BE */
  6296.         if (hs != 0) {
  6297.                 pb->buf[i++] = (BYTE)(hs >> 8);
  6298.                 pb->buf[i++] = (BYTE)hs;
  6299.                 nc++;
  6300.         }
  6301.         pb->buf[i++] = (BYTE)(wc >> 8);
  6302.         pb->buf[i++] = (BYTE)wc;
  6303. #elif FF_STRF_ENCODE == 3       /* Write it in UTF-8 */
  6304.         if (hs != 0) {                          /* 4-byte */
  6305.                 nc += 3;
  6306.                 hs = (hs & 0x3FF) + 0x40;
  6307.                 pb->buf[i++] = (BYTE)(0xF0 | hs >> 8);
  6308.                 pb->buf[i++] = (BYTE)(0x80 | (hs >> 2 & 0x3F));
  6309.                 pb->buf[i++] = (BYTE)(0x80 | (hs & 3) << 4 | (wc >> 6 & 0x0F));
  6310.                 pb->buf[i++] = (BYTE)(0x80 | (wc & 0x3F));
  6311.         } else {
  6312.                 if (wc < 0x80) {                /* 1-byte */
  6313.                         pb->buf[i++] = (BYTE)wc;
  6314.                 } else {
  6315.                         if (wc < 0x800) {       /* 2-byte */
  6316.                                 nc += 1;
  6317.                                 pb->buf[i++] = (BYTE)(0xC0 | wc >> 6);
  6318.                         } else {                        /* 3-byte */
  6319.                                 nc += 2;
  6320.                                 pb->buf[i++] = (BYTE)(0xE0 | wc >> 12);
  6321.                                 pb->buf[i++] = (BYTE)(0x80 | (wc >> 6 & 0x3F));
  6322.                         }
  6323.                         pb->buf[i++] = (BYTE)(0x80 | (wc & 0x3F));
  6324.                 }
  6325.         }
  6326. #else                                           /* Write it in ANSI/OEM */
  6327.         if (hs != 0) return;
  6328.         wc = ff_uni2oem(wc, CODEPAGE);  /* UTF-16 ==> ANSI/OEM */
  6329.         if (wc == 0) return;
  6330.         if (wc >= 0x100) {
  6331.                 pb->buf[i++] = (BYTE)(wc >> 8); nc++;
  6332.         }
  6333.         pb->buf[i++] = (BYTE)wc;
  6334. #endif
  6335.  
  6336. #else                                                                   /* ANSI/OEM input (without re-encode) */
  6337.         pb->buf[i++] = (BYTE)c;
  6338. #endif
  6339.  
  6340.         if (i >= (int)(sizeof pb->buf) - 4) {   /* Write buffered characters to the file */
  6341.                 f_write(pb->fp, pb->buf, (UINT)i, &n);
  6342.                 i = (n == (UINT)i) ? 0 : -1;
  6343.         }
  6344.         pb->idx = i;
  6345.         pb->nchr = nc + 1;
  6346. }
  6347.  
  6348.  
  6349. static int putc_flush (         /* Flush left characters in the buffer */
  6350.         putbuff* pb
  6351. )
  6352. {
  6353.         UINT nw;
  6354.  
  6355.         if (   pb->idx >= 0     /* Flush buffered characters to the file */
  6356.                 && f_write(pb->fp, pb->buf, (UINT)pb->idx, &nw) == FR_OK
  6357.                 && (UINT)pb->idx == nw) return pb->nchr;
  6358.         return EOF;
  6359. }
  6360.  
  6361.  
  6362. static void putc_init (         /* Initialize write buffer */
  6363.         putbuff* pb,
  6364.         FIL* fp
  6365. )
  6366. {
  6367.         mem_set(pb, 0, sizeof (putbuff));
  6368.         pb->fp = fp;
  6369. }
  6370.  
  6371.  
  6372.  
  6373. int f_putc (
  6374.         TCHAR c,        /* A character to be output */
  6375.         FIL* fp         /* Pointer to the file object */
  6376. )
  6377. {
  6378.         putbuff pb;
  6379.  
  6380.  
  6381.         putc_init(&pb, fp);
  6382.         putc_bfd(&pb, c);       /* Put the character */
  6383.         return putc_flush(&pb);
  6384. }
  6385.  
  6386.  
  6387.  
  6388.  
  6389. /*-----------------------------------------------------------------------*/
  6390. /* Put a String to the File                                              */
  6391. /*-----------------------------------------------------------------------*/
  6392.  
  6393. int f_puts (
  6394.         const TCHAR* str,       /* Pointer to the string to be output */
  6395.         FIL* fp                         /* Pointer to the file object */
  6396. )
  6397. {
  6398.         putbuff pb;
  6399.  
  6400.  
  6401.         putc_init(&pb, fp);
  6402.         while (*str) putc_bfd(&pb, *str++);             /* Put the string */
  6403.         return putc_flush(&pb);
  6404. }
  6405.  
  6406.  
  6407.  
  6408.  
  6409. /*-----------------------------------------------------------------------*/
  6410. /* Put a Formatted String to the File                                    */
  6411. /*-----------------------------------------------------------------------*/
  6412.  
  6413. int f_printf (
  6414.         FIL* fp,                        /* Pointer to the file object */
  6415.         const TCHAR* fmt,       /* Pointer to the format string */
  6416.         ...                                     /* Optional arguments... */
  6417. )
  6418. {
  6419.         va_list arp;
  6420.         putbuff pb;
  6421.         BYTE f, r;
  6422.         UINT i, j, w;
  6423.         DWORD v;
  6424.         TCHAR c, d, str[32], *p;
  6425.  
  6426.  
  6427.         putc_init(&pb, fp);
  6428.  
  6429.         va_start(arp, fmt);
  6430.  
  6431.         for (;;) {
  6432.                 c = *fmt++;
  6433.                 if (c == 0) break;                      /* End of string */
  6434.                 if (c != '%') {                         /* Non escape character */
  6435.                         putc_bfd(&pb, c);
  6436.                         continue;
  6437.                 }
  6438.                 w = f = 0;
  6439.                 c = *fmt++;
  6440.                 if (c == '0') {                         /* Flag: '0' padding */
  6441.                         f = 1; c = *fmt++;
  6442.                 } else {
  6443.                         if (c == '-') {                 /* Flag: left justified */
  6444.                                 f = 2; c = *fmt++;
  6445.                         }
  6446.                 }
  6447.                 if (c == '*') {                         /* Minimum width by argument */
  6448.                         w = va_arg(arp, int);
  6449.                         c = *fmt++;
  6450.                 } else {
  6451.                         while (IsDigit(c)) {    /* Minimum width */
  6452.                                 w = w * 10 + c - '0';
  6453.                                 c = *fmt++;
  6454.                         }
  6455.                 }
  6456.                 if (c == 'l' || c == 'L') {     /* Type prefix: Size is long int */
  6457.                         f |= 4; c = *fmt++;
  6458.                 }
  6459.                 if (c == 0) break;
  6460.                 d = c;
  6461.                 if (IsLower(d)) d -= 0x20;
  6462.                 switch (d) {                            /* Atgument type is... */
  6463.                 case 'S' :                                      /* String */
  6464.                         p = va_arg(arp, TCHAR*);
  6465.                         for (j = 0; p[j]; j++) ;
  6466.                         if (!(f & 2)) {                                         /* Right padded */
  6467.                                 while (j++ < w) putc_bfd(&pb, ' ') ;
  6468.                         }
  6469.                         while (*p) putc_bfd(&pb, *p++) ;                /* String body */
  6470.                         while (j++ < w) putc_bfd(&pb, ' ') ;    /* Left padded */
  6471.                         continue;
  6472.  
  6473.                 case 'C' :                                      /* Character */
  6474.                         putc_bfd(&pb, (TCHAR)va_arg(arp, int)); continue;
  6475.  
  6476.                 case 'B' :                                      /* Unsigned binary */
  6477.                         r = 2; break;
  6478.  
  6479.                 case 'O' :                                      /* Unsigned octal */
  6480.                         r = 8; break;
  6481.  
  6482.                 case 'D' :                                      /* Signed decimal */
  6483.                 case 'U' :                                      /* Unsigned decimal */
  6484.                         r = 10; break;
  6485.  
  6486.                 case 'X' :                                      /* Unsigned hexdecimal */
  6487.                         r = 16; break;
  6488.  
  6489.                 default:                                        /* Unknown type (pass-through) */
  6490.                         putc_bfd(&pb, c); continue;
  6491.                 }
  6492.  
  6493.                 /* Get an argument and put it in numeral */
  6494.                 v = (f & 4) ? (DWORD)va_arg(arp, long) : ((d == 'D') ? (DWORD)(long)va_arg(arp, int) : (DWORD)va_arg(arp, unsigned int));
  6495.                 if (d == 'D' && (v & 0x80000000)) {
  6496.                         v = 0 - v;
  6497.                         f |= 8;
  6498.                 }
  6499.                 i = 0;
  6500.                 do {
  6501.                         d = (TCHAR)(v % r); v /= r;
  6502.                         if (d > 9) d += (c == 'x') ? 0x27 : 0x07;
  6503.                         str[i++] = d + '0';
  6504.                 } while (v && i < sizeof str / sizeof *str);
  6505.                 if (f & 8) str[i++] = '-';
  6506.                 j = i; d = (f & 1) ? '0' : ' ';
  6507.                 if (!(f & 2)) {
  6508.                         while (j++ < w) putc_bfd(&pb, d);       /* Right pad */
  6509.                 }
  6510.                 do {
  6511.                         putc_bfd(&pb, str[--i]);                        /* Number body */
  6512.                 } while (i);
  6513.                 while (j++ < w) putc_bfd(&pb, d);               /* Left pad */
  6514.         }
  6515.  
  6516.         va_end(arp);
  6517.  
  6518.         return putc_flush(&pb);
  6519. }
  6520.  
  6521. #endif /* !FF_FS_READONLY */
  6522. #endif /* FF_USE_STRFUNC */
  6523.  
  6524.  
  6525.  
  6526. #if FF_CODE_PAGE == 0
  6527. /*-----------------------------------------------------------------------*/
  6528. /* Set Active Codepage for the Path Name                                 */
  6529. /*-----------------------------------------------------------------------*/
  6530.  
  6531. FRESULT f_setcp (
  6532.         WORD cp         /* Value to be set as active code page */
  6533. )
  6534. {
  6535.         static const WORD       validcp[] = {  437,   720,   737,   771,   775,   850,   852,   857,   860,   861,   862,   863,   864,   865,   866,   869,   932,   936,   949,   950, 0};
  6536.         static const BYTE* const tables[] = {Ct437, Ct720, Ct737, Ct771, Ct775, Ct850, Ct852, Ct857, Ct860, Ct861, Ct862, Ct863, Ct864, Ct865, Ct866, Ct869, Dc932, Dc936, Dc949, Dc950, 0};
  6537.         UINT i;
  6538.  
  6539.  
  6540.         for (i = 0; validcp[i] != 0 && validcp[i] != cp; i++) ; /* Find the code page */
  6541.         if (validcp[i] != cp) return FR_INVALID_PARAMETER;      /* Not found? */
  6542.  
  6543.         CodePage = cp;
  6544.         if (cp >= 900) {        /* DBCS */
  6545.                 ExCvt = 0;
  6546.                 DbcTbl = tables[i];
  6547.         } else {                        /* SBCS */
  6548.                 ExCvt = tables[i];
  6549.                 DbcTbl = 0;
  6550.         }
  6551.         return FR_OK;
  6552. }
  6553. #endif  /* FF_CODE_PAGE == 0 */
  6554.  
  6555.