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