]> git.sur5r.net Git - freertos/blob - FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_dir.c
Add the Labs projects provided in the V10.2.1_191129 zip file.
[freertos] / FreeRTOS-Labs / Source / FreeRTOS-Plus-FAT / ff_dir.c
1 /*\r
2  * FreeRTOS+FAT build 191128 - Note:  FreeRTOS+FAT is still in the lab!\r
3  * Copyright (C) 2018 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  * Authors include James Walmsley, Hein Tibosch and Richard Barry\r
5  *\r
6  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
7  * this software and associated documentation files (the "Software"), to deal in\r
8  * the Software without restriction, including without limitation the rights to\r
9  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
10  * the Software, and to permit persons to whom the Software is furnished to do so,\r
11  * subject to the following conditions:\r
12  *\r
13  * The above copyright notice and this permission notice shall be included in all\r
14  * copies or substantial portions of the Software.\r
15  *\r
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
18  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
19  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
22  *\r
23  * https://www.FreeRTOS.org\r
24  *\r
25  */\r
26 \r
27 /**\r
28  *      @file           ff_dir.c\r
29  *      @ingroup        DIR\r
30  *\r
31  *      @defgroup       DIR Handles Directory Traversal\r
32  *      @brief          Handles DIR access and traversal.\r
33  *\r
34  *      Provides FindFirst() and FindNext() Interfaces\r
35  **/\r
36 \r
37 #include "ff_headers.h"\r
38 \r
39 #include <stdio.h>\r
40 \r
41 #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
42 #include <wchar.h>\r
43 #endif\r
44 \r
45 #if defined( WIN32 )\r
46         #define wcsicmp _wcsicmp\r
47 #else\r
48         #define wcsicmp wcscasecmp\r
49         #include <ctype.h>\r
50 #endif\r
51 \r
52 /* Calculate a simple LFN checmsum. */\r
53 static uint8_t FF_CreateChkSum( const uint8_t *pa_pShortName );\r
54 \r
55 static BaseType_t FF_ShortNameExists( FF_IOManager_t *pxIOManager, uint32_t ulDirCluster, char *pcShortName, FF_Error_t *pxError );\r
56 \r
57 #if( ffconfigSHORTNAME_CASE != 0 )\r
58         /* For short-name entries, NT/XP etc store case information in byte 0x0c\r
59          * Use this to show proper case of "README.txt" or "source.H".\r
60          */\r
61         #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
62                 static void FF_CaseShortName( FF_T_WCHAR *pcName, uint8_t attrib );\r
63         #else\r
64                 static void FF_CaseShortName( char *pcName, uint8_t attrib );\r
65         #endif\r
66 #endif /* ffconfigSHORTNAME_CASE */\r
67 \r
68 #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
69 \r
70         /* For unicode, the short name can be expanded to wchar\r
71          * by inserting zero's.\r
72          */\r
73         static void FF_ShortNameExpand( FF_T_WCHAR * );\r
74 \r
75 #endif\r
76 \r
77 /*\r
78  * Transform a name as stored on disk "README__TXT"\r
79  * to a nul-terminated string: "README.TXT", "FILE001".\r
80  * A dot is only added if an extension is present.\r
81  */\r
82 static void FF_ProcessShortName( char *pcName );\r
83 \r
84 #if( ffconfigTIME_SUPPORT != 0 )\r
85         static void FF_PlaceTime( uint8_t *pucEntryBuffer, uint32_t Offset, FF_SystemTime_t *pxTime );\r
86         static void FF_PlaceDate( uint8_t *pucEntryBuffer, uint32_t Offset, FF_SystemTime_t *pxTime );\r
87         static void FF_GetTime( FF_SystemTime_t *pxTime, const uint8_t *pucEntryBuffer, uint32_t ulOffset );\r
88         static void FF_GetDate( FF_SystemTime_t *pxTime, const uint8_t *pucEntryBuffer, uint32_t ulOffset );\r
89 #endif /* ffconfigTIME_SUPPORT */\r
90 static FF_Error_t FF_Traverse( FF_IOManager_t *pxIOManager, uint32_t ulEntry, FF_FetchContext_t *pxContext );\r
91 static int32_t FF_FindFreeDirent( FF_IOManager_t *pxIOManager, FF_FindParams_t *pxFindParams, uint16_t usSequential );\r
92 \r
93 #if( ffconfigLFN_SUPPORT != 0 )\r
94         static int8_t FF_CreateLFNEntry( uint8_t *pucEntryBuffer, uint8_t *pcName, UBaseType_t uxNameLength, UBaseType_t uxLFN, uint8_t ucCheckSum );\r
95 #endif /* ffconfigLFN_SUPPORT */\r
96 \r
97 static BaseType_t FF_ValidShortChar( char cChar );\r
98 \r
99 #if( ffconfigLFN_SUPPORT != 0 )\r
100         #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
101                 static FF_Error_t FF_CreateLFNs( FF_IOManager_t *pxIOManager, uint32_t ulDirCluster, FF_T_WCHAR *pcName, uint8_t ucCheckSum, uint16_t usEntry );\r
102         #else\r
103                 static FF_Error_t FF_CreateLFNs( FF_IOManager_t *pxIOManager, uint32_t ulDirCluster, char *pcName, uint8_t ucCheckSum, uint16_t usEntry );\r
104         #endif\r
105 #endif\r
106 \r
107 #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
108         static void FF_MakeNameCompliant( FF_T_WCHAR *pcName );\r
109 #else\r
110         static void FF_MakeNameCompliant( char *pcName );\r
111 #endif\r
112 \r
113 #if ( FF_NOSTRCASECMP == 0 )\r
114         static portINLINE unsigned char prvToLower( unsigned char c )\r
115         {\r
116         unsigned char cReturnChar;\r
117                 if( c >= 'A' && c <= 'Z' )\r
118                 {\r
119                         cReturnChar = c + 0x20;\r
120                 }\r
121                 else\r
122                 {\r
123                         cReturnChar = c;\r
124                 }\r
125 \r
126                 return cReturnChar;\r
127         }\r
128 \r
129         int strcasecmp( const char *pcString1, const char *pcString2 )\r
130         {\r
131                 unsigned char c1,c2;\r
132                 do\r
133                 {\r
134                         c1 = *pcString1++;\r
135                         c2 = *pcString2++;\r
136                         c1 = ( unsigned char ) prvToLower( ( unsigned char ) c1 );\r
137                         c2 = ( unsigned char ) prvToLower( ( unsigned char ) c2 );\r
138                 }\r
139                 while( ( c1 == c2 ) && ( c1 != '\0' ) );\r
140 \r
141                 return ( int ) c1 - c2;\r
142         }       /* strcasecmp() */\r
143 #endif\r
144 /*-----------------------------------------------------------*/\r
145 \r
146 static uint8_t FF_CreateChkSum( const uint8_t *pa_pShortName )\r
147 {\r
148 uint8_t cNameLen;\r
149 uint8_t ChkSum = 0;\r
150 \r
151         for( cNameLen = 11; cNameLen != 0; cNameLen-- )\r
152         {\r
153                 ChkSum = ( uint8_t )\r
154                         ( ( ( ChkSum & 1 ) ? 0x80 : 0 ) + ( ChkSum >> 1 ) + *( pa_pShortName++ ) );\r
155         }\r
156 \r
157         return ChkSum;\r
158 }       /* FF_CreateChkSum() */\r
159 /*-----------------------------------------------------------*/\r
160 \r
161 /* _HT_ Does not need a wchar version because a short name is treated  a normal string of bytes */\r
162 static BaseType_t FF_ShortNameExists( FF_IOManager_t *pxIOManager, uint32_t ulDirCluster, char *pcShortName, FF_Error_t *pxError )\r
163 {\r
164 BaseType_t xIndex;\r
165 const uint8_t *pucEntryBuffer = NULL; /* initialisation not necessary, just for the compiler */\r
166 uint8_t ucAttrib;\r
167 FF_FetchContext_t xFetchContext;\r
168 char pcMyShortName[ FF_SIZEOF_DIRECTORY_ENTRY ];\r
169 BaseType_t xResult = -1;\r
170 \r
171 #if( ffconfigHASH_CACHE != 0 )\r
172         uint32_t ulHash;\r
173 #endif\r
174 \r
175         *pxError = FF_ERR_NONE;\r
176 \r
177         #if( ffconfigHASH_CACHE != 0 )\r
178         {\r
179                 if( !FF_DirHashed( pxIOManager, ulDirCluster ) )\r
180                 {\r
181                         /* Hash the directory. */\r
182                         FF_HashDir( pxIOManager, ulDirCluster );\r
183                 }\r
184 \r
185                 #if ffconfigHASH_FUNCTION == CRC16\r
186                 {\r
187                         ulHash = ( uint32_t ) FF_GetCRC16( ( uint8_t * ) pcShortName, strlen( pcShortName ) );\r
188                 }\r
189                 #else /* ffconfigHASH_FUNCTION == CRC8 */\r
190                 {\r
191                         ulHash = ( uint32_t ) FF_GetCRC8( ( uint8_t * ) pcShortName, strlen( pcShortName ) );\r
192                 }\r
193                 #endif\r
194                 {\r
195                         /* FF_CheckDirentHash result: 0 not found, 1 found, -1 directory not hashed */\r
196                         xResult = FF_CheckDirentHash( pxIOManager, ulDirCluster, ulHash );\r
197                 }\r
198         }\r
199         #endif\r
200 \r
201         if( xResult < 0 )\r
202         {\r
203                 xResult = pdFALSE;\r
204                 *pxError = FF_InitEntryFetch( pxIOManager, ulDirCluster, &xFetchContext );\r
205 \r
206                 if( FF_isERR( *pxError ) == pdFALSE )\r
207                 {\r
208                         for( xIndex = 0; xIndex < FF_MAX_ENTRIES_PER_DIRECTORY; xIndex++ )\r
209                         {\r
210                                 /* Call FF_FetchEntryWithContext only once for every 512-byte block */\r
211                                 if( ( xIndex == 0 ) ||\r
212                                         ( pucEntryBuffer >= xFetchContext.pxBuffer->pucBuffer + ( FF_SIZEOF_SECTOR - FF_SIZEOF_DIRECTORY_ENTRY ) ) )\r
213                                 {\r
214                                         *pxError = FF_FetchEntryWithContext( pxIOManager, ( uint32_t ) xIndex, &xFetchContext, NULL );\r
215                                         if( FF_isERR( *pxError ) )\r
216                                         {\r
217                                                 break;\r
218                                         }\r
219                                         pucEntryBuffer = xFetchContext.pxBuffer->pucBuffer;\r
220                                 }\r
221                                 else\r
222                                 {\r
223                                         /* Advance 32 bytes to get the next directory entry. */\r
224                                         pucEntryBuffer += FF_SIZEOF_DIRECTORY_ENTRY;\r
225                                 }\r
226 \r
227                                 if( FF_isEndOfDir( pucEntryBuffer ) )\r
228                                 {\r
229                                         break;\r
230                                 }\r
231                                 if( FF_isDeleted( pucEntryBuffer ) == pdFALSE )\r
232                                 {\r
233                                         ucAttrib = FF_getChar( pucEntryBuffer, FF_FAT_DIRENT_ATTRIB );\r
234                                         if( ( ucAttrib & FF_FAT_ATTR_LFN ) != FF_FAT_ATTR_LFN )\r
235                                         {\r
236                                                 memcpy( pcMyShortName, pucEntryBuffer, sizeof( pcMyShortName ) );\r
237                                                 FF_ProcessShortName( pcMyShortName );\r
238                                                 if( strcmp( ( const char * )pcShortName, ( const char * )pcMyShortName ) == 0 )\r
239                                                 {\r
240                                                         xResult = pdTRUE;\r
241                                                         break;\r
242                                                 }\r
243                                         }\r
244                                 }\r
245                         } /* for ( xIndex = 0; xIndex < FF_MAX_ENTRIES_PER_DIRECTORY; xIndex++ ) */\r
246                 }\r
247                 *pxError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext );\r
248         }\r
249 \r
250     return xResult;\r
251 }       /* FF_ShortNameExists() */\r
252 /*-----------------------------------------------------------*/\r
253 \r
254 /* _HT_ When adding many files to a single directory, FF_FindEntryInDir was sometimes */\r
255 /* _HT_ called 3 times before inserting a single file. With these changes it is called one time only */\r
256 /* _HT_ pxFindParams caches some information: */\r
257 /* _HT_ 1: the first free entry 2: whether the short-name version already exists */\r
258 #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
259 uint32_t FF_FindEntryInDir( FF_IOManager_t *pxIOManager, FF_FindParams_t *pxFindParams, const FF_T_WCHAR *pcName, uint8_t pa_Attrib, FF_DirEnt_t *pxDirEntry, FF_Error_t *pxError )\r
260 #else\r
261 uint32_t FF_FindEntryInDir( FF_IOManager_t *pxIOManager, FF_FindParams_t *pxFindParams, const char *pcName, uint8_t pa_Attrib, FF_DirEnt_t *pxDirEntry, FF_Error_t *pxError )\r
262 #endif\r
263 {\r
264 FF_FetchContext_t xFetchContext;\r
265 /* const pointer to read from pBuffer */\r
266 const uint8_t *src = NULL;\r
267 /* As we're walking through a directory, we might as well\r
268 find the first free entry to help FF_FindFreeDirent( )\r
269 The result will be stored in 'pxFindParams->lFreeEntry' */\r
270 BaseType_t      entriesNeeded;\r
271 BaseType_t      freeCount = 0;\r
272 FF_Error_t xError;\r
273 /* If the file name fits into a short file name\r
274 then the existence of that short file name will be checked as well. */\r
275 BaseType_t      testShortname;\r
276 uint32_t xResult = 0ul;\r
277 #if( ffconfigUNICODE_UTF8_SUPPORT == 1 )\r
278         int32_t utf8Error;\r
279 #endif\r
280 \r
281 #if( ffconfigLFN_SUPPORT != 0 )\r
282         #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
283                 FF_T_WCHAR      *pcCurPtr;              /* Pointer to store a LFN. */\r
284                 FF_T_WCHAR      *pcLastPtr = pxDirEntry->pcFileName + sizeof( pxDirEntry->pcFileName );\r
285         #else\r
286                 char    *pcCurPtr;              /* Pointer to store a LFN. */\r
287                 char    *pcLastPtr = pxDirEntry->pcFileName + sizeof( pxDirEntry->pcFileName );\r
288         #endif /* ffconfigUNICODE_UTF16_SUPPORT */\r
289 \r
290         uint16_t lfnItem = 0;\r
291         uint8_t ucCheckSum = 0;\r
292         BaseType_t xLFNCount = 0;\r
293         BaseType_t xLFNTotal = 0;\r
294         uint8_t lastAttrib;\r
295 \r
296         BaseType_t xIndex;\r
297 #endif /* ffconfigLFN_SUPPORT */\r
298 \r
299         #if( ffconfigLFN_SUPPORT != 0 )\r
300         {\r
301                 #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
302                         BaseType_t      NameLen = ( BaseType_t ) wcslen( ( const char * )pcName );\r
303                 #else\r
304                         BaseType_t      NameLen = ( BaseType_t ) strlen( ( const char * )pcName );\r
305                 #endif\r
306                 /* Find enough places for the LFNs and the ShortName. */\r
307                 entriesNeeded = ( uint8_t )( ( NameLen + 12 ) / 13 ) + 1;\r
308         }\r
309         #else\r
310         {\r
311                 entriesNeeded = 1;\r
312         }\r
313         #endif /* ffconfigLFN_SUPPORT */\r
314 \r
315         if( ( pxFindParams->ulFlags & FIND_FLAG_FITS_SHORT_OK ) == FIND_FLAG_FITS_SHORT_OK )\r
316         {\r
317                 testShortname = pdTRUE;\r
318         }\r
319         else\r
320         {\r
321                 testShortname = pdFALSE;\r
322         }\r
323 \r
324         pxDirEntry->ucAttrib = 0;\r
325 \r
326         if( ( pxFindParams->ulFlags & FIND_FLAG_CREATE_FLAG ) != 0 )\r
327         {\r
328                 /* A file is to be created: keep track of the first free entry big enough\r
329                 to hold this file name. */\r
330                 pxFindParams->lFreeEntry = -1;\r
331         }\r
332         else\r
333         {\r
334                 pxFindParams->lFreeEntry = 0;\r
335         }\r
336 \r
337         xError = FF_InitEntryFetch( pxIOManager, pxFindParams->ulDirCluster, &xFetchContext );\r
338 \r
339         if( FF_isERR( xError ) == pdFALSE )\r
340         {\r
341                 for( pxDirEntry->usCurrentItem = 0; pxDirEntry->usCurrentItem < FF_MAX_ENTRIES_PER_DIRECTORY; pxDirEntry->usCurrentItem++ )\r
342                 {\r
343                         if( ( src == NULL ) ||\r
344                                 ( src >= xFetchContext.pxBuffer->pucBuffer + ( FF_SIZEOF_SECTOR - FF_SIZEOF_DIRECTORY_ENTRY ) ) )\r
345                         {\r
346                                 xError = FF_FetchEntryWithContext( pxIOManager, pxDirEntry->usCurrentItem, &xFetchContext, NULL );\r
347 \r
348                                 if( FF_isERR( xError ) != pdFALSE )\r
349                                 {\r
350                                         break;\r
351                                 }\r
352                                 src = xFetchContext.pxBuffer->pucBuffer;\r
353                         }\r
354                         else\r
355                         {\r
356                                 /* Advance 32 bytes. */\r
357                                 src += FF_SIZEOF_DIRECTORY_ENTRY;\r
358                         }\r
359 \r
360                         if( FF_isEndOfDir( src ) )\r
361                         {\r
362                                 /* 0x00 end-of-dir. */\r
363                                 break;\r
364                         }\r
365 \r
366                         if( FF_isDeleted( src ) )\r
367                         {\r
368                                 /* Entry not used or deleted. */\r
369                                 pxDirEntry->ucAttrib = 0;\r
370                                 if( ( pxFindParams->lFreeEntry < 0 ) && ( ++freeCount == entriesNeeded ) )\r
371                                 {\r
372                                         /* Remember the beginning entry in the sequential sequence. */\r
373                                         pxFindParams->lFreeEntry = ( pxDirEntry->usCurrentItem - ( entriesNeeded - 1 ) );\r
374                                 }\r
375                                 continue;\r
376                         }\r
377 \r
378                         /* The current entry is in use, so reset the free-entry-counter */\r
379                         freeCount = 0;\r
380                         #if( ffconfigLFN_SUPPORT != 0 )\r
381                         {\r
382                                 lastAttrib = pxDirEntry->ucAttrib;\r
383                         }\r
384                         #endif\r
385 \r
386                         pxDirEntry->ucAttrib = FF_getChar( src, FF_FAT_DIRENT_ATTRIB );\r
387 \r
388                         if( ( pxDirEntry->ucAttrib & FF_FAT_ATTR_LFN ) == FF_FAT_ATTR_LFN )\r
389                         {\r
390                                 /* LFN Processing. */\r
391                                 #if( ffconfigLFN_SUPPORT != 0 )\r
392                                 {\r
393                                         if( ( xLFNCount == 0 ) || ( lastAttrib & FF_FAT_ATTR_LFN ) != FF_FAT_ATTR_LFN )\r
394                                         {\r
395                                                 xLFNTotal = xLFNCount = ( BaseType_t )( src[ 0 ] & ~0x40 );\r
396                                                 lfnItem = pxDirEntry->usCurrentItem;\r
397                                                 ucCheckSum = FF_getChar( src, FF_FAT_LFN_CHECKSUM );\r
398                                                 pcLastPtr[ -1 ] = '\0';\r
399                                         }\r
400 \r
401                                         if( xLFNCount != 0 )\r
402                                         {\r
403                                                 xLFNCount--;\r
404                                                 pcCurPtr = pxDirEntry->pcFileName + ( xLFNCount * 13 );\r
405 \r
406                                                 /*\r
407                                                         This section needs to extract the name and do the comparison\r
408                                                         dependent on UNICODE settings in the FreeRTOSFATConfig.h file.\r
409                                                 */\r
410                                                 #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
411                                                 {\r
412                                                         /* Add UTF-16 Routine here. */\r
413                                                         /* Copy first 5 UTF-16 chars ( 10 bytes ). */\r
414                                                         memcpy( pcCurPtr, &src[ FF_FAT_LFN_NAME_1 ], 10 );\r
415                                                         /* Increment Filename pointer 5 utf16 chars. */\r
416                                                         pcCurPtr += 5;\r
417 \r
418                                                         /* Copy next 6 chars ( 12 bytes ). */\r
419                                                         memcpy( pcCurPtr, &src[ FF_FAT_LFN_NAME_2 ], 12 );\r
420                                                         pcCurPtr += 6;\r
421 \r
422                                                         /* You're getting the idea by now! */\r
423                                                         memcpy( pcCurPtr, &src[ FF_FAT_LFN_NAME_3 ], 4 );\r
424                                                         pcCurPtr += 2;\r
425                                                 }       /* ffconfigUNICODE_UTF16_SUPPORT */\r
426                                                 #elif( ffconfigUNICODE_UTF8_SUPPORT != 0 )\r
427                                                 {\r
428                                                         /* UTF-8 Routine here. */\r
429                                                         for( xIndex = 0; ( xIndex < 5 ) && ( pcCurPtr < pcLastPtr ); xIndex++ )\r
430                                                         {\r
431                                                                 /* Was there a surrogate sequence? -- Add handling here. */\r
432                                                                 utf8Error = FF_Utf16ctoUtf8c( ( uint8_t * ) pcCurPtr, ( uint16_t * ) &src[ FF_FAT_LFN_NAME_1 + ( 2 * xIndex ) ], pcLastPtr - pcCurPtr );\r
433                                                                 if( utf8Error > 0 )\r
434                                                                 {\r
435                                                                         pcCurPtr += utf8Error;\r
436                                                                 }\r
437                                                                 else\r
438                                                                 {\r
439                                                                         if( FF_GETERROR( utf8Error ) == FF_ERR_UNICODE_INVALID_SEQUENCE )\r
440                                                                         {\r
441                                                                                 /* Handle potential surrogate sequence across entries. */\r
442                                                                         }\r
443                                                                 }\r
444                                                         }\r
445 \r
446                                                         for( xIndex = 0; xIndex < 6 && pcCurPtr < pcLastPtr; xIndex++ )\r
447                                                         {\r
448                                                                 /* Was there a surrogate sequence? -- To add handling here. */\r
449                                                                 utf8Error = FF_Utf16ctoUtf8c( ( uint8_t * ) pcCurPtr, ( uint16_t * ) &src[ FF_FAT_LFN_NAME_2 + ( 2 * xIndex ) ], pcLastPtr - pcCurPtr );\r
450                                                                 if( utf8Error > 0 )\r
451                                                                 {\r
452                                                                         pcCurPtr += utf8Error;\r
453                                                                 }\r
454                                                                 else\r
455                                                                 {\r
456                                                                         if( FF_GETERROR( utf8Error ) == FF_ERR_UNICODE_INVALID_SEQUENCE )\r
457                                                                         {\r
458                                                                                 /* Handle potential surrogate sequence across entries. */\r
459                                                                         }\r
460                                                                 }\r
461                                                         }\r
462 \r
463                                                         for( xIndex = 0; xIndex < 2 && pcCurPtr < pcLastPtr; xIndex++ )\r
464                                                         {\r
465                                                                 /* Was there a surrogate sequence? -- To add handling here. */\r
466                                                                 utf8Error = FF_Utf16ctoUtf8c( ( uint8_t * ) pcCurPtr, ( uint16_t * ) &src[ FF_FAT_LFN_NAME_3 + ( 2 * xIndex ) ], pcLastPtr - pcCurPtr );\r
467                                                                 if( utf8Error > 0 )\r
468                                                                 {\r
469                                                                         pcCurPtr += utf8Error;\r
470                                                                 }\r
471                                                                 else\r
472                                                                 {\r
473                                                                         if( FF_GETERROR( utf8Error ) == FF_ERR_UNICODE_INVALID_SEQUENCE )\r
474                                                                         {\r
475                                                                                 /* Handle potential surrogate sequence across entries. */\r
476                                                                         }\r
477                                                                 }\r
478                                                         }\r
479                                                 }       /* ffconfigUNICODE_UTF8_SUPPORT */\r
480                                                 #else\r
481                                                 {       /* use ASCII notation. */\r
482                                                         for( xIndex = 0; ( xIndex < 10 ) && ( pcCurPtr < pcLastPtr ); xIndex += 2 )\r
483                                                         {\r
484                                                                 *( pcCurPtr++ ) = src[ FF_FAT_LFN_NAME_1 + xIndex ];\r
485                                                         }\r
486                                                         for( xIndex = 0; ( xIndex < 12 )  && ( pcCurPtr < pcLastPtr ); xIndex += 2 )\r
487                                                         {\r
488                                                                 *( pcCurPtr++ ) = src[ FF_FAT_LFN_NAME_2 + xIndex ];\r
489                                                         }\r
490 \r
491                                                         for( xIndex = 0; ( xIndex < 4 ) && ( pcCurPtr < pcLastPtr ); xIndex += 2 )\r
492                                                         {\r
493                                                                 *( pcCurPtr++ ) = src[ FF_FAT_LFN_NAME_3 + xIndex ];\r
494                                                         }\r
495                                                 }\r
496                                                 #endif /* ( ffconfigUNICODE_UTF16_SUPPORT == 0 ) && !( ffconfigUNICODE_UTF8_SUPPORT == 0 ) */\r
497                                                 if( ( xLFNCount == xLFNTotal - 1 ) && ( pcCurPtr < pcLastPtr ) )\r
498                                                 {\r
499                                                         *pcCurPtr = '\0';       /* Important when name len is multiple of 13. */\r
500                                                 }\r
501                                         } /* if( xLFNCount ) */\r
502                                 }\r
503                                 #endif /* ffconfigLFN_SUPPORT */\r
504                                 continue;\r
505                         }\r
506 \r
507                         if( ( pxDirEntry->ucAttrib & FF_FAT_ATTR_VOLID ) == FF_FAT_ATTR_VOLID )\r
508                         {\r
509                                 #if( ffconfigLFN_SUPPORT != 0 )\r
510                                 {\r
511                                         xLFNTotal = 0;\r
512                                 }\r
513                                 #endif /* ffconfigLFN_SUPPORT */\r
514                                 continue;\r
515                         }\r
516 \r
517                 #if( ffconfigLFN_SUPPORT != 0 )\r
518                         if( ( xLFNTotal == 0 ) || ( ucCheckSum != FF_CreateChkSum( src ) ) )\r
519                 #endif /* ffconfigLFN_SUPPORT */\r
520                         {\r
521                                 /* This entry has only a short name, or the checksum isn't correct\r
522                                  * Use the short name for comparison */\r
523                                 memcpy( pxDirEntry->pcFileName, src, 11 );\r
524                                 FF_ProcessShortName( ( char * ) pxDirEntry->pcFileName );\r
525                                 #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
526                                 {\r
527                                         /* FileName now contains a 8-bit short name\r
528                                         Expand it to a FF_T_WCHAR string. */\r
529                                         FF_ShortNameExpand( pxDirEntry->pcFileName );\r
530                                 }\r
531                                 #endif /* ffconfigUNICODE_UTF16_SUPPORT */\r
532                                 #if( ffconfigLFN_SUPPORT != 0)\r
533                                 {\r
534                                         xLFNTotal = 0;\r
535                                 }\r
536                                 #endif /* ffconfigLFN_SUPPORT */\r
537                         }\r
538 \r
539                         /* This function FF_FindEntryInDir( ) is either called with\r
540                          * pa_Attrib==0 or with pa_Attrib==FF_FAT_ATTR_DIR\r
541                          * In the last case the caller is looking for a directory */\r
542                         if( ( pxDirEntry->ucAttrib & pa_Attrib ) == pa_Attrib )\r
543                         {\r
544                                 if( testShortname )\r
545                                 {\r
546                                         /* Both strings are stored in the directory format\r
547                                          * e.g. "README  TXT", without a dot */\r
548                                         if( memcmp( src, pxFindParams->pcEntryBuffer, 11 ) == 0 )\r
549                                         {\r
550                                                 pxFindParams->ulFlags |= FIND_FLAG_SHORTNAME_CHECKED | FIND_FLAG_SHORTNAME_FOUND;\r
551                                         }\r
552                                 }\r
553 \r
554                         #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
555                                 if( wcsicmp( ( const char * )pcName, ( const char * )pxDirEntry->pcFileName ) == 0 )\r
556                         #else\r
557                                 if( FF_stricmp( ( const char * )pcName, ( const char * )pxDirEntry->pcFileName ) == 0 )\r
558                         #endif /* ffconfigUNICODE_UTF16_SUPPORT */\r
559                                 {\r
560                                         /* Finally get the complete information. */\r
561                                 #if( ffconfigLFN_SUPPORT != 0 )\r
562                                         if( xLFNTotal )\r
563                                         {\r
564                                                 xError = FF_PopulateLongDirent( pxIOManager, pxDirEntry, ( uint16_t ) lfnItem, &xFetchContext );\r
565                                                 if( FF_isERR( xError ) )\r
566                                                 {\r
567                                                         break;\r
568                                                 }\r
569                                         }\r
570                                         else\r
571                                 #endif /* ffconfigLFN_SUPPORT */\r
572                                         {\r
573                                                 FF_PopulateShortDirent( pxIOManager, pxDirEntry, src );\r
574                                                 /* HT: usCurrentItem wasn't increased here. */\r
575                                                 pxDirEntry->usCurrentItem++;\r
576                                         }\r
577                                         /* Object found, the cluster number will be returned. */\r
578                                         xResult = pxDirEntry->ulObjectCluster;\r
579                                         break;\r
580                                 }\r
581                         }\r
582                         #if( ffconfigLFN_SUPPORT != 0 )\r
583                         {\r
584                                 xLFNTotal = 0;\r
585                         }\r
586                         #endif\r
587                 }       /* for( ; pxDirEntry->usCurrentItem < FF_MAX_ENTRIES_PER_DIRECTORY; pxDirEntry->usCurrentItem++ ) */\r
588 \r
589                 {\r
590                 FF_Error_t xTempError;\r
591                         xTempError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext );\r
592                         if( FF_isERR( xError ) == pdFALSE )\r
593                         {\r
594                                 xError = xTempError;\r
595                         }\r
596                 }\r
597         } /* if( FF_isERR( xError ) == pdFALSE ) */\r
598 \r
599         if( FF_isERR( xError ) == pdFALSE )\r
600         {\r
601                 /* If a free entry wasn't found yet, put it to the current (last) item */\r
602                 if( pxFindParams->lFreeEntry < 0 )\r
603                 {\r
604                         pxFindParams->lFreeEntry = pxDirEntry->usCurrentItem;\r
605                 }\r
606 \r
607                 /* If we were checking the existence of the short-name\r
608                 set the Checked flag now */\r
609                 if( testShortname )\r
610                 {\r
611                         pxFindParams->ulFlags |= FIND_FLAG_SHORTNAME_CHECKED;\r
612                 }\r
613         }\r
614 \r
615         if( pxError != NULL )\r
616         {\r
617                 *pxError = xError;\r
618         }\r
619 \r
620         return xResult;\r
621 }       /* FF_FindEntryInDir() */\r
622 /*-----------------------------------------------------------*/\r
623 \r
624 \r
625 /**\r
626  *      @private\r
627  **/\r
628 #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
629 uint32_t FF_FindDir( FF_IOManager_t *pxIOManager, const FF_T_WCHAR *pcPath, uint16_t pathLen, FF_Error_t *pxError )\r
630 #else\r
631 uint32_t FF_FindDir( FF_IOManager_t *pxIOManager, const char *pcPath, uint16_t pathLen, FF_Error_t *pxError )\r
632 #endif\r
633 {\r
634 uint16_t it = 0;         /* Re-entrancy Variables for FF_strtok( ). */\r
635 BaseType_t last = pdFALSE;\r
636 FF_DirEnt_t xMyDirectory;\r
637 FF_FindParams_t  xFindParams;\r
638 FF_Error_t xError;\r
639 BaseType_t xFound;\r
640 \r
641 #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
642         FF_T_WCHAR mytoken[ ffconfigMAX_FILENAME ];\r
643         FF_T_WCHAR *token;\r
644 #else\r
645         char mytoken[ ffconfigMAX_FILENAME ];\r
646         char *pcToken;\r
647 #endif\r
648 \r
649 #if( ffconfigPATH_CACHE != 0 )\r
650         BaseType_t xIndex;\r
651 #endif\r
652 \r
653         memset( &xFindParams, '\0', sizeof( xFindParams ) );\r
654         xFindParams.ulDirCluster = pxIOManager->xPartition.ulRootDirCluster;\r
655 \r
656         xError = FF_ERR_NONE;\r
657 \r
658     if( pathLen <= 1 )\r
659         {\r
660                 /* Must be the root directory.\r
661                 'xFindParams.ulDirCluster' will be returned containing 'pxIOManager->xPartition.ulRootDirCluster'. */\r
662                 xFound = pdTRUE;\r
663     }\r
664         else\r
665         {\r
666                 /* Only the root directory '/' shall have a trailing slash in its name. */\r
667                 if( ( pcPath[ pathLen - 1 ] == '\\' ) || ( pcPath[ pathLen - 1 ] == '/' ) )\r
668                 {\r
669                         pathLen--;\r
670                 }\r
671                 xFound = pdFALSE;\r
672 \r
673                 #if( ffconfigPATH_CACHE != 0 )  /* Is the requested pcPath in the PATH CACHE? */\r
674                 {\r
675                         FF_PendSemaphore( pxIOManager->pvSemaphore );   /* Thread safety on shared object! */\r
676                         {\r
677                                 for( xIndex = 0; xIndex < ffconfigPATH_CACHE_DEPTH; xIndex++ )\r
678                                 {\r
679                                 #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
680                                         if( wcslen( pxIOManager->xPartition.pxPathCache[ xIndex ].pcPath ) == ( size_t )pathLen )\r
681                                 #else\r
682                                         if( strlen( pxIOManager->xPartition.pxPathCache[ xIndex ].pcPath ) == ( size_t )pathLen )\r
683                                 #endif\r
684                                         {\r
685                                                 if( FF_strmatch( pxIOManager->xPartition.pxPathCache[ xIndex ].pcPath, pcPath, pathLen ) )\r
686                                                 {\r
687                                                         xFindParams.ulDirCluster = pxIOManager->xPartition.pxPathCache[ xIndex ].ulDirCluster;\r
688                                                         xFound = pdTRUE;\r
689                                                         break;\r
690                                                 }\r
691                                         }\r
692                                 }\r
693                         }\r
694                         FF_ReleaseSemaphore( pxIOManager->pvSemaphore );\r
695                 }\r
696                 #endif /* ffconfigPATH_CACHE */\r
697         }\r
698         if( xFound == pdFALSE )\r
699         {\r
700                 pcToken = FF_strtok( pcPath, mytoken, &it, &last, pathLen );\r
701 \r
702                 do\r
703                 {\r
704                         xMyDirectory.usCurrentItem = 0;\r
705                         xFindParams.ulDirCluster = FF_FindEntryInDir( pxIOManager, &xFindParams, pcToken, ( uint8_t ) FF_FAT_ATTR_DIR, &xMyDirectory, &xError );\r
706 \r
707                         if( xFindParams.ulDirCluster == 0ul )\r
708                         {\r
709                                 break;\r
710                         }\r
711 \r
712                         pcToken = FF_strtok( pcPath, mytoken, &it, &last, pathLen );\r
713 \r
714                 } while( pcToken != NULL );\r
715                 if( ( pcToken != NULL ) &&\r
716                         ( ( FF_isERR( xError ) == pdFALSE ) || ( FF_GETERROR( xError ) == FF_ERR_DIR_END_OF_DIR ) ) )\r
717                 {\r
718                         xError = ( FF_Error_t ) ( FF_FINDDIR | FF_ERR_FILE_INVALID_PATH );\r
719                 }\r
720                 #if( ffconfigPATH_CACHE != 0 )  /* Update the PATH CACHE with a new PATH. */\r
721                 {\r
722                         /* Only cache if the dir was actually found! */\r
723                         if( ( FF_isERR( xError ) == pdFALSE ) && ( xFindParams.ulDirCluster != 0ul ) )\r
724                         {\r
725                                 FF_PendSemaphore( pxIOManager->pvSemaphore );\r
726                                 {\r
727                                         if( pathLen < ffconfigMAX_FILENAME )    /* Ensure the PATH won't cause a buffer overrun. */\r
728                                         {\r
729                                                 #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
730                                                 {\r
731                                                         memcpy( pxIOManager->xPartition.pxPathCache[ pxIOManager->xPartition.ulPCIndex ].pcPath, pcPath, pathLen * sizeof( FF_T_WCHAR ) );\r
732                                                 }\r
733                                                 #else\r
734                                                 {\r
735                                                         memcpy( pxIOManager->xPartition.pxPathCache[ pxIOManager->xPartition.ulPCIndex ].pcPath, pcPath, pathLen );\r
736                                                 }\r
737                                                 #endif\r
738 \r
739                                                 pxIOManager->xPartition.pxPathCache[ pxIOManager->xPartition.ulPCIndex ].pcPath[ pathLen ] = '\0';\r
740                                                 pxIOManager->xPartition.pxPathCache[ pxIOManager->xPartition.ulPCIndex ].ulDirCluster = xFindParams.ulDirCluster;\r
741 \r
742                                                 pxIOManager->xPartition.ulPCIndex += 1;\r
743                                                 if( pxIOManager->xPartition.ulPCIndex >= ffconfigPATH_CACHE_DEPTH )\r
744                                                 {\r
745                                                         pxIOManager->xPartition.ulPCIndex = 0;\r
746                                                 }\r
747                                         }\r
748                                 }\r
749                                 FF_ReleaseSemaphore( pxIOManager->pvSemaphore );\r
750                         }\r
751                 }\r
752                 #endif /* ffconfigPATH_CACHE */\r
753         } /* if( pathLen > 1 ) */\r
754 \r
755         if( pxError != NULL )\r
756         {\r
757                 *pxError = xError;\r
758         }\r
759 \r
760     return xFindParams.ulDirCluster;\r
761 }       /* FF_FindDir() */\r
762 /*-----------------------------------------------------------*/\r
763 \r
764 \r
765 #if( ffconfigSHORTNAME_CASE != 0 )\r
766         /**\r
767          *      @private\r
768          *  For short-name entries, NT/XP etc store case information in byte 0x0c\r
769          *  Use this to show proper case of "README.txt" or "source.H"\r
770          **/\r
771         #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
772         static void FF_CaseShortName( FF_T_WCHAR *pcName, uint8_t attrib )\r
773         #else\r
774         static void FF_CaseShortName( char *pcName, uint8_t attrib )\r
775         #endif\r
776         {\r
777         uint8_t testAttrib = FF_FAT_CASE_ATTR_BASE;\r
778 \r
779                 for ( ; *pcName != '\0'; pcName++ )\r
780                 {\r
781                         if( *pcName == '.' )\r
782                         {\r
783                                 testAttrib = FF_FAT_CASE_ATTR_EXT;\r
784                         }\r
785                         else if ( ( attrib & testAttrib ) != 0 )\r
786                         {\r
787                                 if( ( *pcName >= 'A' ) && ( *pcName <= 'Z' ) )\r
788                                 {\r
789                                         *pcName += 0x20;\r
790                                 }\r
791                         }\r
792                         else if( ( *pcName >= 'a' ) && ( *pcName <= 'z' ) )\r
793                         {\r
794                                 *pcName -= 0x20;\r
795                         }\r
796                 }\r
797         }\r
798 #endif /* ffconfigSHORTNAME_CASE */\r
799 /*-----------------------------------------------------------*/\r
800 \r
801 #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
802         /**\r
803          *      @private\r
804          *      Expand a short-name, adding a zero after each character\r
805          **/\r
806 \r
807         static void FF_ShortNameExpand( FF_T_WCHAR *pFileName )\r
808         {\r
809                 int8_t *pSource = ( ( int8_t * ) pFileName ) + 13;\r
810                 int8_t *pTarget = ( ( int8_t * ) pFileName ) + 26;\r
811                 /* "aaaaaaaa.eee": 12 characters plus a zero makes 13\r
812                  * Copy from the right to the left */\r
813                 while( pTarget > ( int8_t * ) pFileName )\r
814                 {\r
815                         pTarget[ -1 ] = 0;\r
816                         pTarget[ -2 ] = *( --pSource );\r
817                         pTarget -= 2;\r
818                 }\r
819         }\r
820 #endif /* ffconfigUNICODE_UTF16_SUPPORT */\r
821 /*-----------------------------------------------------------*/\r
822 \r
823 /**\r
824  *      @private\r
825  **/\r
826 \r
827 static void FF_ProcessShortName( char *pcName )\r
828 {\r
829         char    pcShortName[ 13 ];\r
830         char    *pcTarget = pcName;\r
831         int             iSource;\r
832         memcpy( pcShortName, pcName, 11 );\r
833 \r
834         for( iSource = 0; iSource < 11; iSource++ )\r
835         {\r
836                 if( pcShortName[ iSource ] == 0x20 )\r
837                 {\r
838                         if( iSource >= 8 )\r
839                         {\r
840                                 break;\r
841                         }\r
842                         iSource = 7;\r
843                 }\r
844                 else\r
845                 {\r
846                         if( iSource == 8 )\r
847                         {\r
848                                 *( pcTarget++ ) = '.';\r
849                         }\r
850                         *( pcTarget++ ) = pcShortName[ iSource ];\r
851                 }\r
852         }\r
853         *pcTarget = '\0';\r
854 }\r
855 /*-----------------------------------------------------------*/\r
856 \r
857 \r
858 #if( ffconfigTIME_SUPPORT != 0 )\r
859         static void FF_PlaceTime( uint8_t *pucEntryBuffer, uint32_t Offset, FF_SystemTime_t *pxTime )\r
860         {\r
861                 uint16_t myShort;\r
862 \r
863                 /* HT time changes:\r
864                 E.g. Unzip needs to use original time rather than\r
865                 the result of FF_GetSystemTime */\r
866 \r
867                 myShort = 0;\r
868                 myShort |= ( ( pxTime->Hour    << 11 ) & 0xF800 );\r
869                 myShort |= ( ( pxTime->Minute  <<  5 ) & 0x07E0 );\r
870                 myShort |= ( ( pxTime->Second   /  2 ) & 0x001F );\r
871                 FF_putShort( pucEntryBuffer, ( uint16_t ) Offset, myShort );\r
872         }\r
873 #endif /* ffconfigTIME_SUPPORT */\r
874 /*-----------------------------------------------------------*/\r
875 \r
876 \r
877 #if( ffconfigTIME_SUPPORT != 0 )\r
878         static void FF_PlaceDate( uint8_t *pucEntryBuffer, uint32_t Offset, FF_SystemTime_t *pxTime )\r
879         {\r
880                 uint16_t myShort;\r
881 \r
882                 /* HT time changes:\r
883                 Unzip needs to use original date rather than\r
884                 the current date, so make it a parameter. */\r
885                 myShort = 0;\r
886                 myShort |= ( ( ( pxTime->Year- 1980 )  <<  9 ) & 0xFE00 ) ;\r
887                 myShort |= ( ( pxTime->Month <<  5 ) & 0x01E0 );\r
888                 myShort |= ( pxTime->Day & 0x001F );\r
889                 FF_putShort( pucEntryBuffer, ( uint16_t ) Offset, myShort );\r
890         }\r
891 #endif /*  ffconfigTIME_SUPPORT */\r
892 /*-----------------------------------------------------------*/\r
893 \r
894 \r
895 #if( ffconfigTIME_SUPPORT != 0 )\r
896         static void FF_GetTime( FF_SystemTime_t *pxTime, const uint8_t *pucEntryBuffer, uint32_t Offset )\r
897         {\r
898                 uint16_t myShort;\r
899                 myShort = FF_getShort( pucEntryBuffer, ( uint16_t ) Offset );\r
900                 pxTime->Hour            = ( ( ( myShort & 0xF800 ) >> 11 ) & 0x001F );\r
901                 pxTime->Minute  = ( ( ( myShort & 0x07E0 ) >>  5 ) & 0x003F );\r
902                 pxTime->Second  = 2 * ( myShort & 0x01F );\r
903         }\r
904 #endif /*  ffconfigTIME_SUPPORT */\r
905 /*-----------------------------------------------------------*/\r
906 \r
907 \r
908 #if( ffconfigTIME_SUPPORT != 0 )\r
909         static void FF_GetDate( FF_SystemTime_t *pxTime, const uint8_t *pucEntryBuffer, uint32_t Offset )\r
910         {\r
911                 uint16_t myShort;\r
912                 myShort = FF_getShort( pucEntryBuffer, ( uint16_t ) Offset );\r
913                 pxTime->Year            = 1980 + ( ( ( myShort & 0xFE00 ) >> 9 ) & 0x07F );\r
914                 pxTime->Month   = ( ( ( myShort & 0x01E0 ) >> 5 ) & 0x000F );\r
915                 pxTime->Day             = myShort & 0x01F;\r
916         }\r
917 #endif /*  ffconfigTIME_SUPPORT */\r
918 /*-----------------------------------------------------------*/\r
919 \r
920 void FF_PopulateShortDirent( FF_IOManager_t *pxIOManager, FF_DirEnt_t *pxDirEntry, const uint8_t *pucEntryBuffer )\r
921 {\r
922         memcpy( pxDirEntry->pcFileName, pucEntryBuffer, 11 );   /* Copy the filename into the Dirent object. */\r
923 #if( ffconfigLFN_SUPPORT != 0 ) && ( ffconfigINCLUDE_SHORT_NAME != 0 )\r
924         memcpy( pxDirEntry->pcShortName, pucEntryBuffer, 11 );\r
925         pxDirEntry->pcShortName[ 11 ] = '\0';\r
926         FF_ProcessShortName( pxDirEntry->pcShortName ); /* For debuggers only. */\r
927 #endif\r
928         FF_ProcessShortName( ( char * ) pxDirEntry->pcFileName );               /* Format the shortname, for pleasant viewing. */\r
929 \r
930 #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
931         /* FileName contains a 8-bit short name\r
932          * Expand it to a FF_T_WCHAR string */\r
933         FF_ShortNameExpand( pxDirEntry->pcFileName );\r
934 #endif\r
935 \r
936         ( void )pxIOManager;    /* Silence a compiler warning, about not referencing pxIOManager. */\r
937 \r
938 #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
939         FF_tolower( pxDirEntry->pcFileName, ( uint32_t )wcslen( pxDirEntry->pcFileName ) );\r
940 #else\r
941         FF_tolower( pxDirEntry->pcFileName, ( uint32_t )strlen( pxDirEntry->pcFileName ) );\r
942 #endif\r
943 \r
944         /* Get the item's Cluster address. */\r
945         pxDirEntry->ulObjectCluster =\r
946                 ( ( uint32_t )FF_getShort( pucEntryBuffer, FF_FAT_DIRENT_CLUS_HIGH ) << 16 ) |\r
947                   ( uint32_t )FF_getShort( pucEntryBuffer, FF_FAT_DIRENT_CLUS_LOW );\r
948 #if( ffconfigTIME_SUPPORT != 0 )\r
949         /* Get the creation Time & Date. */\r
950         FF_GetTime( &pxDirEntry->xCreateTime, pucEntryBuffer, FF_FAT_DIRENT_CREATE_TIME );\r
951         FF_GetDate( &pxDirEntry->xCreateTime, pucEntryBuffer, FF_FAT_DIRENT_CREATE_DATE );\r
952         /* Get the modified Time & Date\r
953         HT Here xCreateTime became xModifiedTime: */\r
954         FF_GetTime( &pxDirEntry->xModifiedTime, pucEntryBuffer, FF_FAT_DIRENT_LASTMOD_TIME );\r
955         FF_GetDate( &pxDirEntry->xModifiedTime, pucEntryBuffer, FF_FAT_DIRENT_LASTMOD_DATE );\r
956         /* Get the last accessed Date. */\r
957         FF_GetDate( &pxDirEntry->xAccessedTime, pucEntryBuffer, FF_FAT_DIRENT_LASTACC_DATE );\r
958         pxDirEntry->xAccessedTime.Hour          = 0;\r
959         pxDirEntry->xAccessedTime.Minute        = 0;\r
960         pxDirEntry->xAccessedTime.Second        = 0;\r
961 #endif\r
962         /* Get the filesize. */\r
963         pxDirEntry->ulFileSize = FF_getLong( pucEntryBuffer, ( uint16_t )( FF_FAT_DIRENT_FILESIZE ) );\r
964         /* Get the attribute. */\r
965         pxDirEntry->ucAttrib = FF_getChar( pucEntryBuffer, ( uint16_t )( FF_FAT_DIRENT_ATTRIB ) );\r
966 }\r
967 /*-----------------------------------------------------------*/\r
968 \r
969 \r
970 /* Initialises a context object for FF_FetchEntryWithContext(  */\r
971 FF_Error_t FF_InitEntryFetch( FF_IOManager_t *pxIOManager, uint32_t ulDirCluster, FF_FetchContext_t *pxContext )\r
972 {\r
973         FF_Error_t xError;\r
974 \r
975         memset( pxContext, 0, sizeof( FF_FetchContext_t ) );\r
976 \r
977         /* Get the total length of the chain. */\r
978         pxContext->ulChainLength = FF_GetChainLength( pxIOManager, ulDirCluster, NULL, &xError );\r
979 \r
980         if( FF_isERR( xError ) == pdFALSE )\r
981         {\r
982                 pxContext->ulDirCluster = ulDirCluster;\r
983                 pxContext->ulCurrentClusterLCN = ulDirCluster;\r
984 \r
985                 if( pxIOManager->xPartition.ucType != FF_T_FAT32 )\r
986                 {\r
987                         /* Handle Root Dirs that don't have cluster chains! */\r
988                         if( pxContext->ulDirCluster == pxIOManager->xPartition.ulRootDirCluster )\r
989                         {\r
990                                 /* This is a RootDIR, special consideration needs to be made, because it doesn't have a Cluster chain! */\r
991                                 pxContext->ulChainLength = pxIOManager->xPartition.ulRootDirSectors / pxIOManager->xPartition.ulSectorsPerCluster;\r
992                                 if( pxContext->ulChainLength == 0 )             /* Some media has ulRootDirSectors < ulSectorsPerCluster. This is wrong, as it should be atleast 1 cluster! */\r
993                                 {\r
994                                         pxContext->ulChainLength = 1;\r
995                                 }\r
996                         }\r
997                 }\r
998         }\r
999 \r
1000         return xError;\r
1001 }       /* FF_InitEntryFetch() */\r
1002 /*-----------------------------------------------------------*/\r
1003 \r
1004 FF_Error_t FF_CleanupEntryFetch( FF_IOManager_t *pxIOManager, FF_FetchContext_t *pxContext )\r
1005 {\r
1006         FF_Error_t xError = FF_ERR_NONE;\r
1007         if( pxContext->pxBuffer )\r
1008         {\r
1009                 xError = FF_ReleaseBuffer( pxIOManager, pxContext->pxBuffer );\r
1010                 pxContext->pxBuffer = NULL;\r
1011         }\r
1012 \r
1013         return xError;\r
1014 }       /* FF_CleanupEntryFetch() */\r
1015 /*-----------------------------------------------------------*/\r
1016 \r
1017 /**\r
1018  *      @private\r
1019  *      @brief  Find the cluster for a given Entry within a directory\r
1020  *  @brief      Make an exception for the root directory ( non FAT32 only ):\r
1021  *  @brief      Just calculate the cluster ( don't consult the actual FAT )\r
1022  *\r
1023  *      @param  pxIOManager FF_IOManager_t object that was created by FF_CreateIOManger( ).\r
1024  *      @param  ulEntry     The sequence number of the entry of interest\r
1025  *  @param      pxContext   Context of current search\r
1026  *\r
1027  *      @Return FF_ERR_NONE on success\r
1028  *      @Return Possible error returned by FF_TraverseFAT( ) or END_OF_DIR\r
1029  *\r
1030  *  Side effects:\r
1031  *    - pxContext->ulCurrentClusterNum : relative cluster number ( 0 <= Num < ulChainLength )\r
1032  *    - pxContext->ulCurrentClusterLCN : fysical cluster on the partition\r
1033  **/\r
1034 \r
1035 static FF_Error_t FF_Traverse( FF_IOManager_t *pxIOManager, uint32_t ulEntry, FF_FetchContext_t *pxContext )\r
1036 {\r
1037 uint32_t ulClusterNum = FF_getClusterChainNumber( pxIOManager, ulEntry, ( uint16_t ) FF_SIZEOF_DIRECTORY_ENTRY );\r
1038 FF_Error_t xError = FF_ERR_NONE;\r
1039 \r
1040         /* Check if we're past the last cluster ( ulChainLength is also valid for root sectors ). */\r
1041         if( ( ulClusterNum + 1 ) > pxContext->ulChainLength )\r
1042         {\r
1043                 xError = FF_ERR_DIR_END_OF_DIR | FF_TRAVERSE;   /* End of Dir was reached! */\r
1044         }\r
1045         else if( ( pxIOManager->xPartition.ucType != FF_T_FAT32 ) &&\r
1046                 ( pxContext->ulDirCluster == pxIOManager->xPartition.ulRootDirCluster ) )\r
1047         {\r
1048                 /* Double-check if the entry number isn't too high. */\r
1049                 if( ulEntry > ( ( pxIOManager->xPartition.ulRootDirSectors * pxIOManager->xPartition.usBlkSize ) / FF_SIZEOF_DIRECTORY_ENTRY ) )\r
1050                 {\r
1051                         xError = ( FF_Error_t ) ( FF_ERR_DIR_END_OF_DIR | FF_FETCHENTRYWITHCONTEXT );\r
1052                 }\r
1053                 else\r
1054                 {\r
1055                         pxContext->ulCurrentClusterLCN = pxContext->ulDirCluster;\r
1056                 }\r
1057         }\r
1058         else if( ulClusterNum != pxContext->ulCurrentClusterNum )\r
1059         {\r
1060                 /* Traverse the fat gently! */\r
1061                 if( ulClusterNum > pxContext->ulCurrentClusterNum )\r
1062                 {\r
1063                         /* Start traverse from the current entry. */\r
1064                         pxContext->ulCurrentClusterLCN = FF_TraverseFAT( pxIOManager, pxContext->ulCurrentClusterLCN, ( ulClusterNum - pxContext->ulCurrentClusterNum ), &xError );\r
1065                 }\r
1066                 else\r
1067                 {\r
1068                         /* Start traverse from the beginning. */\r
1069                         pxContext->ulCurrentClusterLCN = FF_TraverseFAT( pxIOManager, pxContext->ulDirCluster, ulClusterNum, &xError );\r
1070                 }\r
1071         }\r
1072         if( FF_isERR( xError ) == pdFALSE )\r
1073         {\r
1074                 pxContext->ulCurrentClusterNum = ulClusterNum;\r
1075         }\r
1076 \r
1077         return xError;\r
1078 }       /* FF_Traverse() */\r
1079 /*-----------------------------------------------------------*/\r
1080 \r
1081 FF_Error_t FF_FetchEntryWithContext( FF_IOManager_t *pxIOManager, uint32_t ulEntry, FF_FetchContext_t *pxContext, uint8_t *pEntryBuffer )\r
1082 {\r
1083         uint32_t ulItemLBA;\r
1084         uint32_t ulRelItem;\r
1085         FF_Error_t xError;\r
1086 \r
1087         xError = FF_Traverse( pxIOManager, ulEntry, pxContext );\r
1088 \r
1089         if( FF_isERR( xError ) == pdFALSE )\r
1090         {\r
1091                 ulRelItem     = FF_getMinorBlockEntry ( pxIOManager, ulEntry, ( uint32_t )FF_SIZEOF_DIRECTORY_ENTRY );\r
1092 \r
1093                 ulItemLBA = FF_Cluster2LBA ( pxIOManager, pxContext->ulCurrentClusterLCN ) +\r
1094                         FF_getMajorBlockNumber( pxIOManager, ulEntry, ( uint32_t ) FF_SIZEOF_DIRECTORY_ENTRY );\r
1095                 if( ( pxIOManager->xPartition.ucType != FF_T_FAT32 ) &&\r
1096                         ( pxContext->ulDirCluster == pxIOManager->xPartition.ulRootDirCluster ) )\r
1097                 {\r
1098                         ulItemLBA += ( ulEntry / ( ( pxIOManager->xPartition.usBlkSize * pxIOManager->xPartition.ulSectorsPerCluster ) /\r
1099                                 FF_SIZEOF_DIRECTORY_ENTRY ) * pxIOManager->xPartition.ulSectorsPerCluster );\r
1100                 }\r
1101 \r
1102                 ulItemLBA = FF_getRealLBA ( pxIOManager, ulItemLBA ) + FF_getMinorBlockNumber( pxIOManager, ulRelItem, ( uint32_t )FF_SIZEOF_DIRECTORY_ENTRY );\r
1103 \r
1104                 if( ( pxContext->pxBuffer == NULL ) ||\r
1105                         ( pxContext->pxBuffer->ulSector != ulItemLBA ) ||\r
1106                         ( ( pxContext->pxBuffer->ucMode & FF_MODE_WRITE ) != 0 ) )\r
1107                 {\r
1108                         if( pxContext->pxBuffer != NULL )\r
1109                         {\r
1110                                 xError = FF_ReleaseBuffer( pxIOManager, pxContext->pxBuffer );\r
1111                                 pxContext->pxBuffer = NULL;\r
1112                         }\r
1113 \r
1114                         if( FF_isERR( xError ) == pdFALSE )\r
1115                         {\r
1116                                 pxContext->pxBuffer = FF_GetBuffer( pxIOManager, ulItemLBA, FF_MODE_READ );\r
1117                                 if( pxContext->pxBuffer == NULL )\r
1118                                 {\r
1119                                         xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_FETCHENTRYWITHCONTEXT );\r
1120                                 }\r
1121                         }\r
1122                 }\r
1123 \r
1124                 if ( ( pEntryBuffer != NULL ) && ( pxContext->pxBuffer != NULL ) )\r
1125                 {\r
1126                         memcpy( pEntryBuffer, pxContext->pxBuffer->pucBuffer + ( ulRelItem * FF_SIZEOF_DIRECTORY_ENTRY ), FF_SIZEOF_DIRECTORY_ENTRY );\r
1127                 }\r
1128         }\r
1129 \r
1130     return xError;\r
1131 }       /* FF_FetchEntryWithContext() */\r
1132 /*-----------------------------------------------------------*/\r
1133 \r
1134 \r
1135 FF_Error_t FF_PushEntryWithContext( FF_IOManager_t *pxIOManager, uint32_t ulEntry, FF_FetchContext_t *pxContext, uint8_t *pEntryBuffer )\r
1136 {\r
1137         uint32_t        ulItemLBA;\r
1138         uint32_t        ulRelItem;\r
1139         FF_Error_t      xError;\r
1140 \r
1141         xError = FF_Traverse( pxIOManager, ulEntry, pxContext );\r
1142         if( FF_isERR( xError ) == pdFALSE )\r
1143         {\r
1144                 ulRelItem     = FF_getMinorBlockEntry ( pxIOManager, ulEntry, ( uint32_t ) FF_SIZEOF_DIRECTORY_ENTRY );\r
1145 \r
1146                 ulItemLBA = FF_Cluster2LBA ( pxIOManager, pxContext->ulCurrentClusterLCN ) + FF_getMajorBlockNumber( pxIOManager, ulEntry, ( uint32_t ) FF_SIZEOF_DIRECTORY_ENTRY );\r
1147                 if( ( pxIOManager->xPartition.ucType != FF_T_FAT32 ) &&\r
1148                         ( pxContext->ulDirCluster == pxIOManager->xPartition.ulRootDirCluster ) )\r
1149                 {\r
1150                         ulItemLBA += ( ulEntry /\r
1151                                 ( ( pxIOManager->xPartition.usBlkSize * pxIOManager->xPartition.ulSectorsPerCluster ) / FF_SIZEOF_DIRECTORY_ENTRY ) * pxIOManager->xPartition.ulSectorsPerCluster );\r
1152                 }\r
1153 \r
1154                 ulItemLBA = FF_getRealLBA ( pxIOManager, ulItemLBA ) + FF_getMinorBlockNumber( pxIOManager, ulRelItem, ( uint32_t )FF_SIZEOF_DIRECTORY_ENTRY );\r
1155 \r
1156                 if( ( pxContext->pxBuffer == NULL ) ||\r
1157                         ( pxContext->pxBuffer->ulSector != ulItemLBA ) ||\r
1158                         ( ( pxContext->pxBuffer->ucMode & FF_MODE_WRITE ) == 0 ) )\r
1159                 {\r
1160                         if( pxContext->pxBuffer != NULL )\r
1161                         {\r
1162                                 xError = FF_ReleaseBuffer( pxIOManager, pxContext->pxBuffer );\r
1163                                 pxContext->pxBuffer = NULL;\r
1164                         }\r
1165                         if( FF_isERR( xError ) == pdFALSE )\r
1166                         {\r
1167                                 pxContext->pxBuffer = FF_GetBuffer( pxIOManager, ulItemLBA, FF_MODE_WRITE );\r
1168                                 if( pxContext->pxBuffer == NULL )\r
1169                                 {\r
1170                                         xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_FETCHENTRYWITHCONTEXT );\r
1171                                 }\r
1172                         }\r
1173                 }\r
1174 \r
1175                 /* Now change the entry: */\r
1176                 if( pxContext->pxBuffer != NULL )\r
1177                 {\r
1178                         memcpy( pxContext->pxBuffer->pucBuffer + ( ulRelItem * FF_SIZEOF_DIRECTORY_ENTRY ), pEntryBuffer, FF_SIZEOF_DIRECTORY_ENTRY );\r
1179                 }\r
1180         }\r
1181 \r
1182     return xError;\r
1183 }       /* FF_PushEntryWithContext() */\r
1184 /*-----------------------------------------------------------*/\r
1185 \r
1186 \r
1187 /**\r
1188  *      @private\r
1189  **/\r
1190 FF_Error_t FF_GetEntry( FF_IOManager_t *pxIOManager, uint16_t usEntry, uint32_t ulDirCluster, FF_DirEnt_t *pxDirEntry )\r
1191 {\r
1192 /* A 32 byte directory entry. */\r
1193 uint8_t ucEntryBuffer[ FF_SIZEOF_DIRECTORY_ENTRY ];\r
1194 FF_FetchContext_t       xFetchContext;\r
1195 FF_Error_t                              xError;\r
1196 \r
1197 #if( ffconfigLFN_SUPPORT == 0 )\r
1198         BaseType_t xLFNCount;\r
1199 #endif\r
1200         xError = FF_InitEntryFetch( pxIOManager, ulDirCluster, &xFetchContext );\r
1201 \r
1202         if( FF_isERR( xError ) == pdFALSE )\r
1203         {\r
1204                 xError = FF_FetchEntryWithContext( pxIOManager, usEntry, &xFetchContext, ucEntryBuffer );\r
1205 \r
1206                 if( ( FF_isERR( xError ) == pdFALSE ) &&\r
1207                         ( FF_isDeleted( ucEntryBuffer ) == pdFALSE ) )\r
1208                 {\r
1209                         if( FF_isEndOfDir( ucEntryBuffer ) != pdFALSE )\r
1210                         {\r
1211                                 xError = ( FF_Error_t ) ( FF_ERR_DIR_END_OF_DIR | FF_GETENTRY );\r
1212                         }\r
1213                         else\r
1214                         {\r
1215                                 pxDirEntry->ucAttrib = FF_getChar( ucEntryBuffer, ( uint16_t )( FF_FAT_DIRENT_ATTRIB ) );\r
1216 \r
1217                                 if( ( pxDirEntry->ucAttrib & FF_FAT_ATTR_LFN ) == FF_FAT_ATTR_LFN )\r
1218                                 {\r
1219                         #if( ffconfigLFN_SUPPORT != 0 )\r
1220                                         xError = FF_PopulateLongDirent( pxIOManager, pxDirEntry, usEntry, &xFetchContext );\r
1221                         #else\r
1222                                         /* LFN Processing. */\r
1223                                         xLFNCount = ( BaseType_t )( ucEntryBuffer[0] & ~0x40 );\r
1224                                         pxDirEntry->usCurrentItem += ( xLFNCount - 1 );\r
1225                         #endif\r
1226                                 }\r
1227                                 else if( ( pxDirEntry->ucAttrib & FF_FAT_ATTR_VOLID ) != FF_FAT_ATTR_VOLID )\r
1228                                 {\r
1229                                         FF_PopulateShortDirent( pxIOManager, pxDirEntry, ucEntryBuffer );\r
1230                                         pxDirEntry->usCurrentItem += 1;\r
1231                                 }\r
1232                         }\r
1233                 }\r
1234                 {\r
1235                 FF_Error_t xTempError;\r
1236                         xTempError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext );\r
1237                         if( FF_isERR( xError ) == pdFALSE )\r
1238                         {\r
1239                                 xError = xTempError;\r
1240                         }\r
1241                 }\r
1242         }\r
1243 \r
1244         return xError;\r
1245 }       /* FF_GetEntry() */\r
1246 /*-----------------------------------------------------------*/\r
1247 \r
1248 \r
1249 FF_Error_t FF_PopulateLongDirent( FF_IOManager_t *pxIOManager, FF_DirEnt_t *pxDirEntry, uint16_t usEntry, FF_FetchContext_t *pxFetchContext )\r
1250 {\r
1251 /* First get the entire name as UTF-16 from the LFN's.\r
1252 Then transform into the API's native string format. */\r
1253 \r
1254 FF_Error_t xError;\r
1255 BaseType_t xNumLFNs;\r
1256 uint8_t ucCheckSum;\r
1257 /* A 32 byte directory entry. */\r
1258 uint8_t pucEntryBuffer[ FF_SIZEOF_DIRECTORY_ENTRY ];\r
1259 char pcShortName[ 13 ];\r
1260 \r
1261 #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
1262         UBaseType_t     uiLfnLength = 0;\r
1263 #endif\r
1264 \r
1265 #if( ffconfigUNICODE_UTF16_SUPPORT == 0 )\r
1266         BaseType_t      xIndex, y;\r
1267 #endif\r
1268 \r
1269 #if( ffconfigUNICODE_UTF16_SUPPORT == 0 ) && ( ffconfigUNICODE_UTF8_SUPPORT == 0 )\r
1270         char    *pcLastPtr = pxDirEntry->pcFileName + sizeof( pxDirEntry->pcFileName );\r
1271         char    *pcCurPtr;\r
1272 #endif\r
1273 \r
1274 #if( ffconfigUNICODE_UTF8_SUPPORT != 0 )\r
1275         uint16_t nLfnBegin;\r
1276         uint16_t        usUtf8Len = 0;\r
1277 #endif /* ffconfigUNICODE_UTF8_SUPPORT */\r
1278 \r
1279         do\r
1280         {\r
1281                 xError = FF_FetchEntryWithContext( pxIOManager, usEntry++, pxFetchContext, pucEntryBuffer );\r
1282                 if( FF_isERR( xError ) )\r
1283                 {\r
1284                         /* After breaking from this do {} while ( pdFALSE ) loop, xResult will be returned. */\r
1285                         break;\r
1286                 }\r
1287 \r
1288                 xNumLFNs = ( BaseType_t )( pucEntryBuffer[0] & ~0x40 );\r
1289                 ucCheckSum = FF_getChar( pucEntryBuffer, FF_FAT_LFN_CHECKSUM );\r
1290 \r
1291                 #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
1292                 {\r
1293                         /* UTF-16 Can simply get segments of the UTF-16 sequence\r
1294                         going forward in the directory entries ( but reversed order ). */\r
1295                         while( xNumLFNs > 0 )\r
1296                         {\r
1297                                 /* Avoid stack intensive use of a UTF-16 buffer. Stream direct to FileName dirent field in correct format. */\r
1298                                 /* memcpy direct! -UTF-16 support. */\r
1299                                 memcpy( pxDirEntry->pcFileName + ( ( xNumLFNs - 1 ) * 13 ) + 0,  &( pucEntryBuffer[ FF_FAT_LFN_NAME_1] ), 10 );\r
1300                                 memcpy( pxDirEntry->pcFileName + ( ( xNumLFNs - 1 ) * 13 ) + 5,  &( pucEntryBuffer[ FF_FAT_LFN_NAME_2] ), 12 );\r
1301                                 memcpy( pxDirEntry->pcFileName + ( ( xNumLFNs - 1 ) * 13 ) + 11, &( pucEntryBuffer[ FF_FAT_LFN_NAME_3] ), 4 );\r
1302                                 uiLfnLength += 13;\r
1303 \r
1304                                 xError = FF_FetchEntryWithContext( pxIOManager, usEntry++, pxFetchContext, pucEntryBuffer );\r
1305                                 if( FF_isERR( xError ) )\r
1306                                 {\r
1307                                         break;\r
1308                                 }\r
1309                                 xNumLFNs--;\r
1310                         }\r
1311                         if( FF_isERR( xError ) )\r
1312                         {\r
1313                                 break;\r
1314                         }\r
1315                         pxDirEntry->pcFileName[ uiLfnLength ] = '\0';\r
1316                 }\r
1317                 #endif /* ffconfigUNICODE_UTF16_SUPPORT */\r
1318 \r
1319                 #if ( ffconfigUNICODE_UTF8_SUPPORT != 0 )\r
1320                 {\r
1321                         /* UTF-8 Sequence, we can only convert this from the beginning, must receive entries in reverse. */\r
1322                         nLfnBegin = usEntry - 1;\r
1323 \r
1324                         for( xIndex = 0; xIndex < xNumLFNs; xIndex++ )\r
1325                         {\r
1326                                 xError = FF_FetchEntryWithContext( pxIOManager, ( nLfnBegin + ( xNumLFNs - 1 ) - xIndex ), pxFetchContext, pucEntryBuffer );\r
1327                                 if( FF_isERR( xError ) )\r
1328                                 {\r
1329                                         break;\r
1330                                 }\r
1331 \r
1332                                 /* Now have the first part of the UTF-16 sequence. Stream into a UTF-8 sequence. */\r
1333                                 for( y = 0; y < 5; y++ )\r
1334                                 {\r
1335                                         xError = FF_Utf16ctoUtf8c( ( uint8_t * )&pxDirEntry->pcFileName[ usUtf8Len ],\r
1336                                                 ( uint16_t * )&pucEntryBuffer[ FF_FAT_LFN_NAME_1 + ( y * 2 ) ], sizeof( pxDirEntry->pcFileName ) - usUtf8Len );\r
1337                                         if( xError > 0 )\r
1338                                         {\r
1339                                                 usUtf8Len += ( uint16_t )xError;\r
1340                                         }\r
1341                                 }\r
1342 \r
1343                                 for( y = 0; y < 6; y++ )\r
1344                                 {\r
1345                                         xError = FF_Utf16ctoUtf8c( ( uint8_t * )&pxDirEntry->pcFileName[ usUtf8Len ],\r
1346                                                 ( uint16_t * )&pucEntryBuffer[ FF_FAT_LFN_NAME_2 + ( y * 2 ) ], sizeof( pxDirEntry->pcFileName ) - usUtf8Len );\r
1347                                         if( xError > 0 )\r
1348                                         {\r
1349                                                 usUtf8Len += ( uint16_t )xError;\r
1350                                         }\r
1351                                 }\r
1352 \r
1353                                 for( y = 0; y < 2; y++ )\r
1354                                 {\r
1355                                         xError = FF_Utf16ctoUtf8c( ( uint8_t * )&pxDirEntry->pcFileName[ usUtf8Len ],\r
1356                                                 ( uint16_t * )&pucEntryBuffer[ FF_FAT_LFN_NAME_3 +  ( y * 2 ) ], sizeof( pxDirEntry->pcFileName ) - usUtf8Len );\r
1357                                         if( xError > 0 )\r
1358                                         {\r
1359                                                 usUtf8Len += ( uint16_t ) xError;\r
1360                                         }\r
1361                                 }\r
1362                                 usEntry++;\r
1363                         }\r
1364                         if( FF_isERR( xError ) )\r
1365                         {\r
1366                                 break;\r
1367                         }\r
1368 \r
1369                         pxDirEntry->pcFileName[ usUtf8Len ] = '\0';\r
1370 \r
1371                         /* Put Entry context to correct position. */\r
1372                         xError = FF_FetchEntryWithContext( pxIOManager, usEntry-1, pxFetchContext, pucEntryBuffer );\r
1373                         if( FF_isERR( xError ) )\r
1374                         {\r
1375                                 break;\r
1376                         }\r
1377                 }\r
1378                 #endif /* ( ffconfigUNICODE_UTF8_SUPPORT != 0 ) */\r
1379 \r
1380                 #if( ffconfigUNICODE_UTF16_SUPPORT == 0 ) && ( ffconfigUNICODE_UTF8_SUPPORT == 0 )      /* No Unicode, simple ASCII. */\r
1381                 {\r
1382                         pcLastPtr[ -1 ] = '\0';\r
1383                         y = xNumLFNs;\r
1384                         while( xNumLFNs-- )\r
1385                         {\r
1386                                 pcCurPtr = pxDirEntry->pcFileName + ( xNumLFNs * 13 );\r
1387                                 for( xIndex = 0; ( xIndex < 10 ) && ( pcCurPtr < pcLastPtr ); xIndex += 2 )\r
1388                                 {\r
1389                                         *( pcCurPtr++ ) = pucEntryBuffer[ FF_FAT_LFN_NAME_1 + xIndex ];\r
1390                                 }\r
1391 \r
1392                                 for( xIndex = 0; ( xIndex < 12 ) && ( pcCurPtr < pcLastPtr ); xIndex += 2 )\r
1393                                 {\r
1394                                         *( pcCurPtr++ ) = pucEntryBuffer[ FF_FAT_LFN_NAME_2 + xIndex ];\r
1395                                 }\r
1396 \r
1397                                 for( xIndex = 0; ( xIndex < 4 ) && ( pcCurPtr < pcLastPtr ); xIndex += 2 )\r
1398                                 {\r
1399                                         *( pcCurPtr++ ) = pucEntryBuffer[ FF_FAT_LFN_NAME_3 + xIndex ];\r
1400                                 }\r
1401                                 if( ( xNumLFNs == ( y - 1 ) ) && ( pcCurPtr < pcLastPtr ) )\r
1402                                 {\r
1403                                         *pcCurPtr = '\0';\r
1404                                 }\r
1405                                 xError = FF_FetchEntryWithContext( pxIOManager, usEntry++, pxFetchContext, pucEntryBuffer );\r
1406                                 if( FF_isERR( xError ) )\r
1407                                 {\r
1408                                         break;\r
1409                                 }\r
1410                         }\r
1411                         if( FF_isERR( xError ) )\r
1412                         {\r
1413                                 break;\r
1414                         }\r
1415                 }\r
1416                 #endif /* ( ffconfigUNICODE_UTF16_SUPPORT == 0 ) && ( ffconfigUNICODE_UTF8_SUPPORT == 0 ) */\r
1417 \r
1418                 /* Process the Shortname. -- LFN Transformation is now complete.\r
1419                 Process the ShortName Entry. */\r
1420 \r
1421                 /* if SHORTNAMES must be included, simple byte copy into shortname buffer. */\r
1422                 #if( ffconfigLFN_SUPPORT != 0 ) && ( ffconfigINCLUDE_SHORT_NAME != 0 )\r
1423                 {\r
1424                         memcpy( pxDirEntry->pcShortName, pucEntryBuffer, 11 );\r
1425                         pxDirEntry->pcShortName[ 11 ] = '\0';\r
1426                         FF_ProcessShortName( pxDirEntry->pcShortName );\r
1427                 }\r
1428                 #endif /* ( != 0 ffconfigLFN_SUPPORT ) && ( ffconfigINCLUDE_SHORT_NAME != 0 ) */\r
1429 \r
1430                 memcpy( pcShortName, pucEntryBuffer, 11 );\r
1431                 FF_ProcessShortName( pcShortName );\r
1432                 if( ucCheckSum != FF_CreateChkSum( pucEntryBuffer ) )\r
1433                 {\r
1434                         strcpy( pxDirEntry->pcFileName, pcShortName );\r
1435                         #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
1436                         {\r
1437                                 FF_ShortNameExpand( pxDirEntry->pcFileName );\r
1438                         }\r
1439                         #endif /* ffconfigUNICODE_UTF16_SUPPORT */\r
1440                 }\r
1441 \r
1442                 /* Finally fill in the other details. */\r
1443                 pxDirEntry->ulObjectCluster =\r
1444                         ( ( uint32_t )FF_getShort( pucEntryBuffer, FF_FAT_DIRENT_CLUS_HIGH ) << 16 ) |\r
1445                           ( uint32_t )FF_getShort( pucEntryBuffer, FF_FAT_DIRENT_CLUS_LOW );\r
1446 \r
1447                 #if( ffconfigTIME_SUPPORT != 0 )\r
1448                 {\r
1449                         /* Get the creation Time & Date. */\r
1450                         FF_GetTime( &pxDirEntry->xCreateTime, pucEntryBuffer, FF_FAT_DIRENT_CREATE_TIME );\r
1451                         FF_GetDate( &pxDirEntry->xCreateTime, pucEntryBuffer, FF_FAT_DIRENT_CREATE_DATE );\r
1452                         /* Get the modified Time & Date. */\r
1453                         /* HT Here xCreateTime has become xModifiedTime, as it should: */\r
1454                         FF_GetTime( &pxDirEntry->xModifiedTime, pucEntryBuffer, FF_FAT_DIRENT_LASTMOD_TIME );\r
1455                         FF_GetDate( &pxDirEntry->xModifiedTime, pucEntryBuffer, FF_FAT_DIRENT_LASTMOD_DATE );\r
1456                         /* Get the last accessed Date. */\r
1457                         FF_GetDate( &pxDirEntry->xAccessedTime, pucEntryBuffer, FF_FAT_DIRENT_LASTACC_DATE );\r
1458                         /* HT Why should these times be zero'd ? */\r
1459                         pxDirEntry->xAccessedTime.Hour          = 0;\r
1460                         pxDirEntry->xAccessedTime.Minute        = 0;\r
1461                         pxDirEntry->xAccessedTime.Second        = 0;\r
1462                 }\r
1463                 #endif /* ffconfigTIME_SUPPORT */\r
1464 \r
1465                 /* Get the filesize. */\r
1466                 pxDirEntry->ulFileSize = FF_getLong( pucEntryBuffer, ( uint16_t ) ( FF_FAT_DIRENT_FILESIZE ) );\r
1467                 /* Get the attribute. */\r
1468                 pxDirEntry->ucAttrib = FF_getChar( pucEntryBuffer, ( uint16_t ) ( FF_FAT_DIRENT_ATTRIB ) );\r
1469 \r
1470                 pxDirEntry->usCurrentItem = usEntry;\r
1471         }\r
1472         while ( pdFALSE );\r
1473 \r
1474         return xError;\r
1475 }       /* FF_PopulateLongDirent() */\r
1476 /*-----------------------------------------------------------*/\r
1477 \r
1478 /**\r
1479  *      @public\r
1480  *      @brief  Find's the first directory entry for the provided path.\r
1481  *\r
1482  *      All values recorded in pxDirEntry must be preserved to and between calls to\r
1483  *      FF_FindNext( ).\r
1484  *\r
1485  *      If ffconfigFINDAPI_ALLOW_WILDCARDS is defined, then path will have the following behaviour:\r
1486  *\r
1487  *      path = "\"                                      - Open the root dir, and iterate through all items.\r
1488  *      path = "\*.c"                           - Open the root dir, showing only files matching *.c wildcard.\r
1489  *      path = "\sub1\newdir"           - Get the DIRENT for the newdir directory in /sub1/ if one exists.\r
1490  *      path = "\sub1\newdir\"          - Open the directory /sub1/newdir/ and iterate through all items.\r
1491  *      path = "\sub1\newdir\*.c"       - Open the directory /sub1/newdir/ and iterate through all items matching the *.c wildcard.\r
1492  *\r
1493  *      It is important to distinguish the differences in behaviour between opening a Find operation\r
1494  *      on a path like /sub1 and /sub1/. ( /sub1 gets the sub1 dirent from the / dir, whereas /sub/ opens the sub1 dir ).\r
1495  *\r
1496  *      Note, as compatible with other similar APIs, FreeRTOS+FAT also accepts \sub1\* for the same behaviour as\r
1497  *      /sub1/.\r
1498  *\r
1499  *      @param  pxIOManager FF_IOManager_t object that was created by FF_CreateIOManger( ).\r
1500  *      @param  pxDirEntry      FF_DirEnt_t object to store the entry information.\r
1501  *      @param  path            String to of the path to the Dir being listed.\r
1502  *\r
1503  *      @Return 0 on success\r
1504  *      @Return FF_ERR_DEVICE_DRIVER_FAILED if device access failed.\r
1505  *      @Return -2 if Dir was not found.\r
1506  *\r
1507  **/\r
1508 #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
1509 FF_Error_t FF_FindFirst( FF_IOManager_t *pxIOManager, FF_DirEnt_t *pxDirEntry, const FF_T_WCHAR *pcPath )\r
1510 #else\r
1511 FF_Error_t FF_FindFirst( FF_IOManager_t *pxIOManager, FF_DirEnt_t *pxDirEntry, const char *pcPath )\r
1512 #endif\r
1513 {\r
1514 FF_Error_t xError;\r
1515 #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
1516         uint16_t        PathLen = ( uint16_t ) wcslen( pcPath );\r
1517 #else\r
1518         uint16_t        PathLen = ( uint16_t ) strlen( pcPath );\r
1519 #endif\r
1520 \r
1521 #if( ffconfigFINDAPI_ALLOW_WILDCARDS != 0 )\r
1522         BaseType_t xIndex = 0;\r
1523         #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
1524                 const FF_T_WCHAR *pcWildCard;   /* Check for a Wild-card. */\r
1525         #else\r
1526                 const char *pcWildCard; /* Check for a Wild-card. */\r
1527         #endif\r
1528 #endif\r
1529 \r
1530         memset( pxDirEntry, 0, sizeof( FF_DirEnt_t ) );\r
1531 \r
1532         if( pxIOManager == NULL )\r
1533         {\r
1534                 xError = ( FF_Error_t ) ( FF_ERR_NULL_POINTER | FF_FINDFIRST );\r
1535         }\r
1536 #if( ffconfigREMOVABLE_MEDIA != 0 )\r
1537         else if( ( pxIOManager->ucFlags & FF_IOMAN_DEVICE_IS_EXTRACTED ) != 0 )\r
1538         {\r
1539                 xError = ( FF_Error_t ) ( FF_ERR_IOMAN_DRIVER_NOMEDIUM | FF_FINDFIRST );\r
1540         }\r
1541 #endif /* ffconfigREMOVABLE_MEDIA */\r
1542         else\r
1543         {\r
1544                 #if( ffconfigFINDAPI_ALLOW_WILDCARDS != 0 )\r
1545                 {\r
1546                         pxDirEntry->pcWildCard[0] = '\0';       /* WildCard blank if its not a wildCard. */\r
1547 \r
1548                         pcWildCard = &pcPath[ PathLen - 1 ];\r
1549 \r
1550                         if( PathLen != 0 )\r
1551                         {\r
1552                                 /* Open the dir of the last token. */\r
1553                                 while( ( *pcWildCard != '\\' ) && ( *pcWildCard != '/' ) )\r
1554                                 {\r
1555                                         xIndex++;\r
1556                                         pcWildCard--;\r
1557                                         if( PathLen == xIndex )\r
1558                                         {\r
1559                                                 break;\r
1560                                         }\r
1561                                 }\r
1562                         }\r
1563 \r
1564                         pxDirEntry->ulDirCluster = FF_FindDir( pxIOManager, pcPath, PathLen - xIndex, &xError );\r
1565                         if( FF_isERR( xError ) == pdFALSE )\r
1566                         {\r
1567                                 if( pxDirEntry->ulDirCluster != 0 )\r
1568                                 {\r
1569                                         /* Valid Dir found, copy the wildCard to filename! */\r
1570                         #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
1571                                         wcsncpy( pxDirEntry->pcWildCard, ++pcWildCard, ffconfigMAX_FILENAME );\r
1572                         #else\r
1573                                         strncpy( pxDirEntry->pcWildCard, ++pcWildCard, ffconfigMAX_FILENAME );\r
1574                         #endif\r
1575                                         if( pxDirEntry->pcWildCard[ xIndex - 1 ] == ':' )\r
1576                                         {\r
1577                                                 pxDirEntry->xInvertWildCard = pdTRUE;\r
1578                                                 pxDirEntry->pcWildCard[ xIndex - 1 ] = '\0';\r
1579                                         }\r
1580                                 }\r
1581                         }\r
1582                 }\r
1583                 #else /* ffconfigFINDAPI_ALLOW_WILDCARDS */\r
1584                 {\r
1585                         /* Get the directory cluster, if it exists. */\r
1586                         pxDirEntry->ulDirCluster = FF_FindDir( pxIOManager, pcPath, PathLen, &xError );\r
1587                 }\r
1588                 #endif /* ffconfigFINDAPI_ALLOW_WILDCARDS */\r
1589 \r
1590                 if( FF_isERR( xError ) == pdFALSE )\r
1591                 {\r
1592                         if( pxDirEntry->ulDirCluster == 0 )\r
1593                         {\r
1594                                 xError = ( FF_Error_t ) ( FF_ERR_DIR_INVALID_PATH | FF_FINDFIRST );\r
1595                         }\r
1596                         else\r
1597                         {\r
1598                                 /* Initialise the Fetch Context. */\r
1599                                 xError = FF_InitEntryFetch( pxIOManager, pxDirEntry->ulDirCluster, &( pxDirEntry->xFetchContext ) );\r
1600                                 if( FF_isERR( xError ) == pdFALSE )\r
1601                                 {\r
1602                                         pxDirEntry->usCurrentItem = 0;\r
1603                                         xError = FF_FindNext( pxIOManager, pxDirEntry );\r
1604                                 }\r
1605                         }\r
1606                 }\r
1607         }\r
1608 \r
1609         return xError;\r
1610 }       /* FF_FindFirst() */\r
1611 /*-----------------------------------------------------------*/\r
1612 \r
1613 /**\r
1614  *      @public\r
1615  *      @brief  Get's the next Entry based on the data recorded in the FF_DirEnt_t object.\r
1616  *\r
1617  *      All values recorded in pxDirEntry must be preserved to and between calls to\r
1618  *      FF_FindNext( ). Please see @see FF_FindFirst( ) for find initialisation.\r
1619  *\r
1620  *      @param  pxIOManager             FF_IOManager_t object that was created by FF_CreateIOManger( ).\r
1621  *      @param  pxDirEntry              FF_DirEnt_t object to store the entry information. ( As initialised by FF_FindFirst( )).\r
1622  *\r
1623  *      @Return FF_ERR_DEVICE_DRIVER_FAILED is device access failed.\r
1624  *\r
1625  **/\r
1626 FF_Error_t FF_FindNext( FF_IOManager_t *pxIOManager, FF_DirEnt_t *pxDirEntry )\r
1627 {\r
1628 FF_Error_t xError;\r
1629 BaseType_t xLFNCount;\r
1630 const uint8_t *pucEntryBuffer = NULL;\r
1631 #if( ffconfigFINDAPI_ALLOW_WILDCARDS != 0 )\r
1632         BaseType_t      b;\r
1633 #endif\r
1634 \r
1635         if( pxIOManager == NULL )\r
1636         {\r
1637                 xError = ( FF_Error_t ) ( FF_ERR_NULL_POINTER | FF_FINDNEXT );\r
1638         }\r
1639 #if( ffconfigREMOVABLE_MEDIA != 0 )\r
1640         else if( ( pxIOManager->ucFlags & FF_IOMAN_DEVICE_IS_EXTRACTED ) != 0 )\r
1641         {\r
1642                 xError = ( FF_Error_t ) ( FF_ERR_IOMAN_DRIVER_NOMEDIUM | FF_FINDNEXT );\r
1643         }\r
1644 #endif /* ffconfigREMOVABLE_MEDIA */\r
1645         else\r
1646         {\r
1647                 xError = FF_ERR_NONE;\r
1648                 for( ; pxDirEntry->usCurrentItem < FF_MAX_ENTRIES_PER_DIRECTORY; pxDirEntry->usCurrentItem++ )\r
1649                 {\r
1650                         if( ( pucEntryBuffer == NULL ) ||\r
1651                                 ( pucEntryBuffer >= ( pxDirEntry->xFetchContext.pxBuffer->pucBuffer + ( FF_SIZEOF_SECTOR - FF_SIZEOF_DIRECTORY_ENTRY ) ) ) )\r
1652                         {\r
1653                                 xError = FF_FetchEntryWithContext( pxIOManager, pxDirEntry->usCurrentItem, &( pxDirEntry->xFetchContext ), NULL );\r
1654 \r
1655                                 if( FF_isERR( xError ) )\r
1656                                 {\r
1657                                         break;\r
1658                                 }\r
1659 \r
1660                                 if( pucEntryBuffer == NULL )\r
1661                                 {\r
1662                                         pucEntryBuffer = pxDirEntry->xFetchContext.pxBuffer->pucBuffer +\r
1663                                                 ( FF_SIZEOF_DIRECTORY_ENTRY * ( pxDirEntry->usCurrentItem % ( FF_SIZEOF_SECTOR/FF_SIZEOF_DIRECTORY_ENTRY ) ) );\r
1664                                 }\r
1665                                 else\r
1666                                 {\r
1667                                         pucEntryBuffer = pxDirEntry->xFetchContext.pxBuffer->pucBuffer;\r
1668                                 }\r
1669                         }\r
1670                         else\r
1671                         {\r
1672                                 pucEntryBuffer += FF_SIZEOF_DIRECTORY_ENTRY;\r
1673                         }\r
1674 \r
1675                         if( FF_isDeleted( pucEntryBuffer ) != pdFALSE )\r
1676                         {\r
1677                                 /* The entry is not in use or deleted. */\r
1678                                 continue;\r
1679                         }\r
1680 \r
1681                         if( FF_isEndOfDir( pucEntryBuffer ) )\r
1682                         {\r
1683                                 /* End of directory, generate a pseudo error 'DIR_END_OF_DIR'. */\r
1684                                 xError = ( FF_Error_t ) ( FF_ERR_DIR_END_OF_DIR | FF_FINDNEXT );\r
1685                                 break;\r
1686                         }\r
1687 \r
1688                         pxDirEntry->ucAttrib = FF_getChar( pucEntryBuffer, ( uint16_t ) ( FF_FAT_DIRENT_ATTRIB ) );\r
1689 \r
1690                         if( ( pxDirEntry->ucAttrib & FF_FAT_ATTR_LFN ) == FF_FAT_ATTR_LFN )\r
1691                         {\r
1692                                 /* LFN Processing. */\r
1693                                 xLFNCount = ( BaseType_t )( pucEntryBuffer[0] & ~0x40 );\r
1694                                 /* Get the shortname and check if it is marked deleted. */\r
1695                                 #if( ffconfigLFN_SUPPORT != 0 )\r
1696                                 {\r
1697                                 /* Reserve 32 bytes to hold one directory entry. */\r
1698                                 uint8_t Buffer[ FF_SIZEOF_DIRECTORY_ENTRY ];\r
1699 \r
1700                                         /* Fetch the shortname, and get it's checksum, or for a deleted item with\r
1701                                         orphaned LFN entries. */\r
1702                                         xError = FF_FetchEntryWithContext( pxIOManager, ( uint32_t ) ( pxDirEntry->usCurrentItem + xLFNCount ), &pxDirEntry->xFetchContext, Buffer );\r
1703                                         if( FF_isERR( xError ) )\r
1704                                         {\r
1705                                                 break;\r
1706                                         }\r
1707 \r
1708                                         if( FF_isDeleted( Buffer ) == pdFALSE )\r
1709                                         {\r
1710                                                 xError = FF_PopulateLongDirent( pxIOManager, pxDirEntry, pxDirEntry->usCurrentItem, &pxDirEntry->xFetchContext );\r
1711                                                 if( FF_isERR( xError ) )\r
1712                                                 {\r
1713                                                         break;\r
1714                                                 }\r
1715                                                 #if( ffconfigINCLUDE_SHORT_NAME != 0 )\r
1716                                                 {\r
1717                                                         pxDirEntry->ucAttrib |= FF_FAT_ATTR_IS_LFN;\r
1718                                                 }\r
1719                                                 #endif\r
1720 \r
1721                                                 #if( ffconfigFINDAPI_ALLOW_WILDCARDS != 0 )\r
1722                                                 {\r
1723                                                 #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
1724                                                         if( wcscmp( pxDirEntry->pcWildCard, L"" ) )\r
1725                                                 #else\r
1726                                                         if( pxDirEntry->pcWildCard[0] )\r
1727                                                 #endif\r
1728                                                         {\r
1729                                                                 b = FF_wildcompare( pxDirEntry->pcWildCard, pxDirEntry->pcFileName );\r
1730                                                                 if( pxDirEntry->xInvertWildCard != pdFALSE )\r
1731                                                                 {\r
1732                                                                         b = !b;\r
1733                                                                 }\r
1734                                                                 if( b != 0 )\r
1735                                                                 {\r
1736                                                                         break;\r
1737                                                                 }\r
1738 \r
1739                                                                 /* 'usCurrentItem' has already incremented by FF_PopulateLongDirent(),\r
1740                                                                 this loop will incremente it again. */\r
1741                                                                 pxDirEntry->usCurrentItem -= 1;\r
1742 \r
1743                                                                 /* xFetchContext/usCurrentItem have changed.  Update\r
1744                                                                 'pucEntryBuffer' to point to the current buffer position. */\r
1745                                                                 pucEntryBuffer = pxDirEntry->xFetchContext.pxBuffer->pucBuffer +\r
1746                                                                         ( FF_SIZEOF_DIRECTORY_ENTRY * ( pxDirEntry->usCurrentItem % ( FF_SIZEOF_SECTOR/FF_SIZEOF_DIRECTORY_ENTRY ) ) );\r
1747                                                         }\r
1748                                                         else\r
1749                                                         {\r
1750                                                                 break;\r
1751                                                         }\r
1752                                                 }\r
1753                                                 #else   /* ffconfigFINDAPI_ALLOW_WILDCARDS == 0 */\r
1754                                                 {\r
1755                                                         /* usCurrentItem has been incremented by FF_PopulateLongDirent().\r
1756                                                         Entry will be returned. */\r
1757                                                         break;\r
1758                                                 }\r
1759                                                 #endif\r
1760                                         }\r
1761                                 }\r
1762                                 #else /* ffconfigLFN_SUPPORT */\r
1763                                 {\r
1764                                         /* Increment 'usCurrentItem' with (xLFNCount-1),\r
1765                                         the loop will do an extra increment. */\r
1766                                         pxDirEntry->usCurrentItem += ( xLFNCount - 1 );\r
1767                                 }\r
1768                                 #endif /* ffconfigLFN_SUPPORT */\r
1769                         } /* ( ( pxDirEntry->ucAttrib & FF_FAT_ATTR_LFN ) == FF_FAT_ATTR_LFN ) */\r
1770                         else if( ( pxDirEntry->ucAttrib & FF_FAT_ATTR_VOLID ) != FF_FAT_ATTR_VOLID )\r
1771                         {\r
1772                                 /* If it's not a LFN entry, neither a Volume ID, it is a normal short name entry. */\r
1773                                 FF_PopulateShortDirent( pxIOManager, pxDirEntry, pucEntryBuffer );\r
1774                                 #if( ffconfigSHORTNAME_CASE != 0 )\r
1775                                 {\r
1776                                         /* Apply NT/XP+ bits to get correct case. */\r
1777                                         FF_CaseShortName( pxDirEntry->pcFileName, FF_getChar( pucEntryBuffer, FF_FAT_CASE_OFFS ) );\r
1778                                 }\r
1779                                 #endif\r
1780 \r
1781                                 #if( ffconfigFINDAPI_ALLOW_WILDCARDS != 0 )\r
1782                                 {\r
1783                                         if( pxDirEntry->pcWildCard[ 0 ] )\r
1784                                         {\r
1785                                                 b = FF_wildcompare( pxDirEntry->pcWildCard, pxDirEntry->pcFileName );\r
1786                                                 if( pxDirEntry->xInvertWildCard != pdFALSE )\r
1787                                                 {\r
1788                                                         b = !b;\r
1789                                                 }\r
1790                                                 if( b != 0 )\r
1791                                                 {\r
1792                                                         pxDirEntry->usCurrentItem += 1;\r
1793                                                         break;\r
1794                                                 }\r
1795                                         }\r
1796                                         else\r
1797                                         {\r
1798                                                 pxDirEntry->usCurrentItem += 1;\r
1799                                                 break;\r
1800                                         }\r
1801                                 }\r
1802                                 #else /* ffconfigFINDAPI_ALLOW_WILDCARDS */\r
1803                                 {\r
1804                                         pxDirEntry->usCurrentItem += 1;\r
1805                                         break;\r
1806                                 }\r
1807                                 #endif\r
1808                         }\r
1809                 } /* for ( ; pxDirEntry->usCurrentItem < FF_MAX_ENTRIES_PER_DIRECTORY; pxDirEntry->usCurrentItem++ ) */\r
1810 \r
1811                 if( pxDirEntry->usCurrentItem == FF_MAX_ENTRIES_PER_DIRECTORY )\r
1812                 {\r
1813                         xError = ( FF_Error_t ) ( FF_ERR_DIR_END_OF_DIR | FF_FINDNEXT );\r
1814                 }\r
1815 \r
1816                 {\r
1817                 FF_Error_t xTempError;\r
1818                         xTempError = FF_CleanupEntryFetch( pxIOManager, &pxDirEntry->xFetchContext );\r
1819 \r
1820                         if( FF_isERR( xError ) == pdFALSE )\r
1821                         {\r
1822                                 xError = xTempError;\r
1823                         }\r
1824                 }\r
1825         }\r
1826 \r
1827         return xError;\r
1828 }       /* FF_FindNext() */\r
1829 /*-----------------------------------------------------------*/\r
1830 \r
1831 \r
1832 /*\r
1833         Returns >= 0 for a free dirent entry.\r
1834         Returns <  0 with and xError code if anything goes wrong.\r
1835 */\r
1836 static int32_t FF_FindFreeDirent( FF_IOManager_t *pxIOManager, FF_FindParams_t *pxFindParams, uint16_t usSequential )\r
1837 {\r
1838 const uint8_t *pucEntryBuffer = NULL;\r
1839 uint16_t freeCount = 0;\r
1840 UBaseType_t uxEntry = 0;\r
1841 BaseType_t xEntryFound = pdFALSE;\r
1842 FF_Error_t xError;\r
1843 uint32_t DirLength;\r
1844 FF_FetchContext_t xFetchContext;\r
1845 uint32_t ulDirCluster = pxFindParams->ulDirCluster;\r
1846 \r
1847         xError = FF_InitEntryFetch( pxIOManager, ulDirCluster, &xFetchContext );\r
1848 \r
1849         if( FF_isERR( xError ) == pdFALSE )\r
1850         {\r
1851                 uxEntry = pxFindParams->lFreeEntry >= 0 ? pxFindParams->lFreeEntry : 0;\r
1852                 for ( ; uxEntry < FF_MAX_ENTRIES_PER_DIRECTORY; uxEntry++ )\r
1853                 {\r
1854                         if( ( pucEntryBuffer == NULL ) ||\r
1855                                 ( pucEntryBuffer >= xFetchContext.pxBuffer->pucBuffer + ( FF_SIZEOF_SECTOR - FF_SIZEOF_DIRECTORY_ENTRY ) ) )\r
1856                         {\r
1857                                 xError = FF_FetchEntryWithContext( pxIOManager, uxEntry, &xFetchContext, NULL );\r
1858                                 if( FF_GETERROR( xError ) == FF_ERR_DIR_END_OF_DIR )\r
1859                                 {\r
1860 \r
1861                                         xError = FF_ExtendDirectory( pxIOManager, ulDirCluster );\r
1862                                         /* The value of xEntryFound will be ignored in case there was an error. */\r
1863                                         xEntryFound = pdTRUE;\r
1864                                         break;\r
1865                                 }\r
1866                                 else if( FF_isERR( xError ) )\r
1867                                 {\r
1868                                         break;\r
1869                                 }\r
1870                                 if( pucEntryBuffer == NULL )\r
1871                                 {\r
1872                                         pucEntryBuffer = xFetchContext.pxBuffer->pucBuffer +\r
1873                                                 ( FF_SIZEOF_DIRECTORY_ENTRY * ( uxEntry % ( FF_SIZEOF_SECTOR / FF_SIZEOF_DIRECTORY_ENTRY ) ) );\r
1874                                 }\r
1875                                 else\r
1876                                 {\r
1877                                         pucEntryBuffer = xFetchContext.pxBuffer->pucBuffer;\r
1878                                 }\r
1879                         }\r
1880                         else\r
1881                         {\r
1882                                 /* Advance 32 bytes to point to the next directory entry. */\r
1883                                 pucEntryBuffer += FF_SIZEOF_DIRECTORY_ENTRY;\r
1884                         }\r
1885                         if( FF_isEndOfDir( pucEntryBuffer ) )   /* If its the end of the Dir, then FreeDirents from here. */\r
1886                         {\r
1887                                 /* Check if the directory has enough space */\r
1888                                 DirLength = xFetchContext.ulChainLength;\r
1889                                 if( ( uxEntry + usSequential ) >\r
1890                                         ( ( DirLength * ( ( UBaseType_t )pxIOManager->xPartition.ulSectorsPerCluster * pxIOManager->xPartition.usBlkSize ) ) / FF_SIZEOF_DIRECTORY_ENTRY ) )\r
1891                                 {\r
1892                                         xError = FF_ExtendDirectory( pxIOManager, ulDirCluster );\r
1893                                 }\r
1894                                 xEntryFound = pdTRUE;\r
1895                                 break;\r
1896                         }\r
1897                         if( FF_isDeleted( pucEntryBuffer ) )\r
1898                         {\r
1899                                 if( ++freeCount == usSequential )\r
1900                                 {\r
1901                                         xError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext );\r
1902                                         xEntryFound = pdTRUE;\r
1903                                         uxEntry = ( uxEntry - ( usSequential - 1 ) );/* Return the beginning entry in the sequential sequence. */\r
1904                                         break;\r
1905                                 }\r
1906                         }\r
1907                         else\r
1908                         {\r
1909                                 freeCount = 0;\r
1910                         }\r
1911                 }       /* for ( uxEntry = 0; uxEntry < FF_MAX_ENTRIES_PER_DIRECTORY; uxEntry++ ) */\r
1912 \r
1913                 {\r
1914                 FF_Error_t xTempError;\r
1915 \r
1916                         xTempError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext );\r
1917                         if( FF_isERR( xError ) == pdFALSE )\r
1918                         {\r
1919                                 xError = xTempError;\r
1920                         }\r
1921                 }\r
1922 \r
1923         }\r
1924 \r
1925         if( FF_isERR( xError ) == pdFALSE )\r
1926         {\r
1927                 if( xEntryFound != pdFALSE )\r
1928                 {\r
1929                         /* No error has occurred and a free directory entry has been found. */\r
1930                         xError = uxEntry;\r
1931                 }\r
1932                 else\r
1933                 {\r
1934                         xError = ( FF_Error_t ) ( FF_ERR_DIR_DIRECTORY_FULL | FF_FINDFREEDIRENT );\r
1935                 }\r
1936         }\r
1937 \r
1938         return xError;\r
1939 }       /* FF_FindFreeDirent() */\r
1940 /*-----------------------------------------------------------*/\r
1941 \r
1942 /* _HT_ Now FF_PutEntry has a new optional parameter *pucContents */\r
1943 /* _HT_ so it can be used FF_MkDir( ) to save some code when adding . and .. entries  */\r
1944 FF_Error_t FF_PutEntry( FF_IOManager_t *pxIOManager, uint16_t usEntry, uint32_t ulDirCluster, FF_DirEnt_t *pxDirEntry, uint8_t *pucContents )\r
1945 {\r
1946 FF_Error_t xError;\r
1947 /* Reserve 32 bytes to hold one directory entry. */\r
1948 uint8_t pucEntryBuffer[ FF_SIZEOF_DIRECTORY_ENTRY ];\r
1949 FF_FetchContext_t xFetchContext;\r
1950 \r
1951         /* HT: use the standard access routine to get the same logic for root dirs. */\r
1952         xError = FF_InitEntryFetch( pxIOManager, ulDirCluster, &xFetchContext );\r
1953         if( FF_isERR( xError ) == pdFALSE )\r
1954         {\r
1955                 xError = FF_FetchEntryWithContext( pxIOManager, usEntry, &xFetchContext, pucEntryBuffer );\r
1956                 if( FF_isERR( xError ) == pdFALSE )\r
1957                 {\r
1958                         /* Cleanup probably not necessary here?\r
1959                         FF_PushEntryWithContext checks for R/W flag. */\r
1960                         xError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext );\r
1961                         if( FF_isERR( xError ) == pdFALSE )\r
1962                         {\r
1963                                 if ( pucContents != NULL )\r
1964                                 {\r
1965                                         memcpy ( pucEntryBuffer, pucContents, sizeof( pucEntryBuffer ) );\r
1966                                 }\r
1967                                 FF_putChar( pucEntryBuffer,  FF_FAT_DIRENT_ATTRIB,    ( uint32_t ) pxDirEntry->ucAttrib );\r
1968                                 FF_putShort( pucEntryBuffer, FF_FAT_DIRENT_CLUS_HIGH, ( uint32_t ) ( pxDirEntry->ulObjectCluster >> 16 ) );\r
1969                                 FF_putShort( pucEntryBuffer, FF_FAT_DIRENT_CLUS_LOW,  ( uint32_t ) ( pxDirEntry->ulObjectCluster ) );\r
1970                                 FF_putLong( pucEntryBuffer,  FF_FAT_DIRENT_FILESIZE,  pxDirEntry->ulFileSize );\r
1971                                 #if( ffconfigTIME_SUPPORT != 0 )\r
1972                                 {\r
1973                                         FF_GetSystemTime( &pxDirEntry->xAccessedTime ); /*/< Date of Last Access. */\r
1974                                         FF_PlaceTime( pucEntryBuffer, FF_FAT_DIRENT_LASTACC_DATE, &pxDirEntry->xAccessedTime );\r
1975                                         FF_PlaceDate( pucEntryBuffer, FF_FAT_DIRENT_LASTACC_DATE, &pxDirEntry->xAccessedTime ); /* Last accessed date. */\r
1976                                         FF_PlaceTime( pucEntryBuffer, FF_FAT_DIRENT_CREATE_TIME,  &pxDirEntry->xCreateTime );\r
1977                                         FF_PlaceDate( pucEntryBuffer, FF_FAT_DIRENT_CREATE_DATE,  &pxDirEntry->xCreateTime );\r
1978                                         FF_PlaceTime( pucEntryBuffer, FF_FAT_DIRENT_LASTMOD_TIME, &pxDirEntry->xModifiedTime );\r
1979                                         FF_PlaceDate( pucEntryBuffer, FF_FAT_DIRENT_LASTMOD_DATE, &pxDirEntry->xModifiedTime );\r
1980                                 }\r
1981                                 #endif  /* ffconfigTIME_SUPPORT */\r
1982                                 xError = FF_PushEntryWithContext( pxIOManager, usEntry, &xFetchContext, pucEntryBuffer );\r
1983                         }\r
1984                 }\r
1985         }\r
1986 \r
1987         FF_CleanupEntryFetch( pxIOManager, &xFetchContext );\r
1988 \r
1989         return xError;\r
1990 }       /* FF_PutEntry() */\r
1991 /*-----------------------------------------------------------*/\r
1992 \r
1993 static BaseType_t FF_ValidShortChar( char cChar )\r
1994 {\r
1995         return ( cChar >= 'A' && cChar <= 'Z' ) ||\r
1996                 ( cChar >= 'a' && cChar <= 'z' ) ||     /* lower-case can be stored using NT/XP attribute. */\r
1997                 ( cChar >= '0' && cChar <= '9' ) ||\r
1998                 strchr ( "$%-_@~`!(){}^#&", cChar ) != NULL;\r
1999 }       /* FF_ValidShortChar() */\r
2000 /*-----------------------------------------------------------*/\r
2001 \r
2002 #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
2003 void FF_CreateShortName( FF_FindParams_t *pxFindParams, const FF_T_WCHAR *pcLongName )\r
2004 #else\r
2005 void FF_CreateShortName( FF_FindParams_t *pxFindParams, const char *pcLongName )\r
2006 #endif\r
2007 {\r
2008 BaseType_t xIndex, xPosition, xLastDot;\r
2009 uint16_t NameLen;\r
2010 \r
2011 #if( ffconfigSHORTNAME_CASE != 0 )\r
2012         uint8_t testAttrib = FF_FAT_CASE_ATTR_BASE;\r
2013 #endif\r
2014 \r
2015         /* Examples:\r
2016          * "readme.TXT" will get the attribute FF_FAT_CASE_ATTR_BASE\r
2017          * "README.txt" will get the attribute FF_FAT_CASE_ATTR_EXT\r
2018          * "Readme.txt" can not be store as a short name */\r
2019 \r
2020         pxFindParams->ucCaseAttrib = 0;         /* May get the value FF_FAT_CASE_ATTR_BASE or FF_FAT_CASE_ATTR_EXT */\r
2021         pxFindParams->ucFirstTilde = 6;         /* The numerical position of the ~ */\r
2022         pxFindParams->ulFlags |= FIND_FLAG_SHORTNAME_SET | FIND_FLAG_FITS_SHORT | FIND_FLAG_SIZE_OK;\r
2023 \r
2024         #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
2025         {\r
2026                 NameLen = ( uint16_t ) wcslen( pcLongName );\r
2027         }\r
2028         #else\r
2029         {\r
2030                 NameLen = ( uint16_t ) strlen( pcLongName );\r
2031         }\r
2032         #endif\r
2033 \r
2034         /* Does pcLongName fit a shortname? */\r
2035 \r
2036         for( xIndex = 0, xPosition = 0, xLastDot = NameLen; xIndex < NameLen; xIndex++ )\r
2037         {\r
2038                 if( pcLongName[ xIndex ] != '.' )\r
2039                 {\r
2040                         xPosition++;\r
2041                 }\r
2042                 else\r
2043                 {\r
2044                         xLastDot = xIndex;\r
2045                 }\r
2046         }\r
2047         /* For example:\r
2048         "FILENAME.EXT": NameLen = 12, xLastDot = 8, xPosition = 11\r
2049         ".cproject"   : NameLen =  9, xLastDot = 0, xPosition =  8\r
2050         */\r
2051 \r
2052         if( ( NameLen > 12 ) ||                         /* If name is longer than 12 characters (8.3). */\r
2053                 ( NameLen - xPosition > 1 ) ||  /* If it contains more than 1 dot. */\r
2054                 ( NameLen - xLastDot > 4 ) ||   /* If the file name extension is longer than 3 characters. */\r
2055                 ( xLastDot > 8 ) )                              /* If the file name base is too long. */\r
2056         {\r
2057                 pxFindParams->ulFlags &= ~FIND_FLAG_SIZE_OK;\r
2058         }\r
2059 \r
2060         for( xIndex = 0, xPosition = 0; xIndex < 11; xPosition++ )\r
2061         {\r
2062                 char ch = pcLongName[ xPosition ];\r
2063                 if( !ch )\r
2064                         break;\r
2065                 if( ( xIndex == 0 ) && ( ch == '.' ) )\r
2066                 {\r
2067                         pxFindParams->ulFlags &= ~FIND_FLAG_FITS_SHORT;\r
2068                         continue;\r
2069                 }\r
2070                 if( xPosition == xLastDot )\r
2071                 {\r
2072                         /* Remember where we put the first space. */\r
2073                         if ( pxFindParams->ucFirstTilde > xIndex )\r
2074                         {\r
2075                                 pxFindParams->ucFirstTilde = xIndex;\r
2076                         }\r
2077                         while ( xIndex < 8 )\r
2078                         {\r
2079                                 pxFindParams->pcEntryBuffer[ xIndex++ ] = 0x20;\r
2080                         }\r
2081                         #if( ffconfigSHORTNAME_CASE != 0 )\r
2082                         {\r
2083                                 testAttrib = FF_FAT_CASE_ATTR_EXT;\r
2084                         }\r
2085                         #endif\r
2086                 }\r
2087                 else\r
2088                 {\r
2089                         if( xIndex == 8 )\r
2090                         {\r
2091                                 if( xPosition <= xLastDot )\r
2092                                 {\r
2093                                         xPosition = xLastDot;\r
2094                                         ch = ( int8_t ) pcLongName[ xPosition ];\r
2095                                         if( ch == '\0' )\r
2096                                         {\r
2097                                                 break;\r
2098                                         }\r
2099                                         ch = ( int8_t ) pcLongName[ ++xPosition ];\r
2100                                         #if( ffconfigSHORTNAME_CASE != 0 )\r
2101                                         {\r
2102                                                 testAttrib = FF_FAT_CASE_ATTR_EXT;\r
2103                                         }\r
2104                                         #endif\r
2105                                 }\r
2106                         }\r
2107                         if( !FF_ValidShortChar ( ch ) )\r
2108                         {\r
2109                                 pxFindParams->ulFlags &= ~FIND_FLAG_FITS_SHORT;\r
2110                                 continue;\r
2111                         }\r
2112                         #if( ffconfigSHORTNAME_CASE != 0 )\r
2113                         {\r
2114                                 if( ( ch >= 'a' ) && ( ch <= 'z' ) )\r
2115                                 {\r
2116                                         ch -= 0x20;\r
2117                                         if ( testAttrib )\r
2118                                         {\r
2119                                                 pxFindParams->ucCaseAttrib |= testAttrib;\r
2120                                         }\r
2121                                         else\r
2122                                         {\r
2123                                                 pxFindParams->ulFlags &= ~FIND_FLAG_FITS_SHORT; /* We had capital: does not fit. */\r
2124                                         }\r
2125                                 }\r
2126                                 else if( ( ch >= 'A' ) && ( ch <= 'Z' ) )\r
2127                                 {\r
2128                                         if( ( pxFindParams->ucCaseAttrib & testAttrib ) != 0 )\r
2129                                         {\r
2130                                                 pxFindParams->ulFlags &= ~FIND_FLAG_FITS_SHORT; /* We had lower-case: does not fit. */\r
2131                                         }\r
2132                                         testAttrib = 0;\r
2133                                 }\r
2134                         }\r
2135                         #else\r
2136                         {\r
2137                                 if( ( ch >= 'a' ) && ( ch <= 'z' ) )\r
2138                                 {\r
2139                                         ch -= 0x20;\r
2140                                 }\r
2141                         }\r
2142                         #endif /* ffconfigSHORTNAME_CASE */\r
2143                         pxFindParams->pcEntryBuffer[ xIndex++ ] = ch;\r
2144                 }\r
2145         }\r
2146 \r
2147         if( ( xLastDot == 0 ) && ( xIndex < 6 ) )\r
2148         {\r
2149                 /* This is a file name like ".info" or ".root" */\r
2150                 pxFindParams->ucFirstTilde = xIndex;\r
2151         }\r
2152 \r
2153         while ( xIndex < 11 )\r
2154         {\r
2155                 pxFindParams->pcEntryBuffer[ xIndex++ ] = 0x20;\r
2156         }\r
2157 \r
2158         if( ( xLastDot < pxFindParams->ucFirstTilde ) && ( xLastDot > 0 ) )\r
2159         {\r
2160                 pxFindParams->ucFirstTilde = xLastDot;\r
2161         }\r
2162 \r
2163         if( NameLen < pxFindParams->ucFirstTilde )      /* Names like "Abc" will become "~Abc". */\r
2164         {\r
2165                 pxFindParams->ucFirstTilde = ( uint8_t ) NameLen;\r
2166         }\r
2167 }       /* FF_CreateShortName() */\r
2168 /*-----------------------------------------------------------*/\r
2169 \r
2170 int32_t FF_FindShortName( FF_IOManager_t *pxIOManager, FF_FindParams_t *pxFindParams )\r
2171 {\r
2172 char pcMyShortName[ 13 ];\r
2173 FF_DirEnt_t xMyDirectory;\r
2174 FF_Error_t xResult = 0;\r
2175 BaseType_t xIndex, x, y;\r
2176 uint16_t NameLen;\r
2177 char pcNumberBuf[ 12 ];\r
2178 uint32_t ulCluster;\r
2179 \r
2180 #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
2181         FF_T_WCHAR      pcFileName[ 13 ];\r
2182 #else\r
2183         char    *pcFileName = pcMyShortName;\r
2184 #endif  /* ffconfigUNICODE_UTF16_SUPPORT */\r
2185 \r
2186 #if( ipconfigQUICK_SHORT_FILENAME_CREATION != 0 )\r
2187         uint16_t usShortHash;\r
2188         uint32_t ulRand = 0ul;\r
2189 #endif\r
2190 \r
2191         memcpy( pcMyShortName, pxFindParams->pcEntryBuffer, 11 );\r
2192         FF_ProcessShortName( pcMyShortName );\r
2193         if( ( pxFindParams->ulFlags & FIND_FLAG_FITS_SHORT_OK ) == FIND_FLAG_FITS_SHORT_OK )\r
2194         {\r
2195                 /* This entry will not get a LFN entry because it fits\r
2196                  * perfectly into a host name */\r
2197                 if( ( pxFindParams->ulFlags & FIND_FLAG_SHORTNAME_CHECKED ) != 0 )\r
2198                 {\r
2199                         if( ( pxFindParams->ulFlags & FIND_FLAG_SHORTNAME_FOUND ) != 0 )\r
2200                         {\r
2201                                 xResult = ( FF_Error_t ) ( FF_ERR_DIR_OBJECT_EXISTS | FF_CREATESHORTNAME );\r
2202                         }\r
2203                         else\r
2204                         {\r
2205                                 xResult = pxFindParams->ucCaseAttrib | 0x01;\r
2206                         }\r
2207                 }\r
2208                 else\r
2209                 {\r
2210                         #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
2211                         {\r
2212                                 memcpy( pcFileName, pcMyShortName, sizeof( pcMyShortName ) );\r
2213                                 FF_ShortNameExpand( pcFileName );\r
2214                         }\r
2215                         #endif\r
2216                         ulCluster = FF_FindEntryInDir( pxIOManager, pxFindParams, pcFileName, 0x00, &xMyDirectory, &xResult );\r
2217 \r
2218                         /* END_OF_DIR is not a fatal error, it only means that the entry was not found. */\r
2219                         if( ( FF_isERR( xResult ) == pdFALSE ) || ( FF_GETERROR( xResult ) == FF_ERR_DIR_END_OF_DIR ) )\r
2220                         {\r
2221                                 if( ulCluster == 0UL )\r
2222                                 {\r
2223                                         xResult = pxFindParams->ucCaseAttrib | 0x01;\r
2224                                 }\r
2225                                 else\r
2226                                 {\r
2227                                         xResult = ( FF_Error_t ) ( FF_ERR_DIR_OBJECT_EXISTS | FF_CREATESHORTNAME );\r
2228                                 }\r
2229                         }\r
2230                         else\r
2231                         {\r
2232                                 /* There was an error, which will be returned. */\r
2233                         }\r
2234                 }\r
2235         }\r
2236         else\r
2237         {\r
2238                 for( xIndex = ( ( pxFindParams->ulFlags & FIND_FLAG_SIZE_OK ) ? 0 : 1 ); ; xIndex++ )\r
2239                 {\r
2240                         if( xIndex != 0 )\r
2241                         {\r
2242                                 #if( ipconfigQUICK_SHORT_FILENAME_CREATION != 0 )\r
2243                                 {\r
2244                                         /* In the first round, check if the original name can be used\r
2245                                         Makefile will be stored as "makefile" and not as "makefi~1". */\r
2246 \r
2247                                         /* This method saves a lot of time when creating directories with\r
2248                                         many similar file names: when the short name version of a LFN already\r
2249                                         exists, try at most 3 entries with a tilde:\r
2250                                                 README~1.TXT\r
2251                                                 README~2.TXT\r
2252                                                 README~3.TXT\r
2253                                         After that create entries with pseudo-random 4-digit hex digits:\r
2254                                                 REA~E7BB.TXT\r
2255                                                 REA~BA32.TXT\r
2256                                                 REA~D394.TXT\r
2257                                         */\r
2258                                         if( xIndex <= 4 )\r
2259                                         {\r
2260                                                 snprintf( pcNumberBuf, sizeof( pcNumberBuf ), "%d", ( int ) xIndex );\r
2261                                         }\r
2262                                         else\r
2263                                         {\r
2264                                                 if( ulRand == 0ul )\r
2265                                                 {\r
2266                                                         ulRand = pxIOManager->xPartition.ulLastFreeCluster;\r
2267                                                         usShortHash = FF_GetCRC16( ( uint8_t *)&ulRand, sizeof( ulRand ) );\r
2268                                                 }\r
2269                                                 else\r
2270                                                 {\r
2271                                                         usShortHash = FF_GetCRC16( ( uint8_t *)&usShortHash, sizeof( usShortHash ) );\r
2272                                                 }\r
2273                                                 snprintf( pcNumberBuf, sizeof( pcNumberBuf ), "%04X", ( int ) usShortHash );\r
2274                                         }\r
2275                                 }\r
2276                                 #else\r
2277                                 {\r
2278                                         snprintf( pcNumberBuf, sizeof( pcNumberBuf ), "%d", ( int ) xIndex );\r
2279                                 }\r
2280                                 #endif\r
2281 \r
2282                                 NameLen = ( uint16_t ) strlen( pcNumberBuf );\r
2283                                 x = 7 - NameLen;\r
2284                                 if ( x > pxFindParams->ucFirstTilde )\r
2285                                 {\r
2286                                         x = pxFindParams->ucFirstTilde;\r
2287                                 }\r
2288                                 pxFindParams->pcEntryBuffer[ x++ ] = '~';\r
2289                                 for( y = 0; y < NameLen; y++ )\r
2290                                 {\r
2291                                         pxFindParams->pcEntryBuffer[ x + y ] = pcNumberBuf[ y ];\r
2292                                 }\r
2293                         }\r
2294                         memcpy( pcMyShortName, pxFindParams->pcEntryBuffer, 11 );\r
2295                         FF_ProcessShortName( pcMyShortName );\r
2296                         if( FF_ShortNameExists( pxIOManager, pxFindParams->ulDirCluster, pcMyShortName, &xResult ) == pdFALSE )\r
2297                         {\r
2298                                 break;\r
2299                         }\r
2300                         if( xIndex >= FF_MAX_ENTRIES_PER_DIRECTORY )\r
2301                         {\r
2302                                 xResult = ( FF_Error_t ) ( FF_ERR_DIR_DIRECTORY_FULL | FF_CREATESHORTNAME );\r
2303                                 break;\r
2304                         }\r
2305                 }\r
2306                 /* Add a tail and special number until we're happy :D. */\r
2307         }\r
2308 \r
2309         return xResult;\r
2310 }       /* FF_FindShortName () */\r
2311 /*-----------------------------------------------------------*/\r
2312 \r
2313 \r
2314 #if( ffconfigLFN_SUPPORT != 0 )\r
2315         static int8_t FF_CreateLFNEntry( uint8_t *pucEntryBuffer, uint8_t *pcName, UBaseType_t uxNameLength, UBaseType_t uxLFN, uint8_t ucCheckSum )\r
2316         {\r
2317                 /*\r
2318                  *      HT for JW:\r
2319                  *      Changed *pcName from 16- to of 8-bits\r
2320                  *      The caller of this function doesn't need an expensive\r
2321                  *      uint16_t usUtf16Name[ffconfigMAX_FILENAME + 1];\r
2322                  *  in case UNICODE isn't used\r
2323                  *  Also did quite a bit of optimisation here\r
2324                  *  and tested well\r
2325                  */\r
2326                 UBaseType_t uxIndex, x;\r
2327 \r
2328                 memset( pucEntryBuffer, 0, FF_SIZEOF_DIRECTORY_ENTRY );\r
2329 \r
2330                 FF_putChar( pucEntryBuffer, FF_FAT_LFN_ORD, ( uint8_t )( ( uxLFN & ~0x40 ) ) );\r
2331                 FF_putChar( pucEntryBuffer, FF_FAT_DIRENT_ATTRIB, ( uint8_t ) FF_FAT_ATTR_LFN );\r
2332                 FF_putChar( pucEntryBuffer, FF_FAT_LFN_CHECKSUM, ( uint8_t ) ucCheckSum );\r
2333 \r
2334                 /* Name_1. */\r
2335                 uxIndex = 0;\r
2336                 for( x = FF_FAT_LFN_NAME_1; uxIndex < 5u; uxIndex++, x += 2 )\r
2337                 {\r
2338                         if( uxIndex < uxNameLength )\r
2339                         {\r
2340                                 pucEntryBuffer[ x ] = *( pcName++ );\r
2341                                 #if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) || ( ffconfigUNICODE_UTF8_SUPPORT != 0 )\r
2342                                 {\r
2343                                         pucEntryBuffer[ x + 1 ] = *( pcName++ );\r
2344                                 }\r
2345                                 #endif\r
2346                         }\r
2347                         else if ( uxIndex > uxNameLength )\r
2348                         {\r
2349                                 pucEntryBuffer[ x] = 0xFF;\r
2350                                 pucEntryBuffer[ x + 1 ] = 0xFF;\r
2351                         }\r
2352                 }\r
2353 \r
2354                 /* Name_2. */\r
2355                 for( x = FF_FAT_LFN_NAME_2; uxIndex < 11u; uxIndex++, x += 2 )\r
2356                 {\r
2357                         if( uxIndex < uxNameLength )\r
2358                         {\r
2359                                 pucEntryBuffer[ x ] = *( pcName++ );\r
2360                                 #if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) || ( ffconfigUNICODE_UTF8_SUPPORT != 0 )\r
2361                                 {\r
2362                                         pucEntryBuffer[ x + 1 ] = *( pcName++ );\r
2363                                 }\r
2364                                 #endif\r
2365                         }\r
2366                         else if( uxIndex > uxNameLength )\r
2367                         {\r
2368                                 pucEntryBuffer[ x ] = 0xFF;\r
2369                                 pucEntryBuffer[ x + 1 ] = 0xFF;\r
2370                         }\r
2371                 }\r
2372 \r
2373                 /* Name_3. */\r
2374                 for( x = FF_FAT_LFN_NAME_3; uxIndex < 13u; uxIndex++, x += 2 )\r
2375                 {\r
2376                         if( uxIndex < uxNameLength )\r
2377                         {\r
2378                                 pucEntryBuffer[ x ] = *( pcName++ );\r
2379                                 #if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) || ( ffconfigUNICODE_UTF8_SUPPORT != 0 )\r
2380                                 {\r
2381                                         pucEntryBuffer[ x + 1 ] = *( pcName++ );\r
2382                                 }\r
2383                                 #endif\r
2384                         }\r
2385                         else if( uxIndex > uxNameLength )\r
2386                         {\r
2387                                 pucEntryBuffer[ x ] = 0xFF;\r
2388                                 pucEntryBuffer[ x + 1 ] = 0xFF;\r
2389                         }\r
2390                 }\r
2391 \r
2392                 return FF_ERR_NONE;\r
2393         }       /* FF_CreateLFNEntry() */\r
2394 #endif /* ffconfigLFN_SUPPORT */\r
2395 /*-----------------------------------------------------------*/\r
2396 \r
2397 #if( ffconfigLFN_SUPPORT != 0 )\r
2398         #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
2399         static FF_Error_t FF_CreateLFNs( FF_IOManager_t *pxIOManager, uint32_t ulDirCluster, FF_T_WCHAR *pcName, uint8_t ucCheckSum, uint16_t usEntry )\r
2400         #else\r
2401         static FF_Error_t FF_CreateLFNs( FF_IOManager_t *pxIOManager, uint32_t ulDirCluster, char *pcName, uint8_t ucCheckSum, uint16_t usEntry )\r
2402         #endif\r
2403         {\r
2404         FF_Error_t xError = FF_ERR_NONE;\r
2405         BaseType_t xNumLFNs;\r
2406         BaseType_t xEndPos;\r
2407         BaseType_t xIndex, y;\r
2408         FF_FetchContext_t xFetchContext;\r
2409         uint8_t pucEntryBuffer[ FF_SIZEOF_DIRECTORY_ENTRY ];\r
2410 \r
2411         #if ( ffconfigUNICODE_UTF8_SUPPORT != 0 )\r
2412                 int32_t slRetVal;\r
2413         #endif\r
2414 \r
2415         #if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) || ( ffconfigUNICODE_UTF8_SUPPORT != 0 )\r
2416                 uint16_t usUtf16Name[ ffconfigMAX_FILENAME + 1 ];\r
2417         #endif\r
2418 \r
2419         #if( ffconfigUNICODE_UTF16_SUPPORT == 0 )\r
2420                 char *NamePtr;\r
2421         #else\r
2422                 int16_t *NamePtr;\r
2423         #endif\r
2424 \r
2425 \r
2426                 #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
2427                 {\r
2428                         #if WCHAR_MAX <= 0xFFFF\r
2429                         {\r
2430                                 y = wcslen( pcName );\r
2431                                 if( y > ffconfigMAX_FILENAME )\r
2432                                 {\r
2433                                         xError = ( FF_Error_t ) ( FF_ERR_DIR_NAME_TOO_LONG | FF_CREATELFNS );\r
2434                                 }\r
2435                                 else\r
2436                                 {\r
2437                                         wcsncpy( usUtf16Name, pcName, ffconfigMAX_FILENAME );\r
2438                                 }\r
2439                         }\r
2440                         #else\r
2441                         {\r
2442                                 xIndex = 0;\r
2443                                 y = 0;\r
2444                                 while( pcName[ xIndex ] )\r
2445                                 {\r
2446                                         FF_Utf32ctoUtf16c( &usUtf16Name[ y ], ( uint32_t ) pcName[xIndex], ffconfigMAX_FILENAME - xIndex );\r
2447                                         y += FF_GetUtf16SequenceLen( usUtf16Name[ y ] );\r
2448                                         xIndex++;\r
2449                                         if( y > ffconfigMAX_FILENAME )\r
2450                                         {\r
2451                                                 xError = ( FF_Error_t ) ( FF_ERR_DIR_NAME_TOO_LONG | FF_CREATELFNS );\r
2452                                                 break;\r
2453                                         }\r
2454                                 }\r
2455                         }\r
2456                         #endif\r
2457                 }\r
2458                 #endif /* ffconfigUNICODE_UTF16_SUPPORT */\r
2459 \r
2460                 /* Convert the name into UTF-16 format. */\r
2461                 #if ( ffconfigUNICODE_UTF8_SUPPORT != 0 )\r
2462                 {\r
2463                         /* Simply convert the UTF8 to UTF16 and be done with it. */\r
2464                         xIndex = 0;\r
2465                         y = 0;\r
2466                         while( pcName[ xIndex ] != 0 )\r
2467                         {\r
2468                                 slRetVal = FF_Utf8ctoUtf16c( &( usUtf16Name[ y ] ), ( uint8_t * )&( pcName[ xIndex ] ), ffconfigMAX_FILENAME - xIndex );\r
2469                                 if( slRetVal > 0 )\r
2470                                 {\r
2471                                         xIndex += slRetVal;\r
2472                                 }\r
2473                                 else\r
2474                                 {\r
2475                                         break;  /* No more space in the UTF-16 buffer, simply truncate for safety. */\r
2476                                 }\r
2477                                 y += FF_GetUtf16SequenceLen( usUtf16Name[ y ] );\r
2478                                 if( y > ffconfigMAX_FILENAME )\r
2479                                 {\r
2480                                         xError = ( FF_Error_t ) ( FF_ERR_DIR_NAME_TOO_LONG | FF_CREATELFNS );\r
2481                                         break;\r
2482                                 }\r
2483                         }\r
2484                 }\r
2485                 #elif ( ffconfigUNICODE_UTF16_SUPPORT == 0 )\r
2486                 {\r
2487                         /* Just check the length. */\r
2488                         y = strlen( pcName );\r
2489                         if( y > ffconfigMAX_FILENAME )\r
2490                         {\r
2491                                 xError = ( FF_Error_t ) ( FF_ERR_DIR_NAME_TOO_LONG | FF_CREATELFNS );\r
2492                         }\r
2493                 }\r
2494                 #endif\r
2495 \r
2496                 /* Whole name is now in a valid UTF-16 format. Lets go make thos LFN's.\r
2497                 At this point, it should a be the length of the name. */\r
2498                 if( FF_isERR( xError ) == pdFALSE )\r
2499                 {\r
2500                         xNumLFNs        = y / 13;       /* Number of LFNs is the total number of UTF-16 units, divided by 13 ( 13 units per LFN ). */\r
2501                         xEndPos = y % 13;       /* The ending position in an LFN, of the last LFN UTF-16 character. */\r
2502 \r
2503                         if( xEndPos )\r
2504                         {\r
2505                                 xNumLFNs++;\r
2506                         }\r
2507                         else\r
2508                         {\r
2509                                 xEndPos = 13;\r
2510                         }\r
2511 \r
2512                         xError = FF_InitEntryFetch( pxIOManager, ulDirCluster, &xFetchContext );\r
2513                         if( FF_isERR( xError ) == pdFALSE )\r
2514                         {\r
2515                                 #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
2516                                 {\r
2517                                         NamePtr = ( int16_t * ) ( usUtf16Name + 13 * ( xNumLFNs - 1 ) );\r
2518                                 }\r
2519                                 #elif ( ffconfigUNICODE_UTF8_SUPPORT != 0 )\r
2520                                 {\r
2521                                         NamePtr = ( int8_t * ) ( usUtf16Name + 13 * ( xNumLFNs - 1 ) );\r
2522                                 }\r
2523                                 #else\r
2524                                 {\r
2525                                         NamePtr = pcName + 13 * ( xNumLFNs - 1 );\r
2526                                 }\r
2527                                 #endif\r
2528                                 /* After this point, xIndex is no longer the length of the Filename in UTF-16 units. */\r
2529                                 for( xIndex = xNumLFNs; xIndex > 0; xIndex-- )\r
2530                                 {\r
2531                                         if( xIndex == xNumLFNs )\r
2532                                         {\r
2533                                                 FF_CreateLFNEntry( pucEntryBuffer, ( uint8_t * ) NamePtr, ( UBaseType_t ) xEndPos, ( UBaseType_t ) xIndex, ucCheckSum );\r
2534                                                 pucEntryBuffer[0] |= 0x40;\r
2535                                         }\r
2536                                         else\r
2537                                         {\r
2538                                                 FF_CreateLFNEntry( pucEntryBuffer, ( uint8_t * ) NamePtr, ( UBaseType_t ) 13u, ( UBaseType_t ) xIndex, ucCheckSum );\r
2539                                         }\r
2540                                         NamePtr -= 13;\r
2541 \r
2542                                         xError = FF_PushEntryWithContext( pxIOManager, ( uint32_t ) ( usEntry + ( xNumLFNs - xIndex ) ), &xFetchContext, pucEntryBuffer );\r
2543                                         if( FF_isERR( xError ) )\r
2544                                         {\r
2545                                                 break;\r
2546                                         }\r
2547                                 }\r
2548 \r
2549                                 {\r
2550                                 FF_Error_t xTempError;\r
2551 \r
2552                                         /* Release any buffers that were used. */\r
2553                                         xTempError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext );\r
2554                                         if( FF_isERR( xTempError ) == pdFALSE )\r
2555                                         {\r
2556                                                 xError = xTempError;\r
2557                                         }\r
2558                                 }\r
2559                         }\r
2560                 }\r
2561 \r
2562                 return xError;\r
2563         }       /* FF_CreateLFNs() */\r
2564 #endif /* ffconfigLFN_SUPPORT */\r
2565 /*-----------------------------------------------------------*/\r
2566 \r
2567 FF_Error_t FF_ExtendDirectory( FF_IOManager_t *pxIOManager, uint32_t ulDirCluster )\r
2568 {\r
2569 uint32_t xCurrentCluster;\r
2570 uint32_t xNextCluster = 0UL;\r
2571 FF_Error_t xError = FF_ERR_NONE;\r
2572 FF_FATBuffers_t xFATBuffers;\r
2573 \r
2574         if( ( ulDirCluster == pxIOManager->xPartition.ulRootDirCluster ) &&\r
2575                 ( pxIOManager->xPartition.ucType != FF_T_FAT32 ) )\r
2576         {\r
2577                 /* root directories on FAT12 and FAT16 can not be extended. */\r
2578                 xError = ( FF_Error_t ) ( FF_ERR_DIR_CANT_EXTEND_ROOT_DIR | FF_EXTENDDIRECTORY );\r
2579         }\r
2580         else if( pxIOManager->xPartition.ulFreeClusterCount == 0UL )\r
2581         {\r
2582                 /* The number of free clusters was not yet calculated or equal to zero. */\r
2583                 pxIOManager->xPartition.ulFreeClusterCount = FF_CountFreeClusters( pxIOManager, &xError );\r
2584         }\r
2585 \r
2586         if( FF_isERR( xError ) == pdFALSE )\r
2587         {\r
2588                 if( pxIOManager->xPartition.ulFreeClusterCount == 0UL )\r
2589                 {\r
2590                         xError = ( FF_Error_t ) ( FF_ERR_FAT_NO_FREE_CLUSTERS | FF_EXTENDDIRECTORY );\r
2591                 }\r
2592                 else\r
2593                 {\r
2594                         FF_LockFAT( pxIOManager );\r
2595                         {\r
2596                                 xCurrentCluster = FF_FindEndOfChain( pxIOManager, ulDirCluster, &xError );\r
2597                                 if( FF_isERR( xError ) == pdFALSE )\r
2598                                 {\r
2599                                         xNextCluster = FF_FindFreeCluster( pxIOManager, &xError, pdTRUE );\r
2600                                         if( FF_isERR( xError ) == pdFALSE )\r
2601                                         {\r
2602                                                 FF_InitFATBuffers ( &xFATBuffers, FF_MODE_WRITE );\r
2603                                                 /* xNextCluster already has been set to 0xFFFFFFFF,\r
2604                                                 now let xCurrentCluster point to xNextCluster. */\r
2605 \r
2606                                                 xError = FF_putFATEntry( pxIOManager, xCurrentCluster, xNextCluster, &xFATBuffers );\r
2607                                                 {\r
2608                                                 FF_Error_t xTempError;\r
2609 \r
2610                                                         xTempError = FF_ReleaseFATBuffers( pxIOManager, &xFATBuffers );\r
2611                                                         if( FF_isERR( xError ) == pdFALSE )\r
2612                                                         {\r
2613                                                                 xError = xTempError;\r
2614                                                         }\r
2615 \r
2616                                                         xTempError = FF_DecreaseFreeClusters( pxIOManager, 1 );\r
2617                                                         if( FF_isERR( xError ) == pdFALSE )\r
2618                                                         {\r
2619                                                                 xError = xTempError;\r
2620                                                         }\r
2621                                                 }\r
2622                                         }\r
2623                                 }\r
2624                         }\r
2625                         FF_UnlockFAT( pxIOManager );\r
2626 \r
2627                         if( FF_isERR( xError ) == pdFALSE )\r
2628                         {\r
2629                                 /* The entire cluster will be filled with zero's,\r
2630                                 because it will contain directory data. */\r
2631                                 xError = FF_ClearCluster( pxIOManager, xNextCluster );\r
2632                         }\r
2633                 }\r
2634         }\r
2635 \r
2636         return xError;\r
2637 }       /* FF_ExtendDirectory() */\r
2638 /*-----------------------------------------------------------*/\r
2639 \r
2640 static const uint8_t forbiddenChrs[] =\r
2641 {\r
2642 /* Windows says: don't use these characters: '\/:*?"<>|'\r
2643     "     *     /           :     <     >     ?    '\'    ?     | */\r
2644         0x22, 0x2A, 0x2F, 0x3A, 0x3C, 0x3E, 0x3F, 0x5C, 0x7F, 0x7C\r
2645 };\r
2646 \r
2647 #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
2648 static void FF_MakeNameCompliant( FF_T_WCHAR *pcName )\r
2649 #else\r
2650 static void FF_MakeNameCompliant( char *pcName )\r
2651 #endif\r
2652 {\r
2653         BaseType_t index;\r
2654         if( ( uint8_t ) pcName[ 0 ] == FF_FAT_DELETED ) /* Support Japanese KANJI symbol0xE5. */\r
2655         {\r
2656                 pcName[ 0 ] = 0x05;\r
2657         }\r
2658         for( ; *pcName; pcName++ )\r
2659         {\r
2660                 for( index = 0; index < ( BaseType_t ) sizeof( forbiddenChrs ); index++ )\r
2661                 {\r
2662                         if( *pcName == forbiddenChrs[index] )\r
2663                         {\r
2664                                 *pcName = '_';\r
2665                                 break;\r
2666                         }\r
2667                 }\r
2668         }\r
2669 }       /* FF_MakeNameCompliant() */\r
2670 /*-----------------------------------------------------------*/\r
2671 \r
2672 FF_Error_t FF_CreateDirent( FF_IOManager_t *pxIOManager, FF_FindParams_t *pxFindParams, FF_DirEnt_t *pxDirEntry )\r
2673 {\r
2674 uint8_t pucEntryBuffer[ FF_SIZEOF_DIRECTORY_ENTRY ];\r
2675 \r
2676 BaseType_t xLFNCount;\r
2677 int32_t lFreeEntry = 0L;\r
2678 FF_Error_t xReturn = FF_ERR_NONE;\r
2679 BaseType_t xEntryCount;\r
2680 FF_FetchContext_t xFetchContext;\r
2681 uint32_t        ulDirCluster = pxFindParams->ulDirCluster;\r
2682 int32_t lFitShort;\r
2683 \r
2684 #if( ffconfigHASH_CACHE != 0 )\r
2685         char pcShortName[ 13 ];\r
2686 #endif\r
2687 #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
2688         uint16_t NameLen = ( uint16_t ) wcslen( pxDirEntry->pcFileName );\r
2689 #else\r
2690         uint16_t NameLen = ( uint16_t ) strlen( pxDirEntry->pcFileName );\r
2691 #endif\r
2692 \r
2693 #if( ffconfigLFN_SUPPORT != 0 )\r
2694         uint8_t ucCheckSum;\r
2695 #endif\r
2696 \r
2697         /* Round-up the number of LFN's needed: */\r
2698         xLFNCount = ( BaseType_t ) ( ( NameLen + 12 ) / 13 );\r
2699 \r
2700         #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
2701         {\r
2702                 FF_MakeNameCompliant( pxDirEntry->pcFileName ); /* Ensure we don't break the Dir tables. */\r
2703         }\r
2704         #else\r
2705         {\r
2706                 FF_MakeNameCompliant( pxDirEntry->pcFileName ); /* Ensure we don't break the Dir tables. */\r
2707         }\r
2708         #endif\r
2709         memset( pucEntryBuffer, 0, sizeof( pucEntryBuffer ) );\r
2710 \r
2711         #if( ffconfigLFN_SUPPORT != 0 )\r
2712         {\r
2713                 /* Create and push the LFN's. */\r
2714                 /* Find enough places for the LFNs and the ShortName. */\r
2715                 xEntryCount = xLFNCount + 1;\r
2716         }\r
2717         #else\r
2718         {\r
2719                 xEntryCount = 1;\r
2720         }\r
2721         #endif\r
2722 \r
2723         /* Create the ShortName. */\r
2724         FF_LockDirectory( pxIOManager );\r
2725         do\r
2726         {\r
2727                 /* Open a do {} while( pdFALSE ) loop to allow the use of break statements. */\r
2728                 /* As FF_FindShortName( ) can fail, it should be called before finding a free directory entry. */\r
2729                 if( ( pxFindParams->ulFlags & FIND_FLAG_SHORTNAME_SET ) == 0 )\r
2730                 {\r
2731                         FF_CreateShortName( pxFindParams, pxDirEntry->pcFileName );\r
2732                 }\r
2733                 lFitShort = FF_FindShortName ( pxIOManager, pxFindParams );\r
2734 \r
2735                 memcpy( pucEntryBuffer, pxFindParams->pcEntryBuffer, sizeof( pucEntryBuffer ) );\r
2736 \r
2737                 if( FF_isERR( lFitShort ) )\r
2738                 {\r
2739                         xReturn = lFitShort;\r
2740                         break;\r
2741                 }\r
2742                 if( lFitShort != 0 )\r
2743                 {\r
2744                         /* There is no need to create a LFN entry because the file name\r
2745                         fits into a normal 32-byte entry.. */\r
2746                         xLFNCount = 0;\r
2747                         xEntryCount = 1;\r
2748                 }\r
2749                 lFreeEntry = FF_FindFreeDirent( pxIOManager, pxFindParams, ( uint16_t ) xEntryCount );\r
2750 \r
2751                 if( FF_isERR( lFreeEntry ) )\r
2752                 {\r
2753                         xReturn = lFreeEntry;\r
2754                         break;\r
2755                 }\r
2756                 #if( ffconfigLFN_SUPPORT != 0 )\r
2757                 {\r
2758                         if( xLFNCount > 0 )\r
2759                         {\r
2760                                 ucCheckSum = FF_CreateChkSum( pucEntryBuffer );\r
2761                                 xReturn = FF_CreateLFNs( pxIOManager, ulDirCluster, pxDirEntry->pcFileName, ucCheckSum, ( uint16_t ) lFreeEntry );\r
2762                         }\r
2763                 }\r
2764                 #else\r
2765                 {\r
2766                         xLFNCount = 0;\r
2767                 }\r
2768                 #endif /* ffconfigLFN_SUPPORT */\r
2769                 if( FF_isERR( xReturn ) == pdFALSE )\r
2770                 {\r
2771                         #if( ffconfigTIME_SUPPORT != 0 )\r
2772                         {\r
2773                                 FF_GetSystemTime( &pxDirEntry->xCreateTime );           /* Date and Time Created. */\r
2774                                 pxDirEntry->xModifiedTime = pxDirEntry->xCreateTime;    /* Date and Time Modified. */\r
2775                                 pxDirEntry->xAccessedTime = pxDirEntry->xCreateTime;    /* Date of Last Access. */\r
2776                                 FF_PlaceTime( pucEntryBuffer, FF_FAT_DIRENT_CREATE_TIME, &pxDirEntry->xCreateTime );\r
2777                                 FF_PlaceDate( pucEntryBuffer, FF_FAT_DIRENT_CREATE_DATE, &pxDirEntry->xCreateTime );\r
2778                                 FF_PlaceTime( pucEntryBuffer, FF_FAT_DIRENT_LASTMOD_TIME, &pxDirEntry->xModifiedTime );\r
2779                                 FF_PlaceDate( pucEntryBuffer, FF_FAT_DIRENT_LASTMOD_DATE, &pxDirEntry->xModifiedTime );\r
2780                         }\r
2781                         #endif /*  ffconfigTIME_SUPPORT */\r
2782 \r
2783                         FF_putChar( pucEntryBuffer,  FF_FAT_DIRENT_ATTRIB, pxDirEntry->ucAttrib );\r
2784                 #if( ffconfigSHORTNAME_CASE != 0 )\r
2785                         FF_putChar( pucEntryBuffer,  FF_FAT_CASE_OFFS, ( uint32_t ) lFitShort & ( FF_FAT_CASE_ATTR_BASE | FF_FAT_CASE_ATTR_EXT ) );\r
2786                 #endif\r
2787                         FF_putShort( pucEntryBuffer, FF_FAT_DIRENT_CLUS_HIGH, ( uint16_t )( pxDirEntry->ulObjectCluster >> 16 ) );\r
2788                         FF_putShort( pucEntryBuffer, FF_FAT_DIRENT_CLUS_LOW, ( uint16_t )( pxDirEntry->ulObjectCluster ) );\r
2789                         FF_putLong( pucEntryBuffer,  FF_FAT_DIRENT_FILESIZE, pxDirEntry->ulFileSize );\r
2790 \r
2791                         xReturn = FF_InitEntryFetch( pxIOManager, ulDirCluster, &xFetchContext );\r
2792                         if( FF_isERR( xReturn ) )\r
2793                         {\r
2794                                 break;\r
2795                         }\r
2796                         xReturn = FF_PushEntryWithContext( pxIOManager, ( uint16_t ) ( lFreeEntry + xLFNCount ), &xFetchContext, pucEntryBuffer );\r
2797 \r
2798                         {\r
2799                         FF_Error_t xTempError;\r
2800 \r
2801                                 xTempError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext );\r
2802                                 if( FF_isERR( xReturn ) == pdFALSE )\r
2803                                 {\r
2804                                         xReturn = xTempError;\r
2805                                 }\r
2806                         }\r
2807                         if( FF_isERR( xReturn ) )\r
2808                         {\r
2809                                 break;\r
2810                         }\r
2811 \r
2812                         #if( ffconfigHASH_CACHE != 0 )\r
2813                         {\r
2814                                 if( FF_DirHashed( pxIOManager, ulDirCluster ) == pdFALSE )\r
2815                                 {\r
2816                                         /* Hash the directory. */\r
2817                                         FF_HashDir( pxIOManager, ulDirCluster );\r
2818                                 }\r
2819                                 memcpy( pcShortName, pucEntryBuffer, 11 );\r
2820                                 FF_ProcessShortName( pcShortName );             /* Format the shortname to 8.3. */\r
2821                                 #if( ffconfigHASH_FUNCTION == CRC16 )\r
2822                                 {\r
2823                                         FF_AddDirentHash( pxIOManager, ulDirCluster, ( uint32_t )FF_GetCRC16( ( uint8_t * ) pcShortName, strlen( pcShortName ) ) );\r
2824                                 }\r
2825                                 #elif( ffconfigHASH_FUNCTION == CRC8 )\r
2826                                 {\r
2827                                         FF_AddDirentHash( pxIOManager, ulDirCluster, ( uint32_t )FF_GetCRC8( ( uint8_t * ) pcShortName, strlen( pcShortName ) ) );\r
2828                                 }\r
2829                                 #endif /* ffconfigHASH_FUNCTION */\r
2830                         }\r
2831                         #endif /* ffconfigHASH_CACHE*/\r
2832                 }\r
2833         }\r
2834         while( pdFALSE );\r
2835 \r
2836         FF_UnlockDirectory( pxIOManager );\r
2837 \r
2838         if( FF_isERR( xReturn ) == pdFALSE )\r
2839         {\r
2840                 if( pxDirEntry != NULL )\r
2841                 {\r
2842                         pxDirEntry->usCurrentItem = ( uint16_t )( lFreeEntry + xLFNCount );\r
2843                 }\r
2844         }\r
2845 \r
2846         return xReturn;\r
2847 }       /* FF_CreateDirent() */\r
2848 /*-----------------------------------------------------------*/\r
2849 \r
2850 \r
2851 #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
2852 uint32_t FF_CreateFile( FF_IOManager_t *pxIOManager, FF_FindParams_t *pxFindParams, FF_T_WCHAR *pcFileName, FF_DirEnt_t *pxDirEntry, FF_Error_t *pxError )\r
2853 #else\r
2854 uint32_t FF_CreateFile( FF_IOManager_t *pxIOManager, FF_FindParams_t *pxFindParams, char *pcFileName, FF_DirEnt_t *pxDirEntry, FF_Error_t *pxError )\r
2855 #endif\r
2856 {\r
2857 FF_DirEnt_t xMyFile;\r
2858 FF_Error_t xTempError, xError = FF_ERR_NONE;\r
2859 uint32_t ulResult;\r
2860 \r
2861         memset ( &xMyFile, '\0', sizeof( xMyFile ) );\r
2862 \r
2863         #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
2864         {\r
2865                 wcsncpy( xMyFile.pcFileName, pcFileName, ffconfigMAX_FILENAME );\r
2866         }\r
2867         #else\r
2868         {\r
2869                 strncpy( xMyFile.pcFileName, pcFileName, ffconfigMAX_FILENAME );\r
2870         }\r
2871         #endif\r
2872 \r
2873         xMyFile.ulObjectCluster = FF_CreateClusterChain( pxIOManager, &xError );\r
2874 \r
2875         if( FF_isERR( xError ) == pdFALSE )\r
2876         {\r
2877                 xError = FF_CreateDirent( pxIOManager, pxFindParams, &xMyFile );\r
2878                 if( FF_isERR( xError ) == pdFALSE )\r
2879                 {\r
2880                         /* The new file now has a cluster chain and it has an entry\r
2881                         in its directory.  Copy data to a pointer provided by caller: */\r
2882                         if( pxDirEntry != NULL )\r
2883                         {\r
2884                                 memcpy( pxDirEntry, &xMyFile, sizeof( FF_DirEnt_t ) );\r
2885                         }\r
2886                 }\r
2887                 else\r
2888                 {\r
2889                         /* An error occurred in FF_CreateDirent().\r
2890                         Unlink the file's cluster chain: */\r
2891                         FF_LockFAT( pxIOManager );\r
2892                         {\r
2893                                 FF_UnlinkClusterChain( pxIOManager, xMyFile.ulObjectCluster, 0 );\r
2894                                 xMyFile.ulObjectCluster = 0ul;\r
2895                         }\r
2896                         FF_UnlockFAT( pxIOManager );\r
2897                 }\r
2898                 /* Now flush all buffers to disk. */\r
2899                 xTempError = FF_FlushCache( pxIOManager );\r
2900                 if( FF_isERR( xError ) == pdFALSE )\r
2901                 {\r
2902                         xError = xTempError;\r
2903                 }\r
2904         }\r
2905 \r
2906         *pxError = xError;\r
2907 \r
2908         if( FF_isERR( xError ) == pdFALSE )\r
2909         {\r
2910                 ulResult = xMyFile.ulObjectCluster;\r
2911         }\r
2912         else\r
2913         {\r
2914                 ulResult = 0;\r
2915         }\r
2916 \r
2917         return ulResult;\r
2918 }       /* FF_CreateFile() */\r
2919 /*-----------------------------------------------------------*/\r
2920 \r
2921 \r
2922 /**\r
2923  *      @brief Creates a Directory of the specified path.\r
2924  *\r
2925  *      @param  pxIOManager     Pointer to the FF_IOManager_t object.\r
2926  *      @param  pcPath  Path of the directory to create.\r
2927  *\r
2928  *      @Return FF_ERR_NULL_POINTER if pxIOManager was NULL.\r
2929  *      @Return FF_ERR_DIR_OBJECT_EXISTS if the object specified by path already exists.\r
2930  *      @Return FF_ERR_DIR_INVALID_PATH\r
2931  *      @Return FF_ERR_NONE on success.\r
2932  **/\r
2933 #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
2934 FF_Error_t FF_MkDir( FF_IOManager_t *pxIOManager, const FF_T_WCHAR *pcPath )\r
2935 #else\r
2936 FF_Error_t FF_MkDir( FF_IOManager_t *pxIOManager, const char *pcPath )\r
2937 #endif\r
2938 {\r
2939 FF_DirEnt_t     xMyDirectory;\r
2940 \r
2941 #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
2942         const FF_T_WCHAR *pcDirName;\r
2943 #else\r
2944         const char      *pcDirName;\r
2945 #endif\r
2946 uint8_t pucEntryBuffer[ FF_SIZEOF_DIRECTORY_ENTRY ];\r
2947 uint32_t ulObjectCluster;\r
2948 BaseType_t xIndex;\r
2949 FF_Error_t xError = FF_ERR_NONE;\r
2950 \r
2951 FF_FindParams_t xFindParams;\r
2952 \r
2953         memset ( &xFindParams, '\0', sizeof( xFindParams ) );\r
2954         /* Inform the functions that the entry will be created if not found */\r
2955         xFindParams.ulFlags |= FIND_FLAG_CREATE_FLAG;\r
2956 \r
2957         /* Open a do {} while ( pdFALSE ) loop */\r
2958         do\r
2959         {\r
2960                 if( pxIOManager == NULL )\r
2961                 {\r
2962                         xError = ( FF_Error_t ) ( FF_ERR_NULL_POINTER | FF_MKDIR );\r
2963                         break;\r
2964                 }\r
2965 #if( ffconfigREMOVABLE_MEDIA != 0 )\r
2966                 if( ( pxIOManager->ucFlags & FF_IOMAN_DEVICE_IS_EXTRACTED ) != 0 )\r
2967                 {\r
2968                         xError = ( FF_Error_t ) ( FF_ERR_IOMAN_DRIVER_NOMEDIUM | FF_MKDIR );\r
2969                         break;\r
2970                 }\r
2971 #endif /* ffconfigREMOVABLE_MEDIA */\r
2972 \r
2973                 #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
2974                 {\r
2975                         xIndex = ( BaseType_t ) wcslen( pcPath );\r
2976                 }\r
2977                 #else\r
2978                 {\r
2979                         xIndex = ( BaseType_t ) strlen( pcPath );\r
2980                 }\r
2981                 #endif\r
2982 \r
2983                 /* Find the last slash in the path. */\r
2984                 while( xIndex != 0 )\r
2985                 {\r
2986                         if( ( pcPath[ xIndex ] == '\\' ) || ( pcPath[ xIndex ] == '/' ) )\r
2987                         {\r
2988                                 break;\r
2989                         }\r
2990                         xIndex--;\r
2991                 }\r
2992 \r
2993                 pcDirName = pcPath + xIndex + 1;\r
2994 \r
2995                 if( xIndex == 0 )\r
2996                 {\r
2997                         xIndex = 1;\r
2998                 }\r
2999 \r
3000                 if( pcDirName[ 0 ] == '\0' )\r
3001                 {\r
3002                         xError = ( FF_ERR_DIR_OBJECT_EXISTS | FF_MKDIR );\r
3003                         break;\r
3004                 }\r
3005 \r
3006                 xFindParams.ulDirCluster = FF_FindDir( pxIOManager, pcPath, ( uint16_t ) xIndex, &xError );\r
3007 \r
3008                 if( FF_isERR( xError ) )\r
3009                 {\r
3010                         break;\r
3011                 }\r
3012 \r
3013                 if( xFindParams.ulDirCluster == 0UL )\r
3014                 {\r
3015                         xError = ( FF_Error_t ) ( FF_ERR_DIR_INVALID_PATH | FF_MKDIR );\r
3016                         break;\r
3017                 }\r
3018                 memset( &xMyDirectory, '\0', sizeof( xMyDirectory ) );\r
3019 \r
3020                 /* Will set flags FIND_FLAG_FITS_SHORT and FIND_FLAG_SIZE_OK */\r
3021                 FF_CreateShortName( &xFindParams, pcDirName );\r
3022 \r
3023                 if( FF_FindEntryInDir( pxIOManager, &xFindParams, pcDirName, 0x00, &xMyDirectory, &xError ) )\r
3024                 {\r
3025                         if( FF_isERR( xError ) == pdFALSE )\r
3026                         {\r
3027                                 xError = ( FF_Error_t ) ( FF_ERR_DIR_OBJECT_EXISTS | FF_MKDIR );\r
3028                         }\r
3029                         break;\r
3030                 }\r
3031 \r
3032                 if( ( FF_isERR( xError ) ) && ( FF_GETERROR( xError ) != FF_ERR_DIR_END_OF_DIR ) )\r
3033                 {\r
3034                         break;\r
3035                 }\r
3036 \r
3037                 #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
3038                 {\r
3039                         wcsncpy( xMyDirectory.pcFileName, pcDirName, ffconfigMAX_FILENAME );\r
3040                 }\r
3041                 #else\r
3042                 {\r
3043                         strncpy( xMyDirectory.pcFileName, pcDirName, ffconfigMAX_FILENAME );\r
3044                 }\r
3045                 #endif\r
3046 \r
3047                 xMyDirectory.ulFileSize = 0;\r
3048                 xMyDirectory.ucAttrib = FF_FAT_ATTR_DIR;\r
3049                 xMyDirectory.ulObjectCluster = FF_CreateClusterChain( pxIOManager, &xError );\r
3050 \r
3051                 /* Give all entries a proper time stamp, looks nicer than 1 Jan 1970 */\r
3052                 #if( ffconfigTIME_SUPPORT != 0 )\r
3053                 {\r
3054                         FF_GetSystemTime( &xMyDirectory.xCreateTime );\r
3055                         FF_GetSystemTime( &xMyDirectory.xModifiedTime );\r
3056                 }\r
3057                 #endif\r
3058 \r
3059                 if( FF_isERR( xError ) )\r
3060                 {\r
3061                         break;\r
3062                 }\r
3063                 if( xMyDirectory.ulObjectCluster == 0UL )\r
3064                 {\r
3065                         /* Couldn't allocate any space for the dir! */\r
3066                         xError = ( FF_Error_t ) ( FF_ERR_DIR_EXTEND_FAILED | FF_MKDIR );\r
3067                         break;\r
3068                 }\r
3069 \r
3070                 xError = FF_ClearCluster( pxIOManager, xMyDirectory.ulObjectCluster );\r
3071                 if( FF_isERR( xError ) == pdFALSE )\r
3072                 {\r
3073                         xError = FF_CreateDirent( pxIOManager, &xFindParams, &xMyDirectory );\r
3074                 }\r
3075 \r
3076                 if( FF_isERR( xError ) )\r
3077                 {\r
3078                         FF_LockFAT( pxIOManager );\r
3079                         {\r
3080                                 FF_UnlinkClusterChain( pxIOManager, xMyDirectory.ulObjectCluster, 0 );\r
3081                         }\r
3082                         FF_UnlockFAT( pxIOManager );\r
3083                         FF_FlushCache( pxIOManager );   /* Don't override error. */\r
3084                         break;\r
3085                 }\r
3086 \r
3087                 /* Write 8.3 entry "." */\r
3088                 pucEntryBuffer[ 0 ] = '.';\r
3089                 /* folowed by 10 spaces: */\r
3090                 memset( pucEntryBuffer + 1, ' ', 10 );\r
3091                 /* Clear the rest of the structure. */\r
3092                 memset( pucEntryBuffer + 11, 0, FF_SIZEOF_DIRECTORY_ENTRY - 11 );\r
3093 \r
3094                 ulObjectCluster = xMyDirectory.ulObjectCluster;\r
3095                 xError = FF_PutEntry( pxIOManager, ( uint16_t ) 0u, ulObjectCluster, &xMyDirectory, pucEntryBuffer );\r
3096 \r
3097                 if( FF_isERR( xError ) == pdFALSE )\r
3098                 {\r
3099                         pucEntryBuffer[ 1 ] = '.';\r
3100 \r
3101                         if( xFindParams.ulDirCluster == pxIOManager->xPartition.ulRootDirCluster )\r
3102                         {\r
3103                                 xMyDirectory.ulObjectCluster = 0;\r
3104                         }\r
3105                         else\r
3106                         {\r
3107                                 xMyDirectory.ulObjectCluster = xFindParams.ulDirCluster;\r
3108                         }\r
3109                         xError = FF_PutEntry( pxIOManager, 1u, ulObjectCluster, &xMyDirectory, pucEntryBuffer );\r
3110 \r
3111                         xMyDirectory.ulObjectCluster = ulObjectCluster;\r
3112                 }\r
3113 \r
3114                 if( FF_isERR( xError ) )\r
3115                 {\r
3116                         FF_LockFAT( pxIOManager );\r
3117                         {\r
3118                                 FF_UnlinkClusterChain( pxIOManager, xMyDirectory.ulObjectCluster, 0 );\r
3119                         }\r
3120                         FF_UnlockFAT( pxIOManager );\r
3121                 }\r
3122                 FF_FlushCache( pxIOManager );\r
3123         }\r
3124         while( pdFALSE );\r
3125 \r
3126         return xError;\r
3127 }       /* FF_MkDir() */\r
3128 /*-----------------------------------------------------------*/\r
3129 \r
3130 \r
3131 FF_Error_t FF_RmLFNs( FF_IOManager_t *pxIOManager, uint16_t usDirEntry, FF_FetchContext_t *pxContext )\r
3132 {\r
3133 FF_Error_t xError = FF_ERR_NONE;\r
3134 uint8_t pucEntryBuffer[ FF_SIZEOF_DIRECTORY_ENTRY ];\r
3135 \r
3136         if( usDirEntry != 0 )\r
3137         {\r
3138                 usDirEntry--;\r
3139 \r
3140                 do\r
3141                 {\r
3142                         xError = FF_FetchEntryWithContext( pxIOManager, usDirEntry, pxContext, pucEntryBuffer );\r
3143                         if( FF_isERR( xError ) )\r
3144                         {\r
3145                                 break;\r
3146                         }\r
3147 \r
3148                         if( FF_getChar( pucEntryBuffer, ( uint16_t )( FF_FAT_DIRENT_ATTRIB ) ) == FF_FAT_ATTR_LFN )\r
3149                         {\r
3150                                 FF_putChar( pucEntryBuffer, ( uint16_t ) 0, ( uint8_t ) FF_FAT_DELETED );\r
3151                                 xError = FF_PushEntryWithContext( pxIOManager, usDirEntry, pxContext, pucEntryBuffer );\r
3152                                 if( FF_isERR( xError ) )\r
3153                                 {\r
3154                                         break;\r
3155                                 }\r
3156                         }\r
3157 \r
3158                         if( usDirEntry == 0 )\r
3159                         {\r
3160                                 break;\r
3161                         }\r
3162                         usDirEntry--;\r
3163                 } while( FF_getChar( pucEntryBuffer, ( uint16_t )( FF_FAT_DIRENT_ATTRIB ) ) == FF_FAT_ATTR_LFN );\r
3164         }\r
3165 \r
3166         return xError;\r
3167 }       /* FF_RmLFNs() */\r
3168 /*-----------------------------------------------------------*/\r
3169 \r
3170 #if( ffconfigHASH_CACHE != 0 )\r
3171         FF_Error_t FF_HashDir( FF_IOManager_t *pxIOManager, uint32_t ulDirCluster )\r
3172         {\r
3173                 /* Find most suitable Hash Table to replace! */\r
3174         BaseType_t xIndex;\r
3175         FF_HashTable_t *pxHashCache = NULL;\r
3176         FF_FetchContext_t xFetchContext;\r
3177         const uint8_t *pucEntryBuffer = NULL;\r
3178         uint8_t ucAttrib;\r
3179         uint32_t ulHash;\r
3180         FF_Error_t xError;\r
3181 \r
3182                 for( xIndex = 0; xIndex < ffconfigHASH_CACHE_DEPTH; xIndex++ )\r
3183                 {\r
3184                         if( pxIOManager->xHashCache[ xIndex ].ulNumHandles == 0 )\r
3185                         {\r
3186                                 if( pxHashCache == NULL )\r
3187                                 {\r
3188                                         pxHashCache = &pxIOManager->xHashCache[ xIndex ];\r
3189                                 }\r
3190                                 else\r
3191                                 {\r
3192                                         if( ( pxIOManager->xHashCache[ xIndex ].ulMisses > pxHashCache->ulMisses ) )\r
3193                                         {\r
3194                                                 pxHashCache = &pxIOManager->xHashCache[ xIndex ];\r
3195                                         }\r
3196                                 }\r
3197                         }\r
3198                 }\r
3199 \r
3200                 if( pxHashCache != NULL )\r
3201                 {\r
3202                 #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
3203                         FF_T_WCHAR      pcMyShortName[ 13 ];\r
3204                 #else\r
3205                         char pcMyShortName[ 13 ];\r
3206                 #endif\r
3207                         /* Clear the hash table! */\r
3208                         memset( pxHashCache, '\0', sizeof( *pxHashCache ) );\r
3209                         pxHashCache->ulDirCluster = ulDirCluster;\r
3210                         pxHashCache->ulMisses = 0;\r
3211 \r
3212                         /* Hash the directory! */\r
3213 \r
3214                         xError = FF_InitEntryFetch( pxIOManager, ulDirCluster, &xFetchContext );\r
3215 \r
3216                         if( FF_isERR( xError ) == pdFALSE )\r
3217                         {\r
3218                                 for( xIndex = 0; xIndex < FF_MAX_ENTRIES_PER_DIRECTORY; xIndex++ )\r
3219                                 {\r
3220                                         if( ( pucEntryBuffer == NULL ) ||\r
3221                                                 ( pucEntryBuffer >= xFetchContext.pxBuffer->pucBuffer + ( FF_SIZEOF_SECTOR - FF_SIZEOF_DIRECTORY_ENTRY ) ) )\r
3222                                         {\r
3223                                                 xError = FF_FetchEntryWithContext( pxIOManager, ( uint32_t ) xIndex, &xFetchContext, NULL );\r
3224                                                 if( FF_isERR( xError ) )\r
3225                                                 {\r
3226                                                         break;\r
3227                                                 }\r
3228                                                 pucEntryBuffer = xFetchContext.pxBuffer->pucBuffer;\r
3229                                         }\r
3230                                         else\r
3231                                         {\r
3232                                                 /* Advance the pointer 32 bytes to the next directory entry. */\r
3233                                                 pucEntryBuffer += FF_SIZEOF_DIRECTORY_ENTRY;\r
3234                                         }\r
3235                                         if( FF_isDeleted( pucEntryBuffer ) == pdFALSE )\r
3236                                         {\r
3237                                                 ucAttrib = FF_getChar( pucEntryBuffer, FF_FAT_DIRENT_ATTRIB );\r
3238                                                 if( ( ( ucAttrib & FF_FAT_ATTR_LFN ) != FF_FAT_ATTR_LFN ) &&\r
3239                                                         ( ( ucAttrib & FF_FAT_ATTR_VOLID ) != FF_FAT_ATTR_VOLID ) )\r
3240                                                 {\r
3241                                                         memcpy ( pcMyShortName, pucEntryBuffer, 11 );\r
3242                                                         FF_ProcessShortName( pcMyShortName );\r
3243                                                         if( FF_isEndOfDir( pucEntryBuffer ) )\r
3244                                                         {\r
3245                                                                 break;\r
3246                                                         }\r
3247 \r
3248                                                         /* Generate the Hash. */\r
3249                                                         #if( ffconfigHASH_FUNCTION == CRC16 )\r
3250                                                         {\r
3251                                                                 ulHash = FF_GetCRC16( ( uint8_t * ) pcMyShortName, strlen( pcMyShortName ) );\r
3252                                                         }\r
3253                                                         #else /* ffconfigHASH_FUNCTION == CRC8 */\r
3254                                                         {\r
3255                                                                 ulHash = FF_GetCRC8( pcMyShortName, strlen( pcMyShortName ) );\r
3256                                                         }\r
3257                                                         #endif\r
3258                                                         FF_SetHash( pxHashCache, ulHash );\r
3259                                                 }\r
3260                                         }\r
3261                                 } /* for( xIndex = 0; xIndex < FF_MAX_ENTRIES_PER_DIRECTORY; xIndex++ ) */\r
3262                                 {\r
3263                                 FF_Error_t xTempError;\r
3264                                         xTempError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext );\r
3265                                         if( FF_isERR( xError ) == pdFALSE )\r
3266                                         {\r
3267                                                 xError = xTempError;\r
3268                                         }\r
3269                                 }\r
3270                         }\r
3271                 } /* if( pxHashCache != NULL ) */\r
3272                 else\r
3273                 {\r
3274                         xError = -1;\r
3275                 }\r
3276 \r
3277                 return xError;\r
3278         }       /* FF_HashDir() */\r
3279 #endif /* ffconfigHASH_CACHE != 0 */\r
3280 /*-----------------------------------------------------------*/\r
3281 \r
3282 #if( ffconfigHASH_CACHE != 0 )\r
3283         /* FF_UnHashDir() : invalidate the hash tables of a given directory.\r
3284         It is called when a file or sub-directory is removed or when the\r
3285         directory itself is removed. */\r
3286         void FF_UnHashDir( FF_IOManager_t *pxIOManager, uint32_t ulDirCluster )\r
3287         {\r
3288         FF_HashTable_t *pxHash = pxIOManager->xHashCache;\r
3289         FF_HashTable_t *pxLast = pxIOManager->xHashCache + ffconfigHASH_CACHE_DEPTH;\r
3290 \r
3291                 for( ; pxHash < pxLast; pxHash++ )\r
3292                 {\r
3293                         if( pxHash->ulDirCluster == ulDirCluster )\r
3294                         {\r
3295                                 pxHash->ulDirCluster = 0;\r
3296                                 break;\r
3297                         }\r
3298                 }\r
3299         }       /* FF_UnHashDir() */\r
3300 #endif /* ffconfigHASH_CACHE */\r
3301 /*-----------------------------------------------------------*/\r
3302 \r
3303 #if( ffconfigHASH_CACHE != 0 )\r
3304         /**\r
3305          *\r
3306          *\r
3307          **/\r
3308         void FF_SetHash( FF_HashTable_t *pxHash, uint32_t ulHash )\r
3309         {\r
3310         uint32_t tblIndex = ( ulHash / 32 ) % FF_HASH_TABLE_ENTRY_COUNT;\r
3311         uint32_t tblBit = ulHash % 32;\r
3312 \r
3313                 pxHash->ulBitTable[ tblIndex ] |= ( 0x80000000ul >> tblBit );\r
3314         }       /* FF_SetHash() */\r
3315 #endif /* ffconfigHASH_CACHE */\r
3316 /*-----------------------------------------------------------*/\r
3317 \r
3318 #if( ffconfigHASH_CACHE != 0 )\r
3319         void FF_ClearHash( FF_HashTable_t *pxHash, uint32_t ulHash )\r
3320         {\r
3321                 if( pxHash != NULL )\r
3322                 {\r
3323                 uint32_t tblIndex = ( ulHash / 32 ) % FF_HASH_TABLE_ENTRY_COUNT;\r
3324                 uint32_t tblBit = ulHash % 32;\r
3325 \r
3326                         pxHash->ulBitTable[ tblIndex ] &= ~( 0x80000000ul >> tblBit );\r
3327                 }\r
3328         }       /* FF_ClearHash() */\r
3329 #endif /* ffconfigHASH_CACHE */\r
3330 /*-----------------------------------------------------------*/\r
3331 \r
3332 #if( ffconfigHASH_CACHE != 0 )\r
3333         BaseType_t FF_isHashSet( FF_HashTable_t *pxHash, uint32_t ulHash )\r
3334         {\r
3335         FF_Error_t xResult;\r
3336 \r
3337                 xResult = pdFALSE;\r
3338 \r
3339                 if( pxHash != NULL )\r
3340                 {\r
3341                 uint32_t tblIndex = ( ulHash / 32 ) % FF_HASH_TABLE_ENTRY_COUNT;\r
3342                 uint32_t tblBit = ulHash % 32;\r
3343 \r
3344                         if( pxHash->ulBitTable[ tblIndex ] & ( 0x80000000ul >> tblBit ) )\r
3345                         {\r
3346                                 xResult = pdTRUE;\r
3347                         }\r
3348                 }\r
3349 \r
3350                 return xResult;\r
3351         }       /* FF_isHashSet() */\r
3352 #endif /* ffconfigHASH_CACHE */\r
3353 /*-----------------------------------------------------------*/\r
3354 \r
3355 #if( ffconfigHASH_CACHE != 0 )\r
3356         void FF_AddDirentHash( FF_IOManager_t *pxIOManager, uint32_t ulDirCluster, uint32_t ulHash )\r
3357         {\r
3358         FF_HashTable_t *pxHash = pxIOManager->xHashCache;\r
3359         FF_HashTable_t *pxLast = pxIOManager->xHashCache + ffconfigHASH_CACHE_DEPTH;\r
3360 \r
3361                 for( ; pxHash < pxLast; pxHash++ )\r
3362                 {\r
3363                         if( pxHash->ulDirCluster == ulDirCluster )\r
3364                         {\r
3365                                 FF_SetHash( pxHash, ulHash );\r
3366                                 break;\r
3367                         }\r
3368                 }\r
3369         }       /* FF_AddDirentHash() */\r
3370 #endif /* ffconfigHASH_CACHE*/\r
3371 /*-----------------------------------------------------------*/\r
3372 \r
3373 #if( ffconfigHASH_CACHE != 0 )\r
3374         BaseType_t FF_CheckDirentHash( FF_IOManager_t *pxIOManager, uint32_t ulDirCluster, uint32_t ulHash )\r
3375         {\r
3376         FF_HashTable_t *pxHash = pxIOManager->xHashCache;\r
3377         FF_HashTable_t *pxLast = pxIOManager->xHashCache + ffconfigHASH_CACHE_DEPTH;\r
3378         BaseType_t xResult;\r
3379 \r
3380                 for( ; ; )\r
3381                 {\r
3382                         if( pxHash->ulDirCluster == ulDirCluster )\r
3383                         {\r
3384                                 xResult = FF_isHashSet( pxHash, ulHash );\r
3385                                 break;\r
3386                         }\r
3387                         pxHash++;\r
3388                         if( pxHash >= pxLast )\r
3389                         {\r
3390                                 xResult = -1;\r
3391                                 break;\r
3392                         }\r
3393                 }\r
3394 \r
3395                 return xResult;\r
3396         }       /* FF_CheckDirentHash() */\r
3397 #endif /* ffconfigHASH_CACHE */\r
3398 /*-----------------------------------------------------------*/\r
3399 \r
3400 #if( ffconfigHASH_CACHE != 0 )\r
3401         BaseType_t FF_DirHashed( FF_IOManager_t *pxIOManager, uint32_t ulDirCluster )\r
3402         {\r
3403         FF_HashTable_t *pxHash = pxIOManager->xHashCache;\r
3404         FF_HashTable_t *pxLast = pxIOManager->xHashCache + ffconfigHASH_CACHE_DEPTH;\r
3405         BaseType_t xResult;\r
3406 \r
3407                 for( ; ; )\r
3408                 {\r
3409                         if( pxHash->ulDirCluster == ulDirCluster )\r
3410                         {\r
3411                                 xResult = pdTRUE;\r
3412                                 break;\r
3413                         }\r
3414                         pxHash++;\r
3415                         if( pxHash >= pxLast )\r
3416                         {\r
3417                                 xResult = pdFALSE;\r
3418                                 break;\r
3419                         }\r
3420                 }\r
3421 \r
3422                 return xResult;\r
3423         }       /* FF_DirHashed() */\r
3424 #endif /* ffconfigHASH_CACHE */\r
3425 /*-----------------------------------------------------------*/\r
3426 \r