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