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