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