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