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