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