]> git.sur5r.net Git - freertos/blob - FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_fat.c
Add the Labs projects provided in the V10.2.1_191129 zip file.
[freertos] / FreeRTOS-Labs / Source / FreeRTOS-Plus-FAT / ff_fat.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_fat.c\r
29  *      @ingroup        FAT\r
30  *\r
31  *      @defgroup       FAT Fat File-System\r
32  *      @brief          Handles FAT access and traversal.\r
33  *\r
34  *      Provides file-system interfaces for the FAT file-system.\r
35  **/\r
36 \r
37 #include "ff_headers.h"\r
38 #include <string.h>\r
39 \r
40 \r
41 #if ffconfigFAT_USES_STAT\r
42         /* This module make use of a buffer caching called 'FF_FATBuffers_t'.\r
43          * The struct below may gather statistics about its usage: hits/misses.\r
44          */\r
45         struct SFatStat fatStat;\r
46 #endif /* ffconfigFAT_USES_STAT */\r
47 \r
48 \r
49 /* prvGetFromFATBuffers() will see if the FF_Buffer_t pointed to by ppxBuffer contains the\r
50  * buffer that is needed, i.e. opened for the same sector and with the correct R/W mode.\r
51  * If ppxBuffer is NULL or if it can not be used, a new buffer will be created.\r
52  * The buffer pointed to by ppxBuffer will either be released or its pointer will be returned.\r
53  */\r
54 FF_Buffer_t *prvGetFromFATBuffers( FF_IOManager_t *pxIOManager, FF_FATBuffers_t *pxFATBuffers, BaseType_t xBufferIndex, uint32_t ulFATSector,\r
55         FF_Error_t *pxError, uint8_t ucMode );\r
56 \r
57 #if( ffconfigFAT12_SUPPORT != 0 )\r
58         /* A very special case for FAT12: an entry is stored in two sectors.\r
59          * Read the two sectors and merge the two values found.\r
60          */\r
61         static uint32_t prvGetFAT12Entry( FF_IOManager_t *pxIOManager, FF_Error_t *pxError, FF_FATBuffers_t *pxFATBuffers, uint32_t ulFATSector );\r
62 #endif\r
63 \r
64 #if( ffconfigFAT12_SUPPORT != 0 )\r
65         /* Same as above: put a FAT12 entry that is spread-out over two sectors.\r
66          * Read the current value first to preserve and merge the earlier 4 bits\r
67          * of an adjacent FAT12 entry.\r
68          */\r
69         static FF_Error_t prvPutFAT12Entry( FF_IOManager_t *pxIOManager, uint32_t ulCluster, uint32_t ulValue, FF_FATBuffers_t *pxFATBuffers,\r
70                 uint32_t ulFATSector );\r
71 #endif\r
72 \r
73 #if( ffconfigFAT12_SUPPORT != 0 )\r
74         /* A generic less-optimised way of finding the first free cluster.\r
75          * Used for FAT12 only.\r
76          */\r
77         static uint32_t prvFindFreeClusterSimple( FF_IOManager_t *pxIOManager, FF_Error_t *pxError );\r
78 #endif  /* ffconfigFAT12_SUPPORT */\r
79 \r
80 #if( ffconfigFAT12_SUPPORT != 0 )\r
81         /* A generic less-optimised way of counting free clusters.\r
82          * Used for FAT12 only.\r
83          */\r
84         static uint32_t prvCountFreeClustersSimple( FF_IOManager_t *pxIOManager, FF_Error_t *pxError );\r
85 #endif  /* ffconfigFAT12_SUPPORT */\r
86 \r
87 \r
88 \r
89 /* Have a cluster number and translate it to an LBA (Logical Block Address).\r
90 'ulSectorsPerCluster' should be seen as 'blocks per cluster', where the length of one\r
91 block is defined in the PBR (Partition Boot Record) at FF_FAT_BYTES_PER_SECTOR (offset 0x0B).\r
92 */\r
93 uint32_t FF_Cluster2LBA( FF_IOManager_t *pxIOManager, uint32_t ulCluster )\r
94 {\r
95 uint32_t ulLBA = 0;\r
96 FF_Partition_t *pxPartition;\r
97 \r
98         if( pxIOManager != NULL )\r
99         {\r
100                 pxPartition = &( pxIOManager->xPartition );\r
101 \r
102                 if( ulCluster >= 2 )\r
103                 {\r
104                         ulLBA = ( ( ulCluster - 2 ) * pxPartition->ulSectorsPerCluster ) + pxPartition->ulFirstDataSector;\r
105                 }\r
106                 else\r
107                 {\r
108                         ulLBA = pxPartition->ulClusterBeginLBA;\r
109                 }\r
110         }\r
111 \r
112         return ulLBA;\r
113 }\r
114 /*-----------------------------------------------------------*/\r
115 \r
116 /*\r
117  * Major and Minor sectors/blocks:\r
118  *\r
119  * A cluster is defined as N "sectors". Those sectors in fact are "major blocks"\r
120  * whose size is defined in a field called 'FF_FAT_BYTES_PER_SECTOR' in the PBR.\r
121  *\r
122  * I/O to the disk takes place in "minor block" of usually 512 byte and the addressing\r
123  * is also based on "minor block" sector numbers.\r
124  *\r
125  * In most cases, Major == Minor == 512 bytes.\r
126  *\r
127  * Here below some translations are done for 'entries', which can be 1-byte entries\r
128  * as well as the 32-byte directory entries.\r
129  *\r
130  */\r
131 \r
132 /* Translate an 'entry number' (ulEntry) to a relative cluster number,\r
133 where e.g. 'ulEntry' may be a sequence number of a directory entry for\r
134 which ulEntrySize = 32 bytes.\r
135 */\r
136 uint32_t FF_getClusterChainNumber( FF_IOManager_t *pxIOManager, uint32_t ulEntry, uint32_t ulEntrySize )\r
137 {\r
138 uint32_t ulBytesPerCluster = pxIOManager->xPartition.usBlkSize * pxIOManager->xPartition.ulSectorsPerCluster;\r
139 uint32_t ulEntriesPerCluster =  ( ulBytesPerCluster / ulEntrySize );\r
140 \r
141         /* E.g. ulBytesPerCluster = 16384, ulEntrySize = 32: 16384 / 32 = 512 entries per cluster. */\r
142         return ulEntry / ulEntriesPerCluster;\r
143 }\r
144 /*-----------------------------------------------------------*/\r
145 \r
146 /* If the above function returns a cluster number, this function\r
147 returns a BYTE position within that cluster. */\r
148 uint32_t FF_getClusterPosition( FF_IOManager_t *pxIOManager, uint32_t ulEntry, uint32_t ulEntrySize )\r
149 {\r
150 uint32_t ulBytesPerCluster = pxIOManager->xPartition.usBlkSize * pxIOManager->xPartition.ulSectorsPerCluster;\r
151 uint32_t ulEntriesPerCluster =  ( ulBytesPerCluster / ulEntrySize );\r
152 \r
153         /* Return the block offset within the current cluster: */\r
154         return ( ulEntry % ulEntriesPerCluster ) * ulEntrySize;\r
155 }\r
156 /*-----------------------------------------------------------*/\r
157 \r
158 /* Return the block offset (= number of major blocks) within the current cluster: */\r
159 uint32_t FF_getMajorBlockNumber( FF_IOManager_t *pxIOManager, uint32_t ulEntry, uint32_t ulEntrySize )\r
160 {\r
161 uint32_t ulBytesPerCluster = pxIOManager->xPartition.usBlkSize * pxIOManager->xPartition.ulSectorsPerCluster;\r
162 uint32_t ulEntriesPerCluster = ( ulBytesPerCluster / ulEntrySize );\r
163 uint32_t ulRelClusterEntry;\r
164 \r
165         /* Calculate the entry number within a cluster: */\r
166         ulRelClusterEntry = ulEntry % ulEntriesPerCluster;\r
167 \r
168         /* Return the block offset within the current cluster: */\r
169         return ulRelClusterEntry / ( pxIOManager->xPartition.usBlkSize / ulEntrySize );\r
170 }\r
171 /*-----------------------------------------------------------*/\r
172 \r
173 /* Return the minor block number within the current major block */\r
174 uint32_t FF_getMinorBlockNumber( FF_IOManager_t *pxIOManager, uint32_t ulEntry, uint32_t ulEntrySize )\r
175 {\r
176 uint32_t ulBytesPerCluster = pxIOManager->xPartition.usBlkSize * pxIOManager->xPartition.ulSectorsPerCluster;\r
177 uint32_t ulEntriesPerCluster = ( ulBytesPerCluster / ulEntrySize );\r
178 uint32_t ulRelClusterEntry;\r
179 uint32_t ulRelMajorBlockEntry;\r
180 \r
181         /* Calculate the entry number within a cluster: */\r
182         ulRelClusterEntry = ulEntry % ulEntriesPerCluster;\r
183 \r
184         ulRelMajorBlockEntry = ulRelClusterEntry % ( pxIOManager->xPartition.usBlkSize / ulEntrySize );\r
185 \r
186         return ulRelMajorBlockEntry / ( pxIOManager->usSectorSize / ulEntrySize );\r
187 }\r
188 /*-----------------------------------------------------------*/\r
189 \r
190 /* Get the entry number within the minor block */\r
191 uint32_t FF_getMinorBlockEntry( FF_IOManager_t *pxIOManager, uint32_t ulEntry, uint32_t ulEntrySize )\r
192 {\r
193 uint32_t ulBytesPerCluster = pxIOManager->xPartition.usBlkSize * pxIOManager->xPartition.ulSectorsPerCluster;\r
194 uint32_t ulEntriesPerCluster =  ( ulBytesPerCluster / ulEntrySize );\r
195 uint32_t ulRelClusterEntry;\r
196 uint32_t ulRelMajorBlockEntry;\r
197 \r
198         /* Calculate the entry number within a cluster: */\r
199         ulRelClusterEntry = ulEntry % ulEntriesPerCluster;\r
200 \r
201         ulRelMajorBlockEntry = ulRelClusterEntry % ( pxIOManager->xPartition.usBlkSize / ulEntrySize );\r
202 \r
203         return ulRelMajorBlockEntry % ( pxIOManager->usSectorSize / ulEntrySize );\r
204 }\r
205 /*-----------------------------------------------------------*/\r
206 \r
207 FF_Error_t FF_ReleaseFATBuffers( FF_IOManager_t *pxIOManager, FF_FATBuffers_t *pxFATBuffers )\r
208 {\r
209 BaseType_t xIndex;\r
210 FF_Error_t xError = FF_ERR_NONE;\r
211 FF_Buffer_t *pxBuffer;\r
212 #if ffconfigBUF_STORE_COUNT != 2\r
213         #warning Only maintaining one FAT table\r
214 #endif\r
215         /* 'ffconfigBUF_STORE_COUNT' equals to the number of FAT tables. */\r
216         for( xIndex = 0; xIndex < ffconfigBUF_STORE_COUNT; xIndex++ )\r
217         {\r
218                 pxBuffer = pxFATBuffers->pxBuffers[ xIndex ];\r
219                 if( pxBuffer != NULL )\r
220                 {\r
221                 FF_Error_t xTempError = FF_ERR_NONE;\r
222 \r
223                         pxFATBuffers->pxBuffers[ xIndex ] = NULL;\r
224                         xTempError = FF_ReleaseBuffer( pxIOManager, pxBuffer );\r
225                         if( FF_isERR( xError ) == pdFALSE )\r
226                         {\r
227                                 /* as everywhere, this function will return\r
228                                 the first error that occurred, if any. */\r
229                                 xError = xTempError;\r
230                         }\r
231                 }\r
232         }\r
233         #if ffconfigFAT_USES_STAT\r
234         {\r
235                 fatStat.clearCount++;\r
236         }\r
237         #endif /* ffconfigFAT_USES_STAT */\r
238 \r
239         return xError;\r
240 }\r
241 /*-----------------------------------------------------------*/\r
242 \r
243 FF_Buffer_t *prvGetFromFATBuffers( FF_IOManager_t *pxIOManager, FF_FATBuffers_t *pxFATBuffers, BaseType_t xBufferIndex,\r
244         uint32_t ulFATSector, FF_Error_t *pxError, uint8_t ucMode )\r
245 {\r
246 FF_Error_t xError = FF_ERR_NONE;\r
247 FF_Buffer_t *pxBuffer = NULL;\r
248 \r
249         if( pxFATBuffers != NULL )\r
250         {\r
251                 /* See if the same buffer can be reused. */\r
252                 pxBuffer = pxFATBuffers->pxBuffers[ xBufferIndex ];\r
253 \r
254                 if( pxBuffer != NULL )\r
255                 {\r
256                         /* Now the buffer is either owned by pxBuffer,\r
257                         or it has been released, so put it to NULL. */\r
258                         pxFATBuffers->pxBuffers[ xBufferIndex ] = NULL;\r
259 \r
260                         if(\r
261                                 ( pxBuffer->ulSector == ulFATSector ) &&\r
262                                 ( ( ( ucMode & FF_MODE_WRITE ) == 0 ) ||\r
263                                   ( ( pxBuffer->ucMode & FF_MODE_WRITE ) != 0 ) )\r
264                         )\r
265                         {\r
266                                 /* Same sector, AND\r
267                                 write-permission is not required OR the buffer has write permission:\r
268                                 it can be reused. */\r
269                                 #if ffconfigFAT_USES_STAT\r
270                                 {\r
271                                         fatStat.reuseCount[ ( ucMode & FF_MODE_WRITE ) ? 1 : 0 ]++;\r
272                                 }\r
273                                 #endif /* ffconfigFAT_USES_STAT */\r
274                         }\r
275                         else\r
276                         {\r
277                                 xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );\r
278                                 pxBuffer = NULL;\r
279                                 #if ffconfigFAT_USES_STAT\r
280                                 {\r
281                                         fatStat.missCount[ ( ucMode & FF_MODE_WRITE ) ? 1 : 0 ]++;\r
282                                 }\r
283                                 #endif /* ffconfigFAT_USES_STAT */\r
284                         }\r
285                 }\r
286                 else\r
287                 {\r
288                         #if ffconfigFAT_USES_STAT\r
289                         {\r
290                                 fatStat.getCount[ ( ucMode & FF_MODE_WRITE ) ? 1 : 0 ]++;\r
291                         }\r
292                         #endif /* ffconfigFAT_USES_STAT */\r
293                 }\r
294         }\r
295 \r
296         if( ( pxBuffer == NULL ) && ( FF_isERR( xError ) == pdFALSE ) )\r
297         {\r
298                 pxBuffer = FF_GetBuffer( pxIOManager, ulFATSector, ucMode );\r
299                 if( pxBuffer == NULL )\r
300                 {\r
301                         /* Setting an error code without the Module/Function,\r
302                         will be filled-in by the caller. */\r
303                         xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_ERRFLAG );\r
304                 }\r
305         }\r
306         *pxError = xError;\r
307 \r
308         return pxBuffer;\r
309 }\r
310 \r
311 #if( ffconfigFAT12_SUPPORT != 0 )\r
312         /* A very special case for FAT12: an entry is stored in two sectors.\r
313         Read the two sectors and merge the two values found. */\r
314         static uint32_t prvGetFAT12Entry( FF_IOManager_t *pxIOManager, FF_Error_t *pxError, FF_FATBuffers_t *pxFATBuffers,\r
315                 uint32_t ulFATSector )\r
316         {\r
317         FF_Error_t xError = FF_ERR_NONE;\r
318         FF_Buffer_t *pxBuffer = NULL;\r
319         /* preferred buffer access mode, user might want to update this entry\r
320         and set it to FF_MODE_WRITE. */\r
321         uint8_t ucMode = pxFATBuffers ? pxFATBuffers->ucMode : FF_MODE_READ;\r
322         /* Collect the two bytes in an array. */\r
323         uint8_t ucBytes[ 2 ];\r
324         /* The function return value. */\r
325         uint32_t ulFATEntry = 0UL;\r
326 \r
327                 pxBuffer = prvGetFromFATBuffers( pxIOManager, pxFATBuffers, 0, ulFATSector, &xError, ucMode );\r
328 \r
329                 if( FF_isERR( xError ) )\r
330                 {\r
331                         xError = FF_GETERROR( xError ) | FF_GETFATENTRY;\r
332                 }\r
333                 else\r
334                 {\r
335                         /* Fetch the very last byte of this segment. */\r
336                         ucBytes[ 0 ] = FF_getChar( pxBuffer->pucBuffer, ( uint16_t ) ( pxIOManager->usSectorSize - 1 ) );\r
337 \r
338                         xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );\r
339 \r
340                         /* release the other buffer as well. */\r
341                         if( ( FF_isERR( xError ) == pdFALSE ) && ( pxFATBuffers != NULL ) )\r
342                         {\r
343                                 xError = FF_ReleaseFATBuffers( pxIOManager, pxFATBuffers );\r
344                         }\r
345 \r
346                         if( FF_isERR( xError ) == pdFALSE )\r
347                         {\r
348                                 /* Second Buffer get the first Byte in buffer (second byte of out address)! */\r
349                                 pxBuffer = FF_GetBuffer( pxIOManager, ulFATSector + 1, ucMode );\r
350                                 if( pxBuffer == NULL )\r
351                                 {\r
352                                         xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_GETFATENTRY );\r
353                                 }\r
354                                 else\r
355                                 {\r
356                                         /* Read the first byte from the subsequent sector. */\r
357                                         ucBytes[ 1 ] = FF_getChar( pxBuffer->pucBuffer, 0 );\r
358                                         /* And release that buffer. */\r
359                                         xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );\r
360                                         if( FF_isERR( xError ) == pdFALSE )\r
361                                         {\r
362                                                 /* Join the two bytes: */\r
363                                                 ulFATEntry = ( uint32_t ) FF_getShort( ( uint8_t * )ucBytes, 0 );\r
364                                         }\r
365                                 }\r
366                         }\r
367                 }\r
368                 *pxError = xError;\r
369 \r
370                 return ( int32_t ) ulFATEntry;\r
371         }\r
372 #endif  /* ffconfigFAT12_SUPPORT */\r
373 /*-----------------------------------------------------------*/\r
374 \r
375 \r
376 /* Get a FAT entry, which is nothing more than a number referring to a sector. */\r
377 uint32_t FF_getFATEntry( FF_IOManager_t *pxIOManager, uint32_t ulCluster, FF_Error_t *pxError, FF_FATBuffers_t *pxFATBuffers )\r
378 {\r
379 FF_Buffer_t *pxBuffer = NULL;\r
380 uint32_t ulFATOffset;\r
381 uint32_t ulFATSector = 0;\r
382 uint32_t ulFATSectorEntry;\r
383 /* The function result. */\r
384 uint32_t ulFATEntry = 0;\r
385 uint32_t ulLBAAdjust;\r
386 uint32_t ulRelClusterEntry = 0;\r
387 FF_Error_t xError = FF_ERR_NONE;\r
388 /* preferred mode, user might want to update this entry. */\r
389 uint8_t ucMode = pxFATBuffers ? pxFATBuffers->ucMode : FF_MODE_READ;\r
390 \r
391         FF_Assert_Lock( pxIOManager, FF_FAT_LOCK );\r
392 \r
393         if( ulCluster >= pxIOManager->xPartition.ulNumClusters )\r
394         {\r
395                 /* _HT_ find a more specific error code.\r
396                 Probably not really important as this is a function internal to the library. */\r
397                 xError = ( FF_Error_t ) ( FF_ERR_IOMAN_NOT_ENOUGH_FREE_SPACE | FF_GETFATENTRY );\r
398         }\r
399         else\r
400         {\r
401                 if( pxIOManager->xPartition.ucType == FF_T_FAT32 )\r
402                 {\r
403                         ulFATOffset = ulCluster * 4;\r
404                 }\r
405                 else if( pxIOManager->xPartition.ucType == FF_T_FAT16 )\r
406                 {\r
407                         ulFATOffset = ulCluster * 2;\r
408                 }\r
409                 else /* pxIOManager->xPartition.ucType == FF_T_FAT12 */\r
410                 {\r
411                         ulFATOffset = ulCluster + ( ulCluster / 2 );\r
412                 }\r
413 \r
414                 ulFATSector = pxIOManager->xPartition.ulFATBeginLBA + ( ulFATOffset / pxIOManager->xPartition.usBlkSize );\r
415                 ulFATSectorEntry = ulFATOffset % pxIOManager->xPartition.usBlkSize;\r
416 \r
417                 ulLBAAdjust = ulFATSectorEntry / ( ( uint32_t ) pxIOManager->usSectorSize );\r
418                 ulRelClusterEntry = ulFATSectorEntry % pxIOManager->usSectorSize;\r
419 \r
420                 ulFATSector = FF_getRealLBA( pxIOManager, ulFATSector );\r
421                 ulFATSector += ulLBAAdjust;\r
422         }\r
423 \r
424 #if( ffconfigFAT12_SUPPORT != 0 )\r
425         if( ( pxIOManager->xPartition.ucType == FF_T_FAT12 ) &&\r
426                 ( FF_isERR( xError ) == pdFALSE ) &&\r
427                 ( ulRelClusterEntry == ( uint32_t ) ( ( pxIOManager->usSectorSize - 1 ) ) ) )\r
428         {\r
429                 /* Fat Entry SPANS a Sector!\r
430                 It has 4 bits on one sector and 8 bits on the other sector.\r
431                 Handle this in a separate function prvGetFAT12Entry(). */\r
432                 ulFATEntry = prvGetFAT12Entry( pxIOManager, &xError, pxFATBuffers, ulFATSector );\r
433 \r
434                 if( ( ulCluster & 0x0001 ) != 0 )\r
435                 {\r
436                         /* For odd clusters, shift the address 4 bits to the right: */\r
437                         ulFATEntry = ( ulFATEntry & 0xfff0 ) >> 4;\r
438                 }\r
439                 else\r
440                 {\r
441                         /* For even clusters, take the lower 12 bits: */\r
442                         ulFATEntry = ( ulFATEntry & 0x0fff );\r
443                 }\r
444                 /* Return ulFATEntry, unless xError contains an error. */\r
445         }\r
446         else\r
447 #endif /* ffconfigFAT12_SUPPORT */\r
448         if( FF_isERR( xError ) == pdFALSE )\r
449         {\r
450                 /* Handle FAT16, FAT32, and FAT12 (in case the entry lies on a single sector). */\r
451 \r
452                 pxBuffer = prvGetFromFATBuffers( pxIOManager, pxFATBuffers, 0, ulFATSector, &xError, ucMode );\r
453                 if( FF_isERR( xError ) )\r
454                 {\r
455                         xError = FF_GETERROR( xError ) | FF_GETFATENTRY;\r
456                 }\r
457                 else\r
458                 {\r
459                         switch( pxIOManager->xPartition.ucType )\r
460                         {\r
461                                 case FF_T_FAT32:\r
462                                         ulFATEntry = FF_getLong( pxBuffer->pucBuffer, ulRelClusterEntry );\r
463                                         /* Clear the top 4 bits. */\r
464                                         ulFATEntry &= 0x0fffffff;\r
465                                         break;\r
466                                 case FF_T_FAT16:\r
467                                         ulFATEntry = ( uint32_t ) FF_getShort( pxBuffer->pucBuffer, ulRelClusterEntry );\r
468                                         break;\r
469                         #if( ffconfigFAT12_SUPPORT != 0 )\r
470                                 case FF_T_FAT12:\r
471                                         ulFATEntry = ( uint32_t ) FF_getShort( pxBuffer->pucBuffer, ulRelClusterEntry );\r
472                                         /* Entries are either stored as 4 + 8 bits or as 8 + 4 bits,\r
473                                         depending on the cluster being odd or even.                                             */\r
474                                         if( ( ulCluster & 0x0001 ) != 0 )\r
475                                         {\r
476                                                 /* For odd clusters, shift the address 4 bits to the right: */\r
477                                                 ulFATEntry = ( ulFATEntry & 0xfff0 ) >> 4;\r
478                                         }\r
479                                         else\r
480                                         {\r
481                                                 /* For even clusters, take the lower 12 bits: */\r
482                                                 ulFATEntry = ( ulFATEntry & 0x0fff );\r
483                                         }\r
484                                         break;\r
485                         #endif\r
486                                 default:\r
487                                         ulFATEntry = 0;\r
488                                         break;\r
489                         }\r
490 \r
491                         if( pxFATBuffers != NULL )\r
492                         {\r
493                                 /* Store the buffer. */\r
494                                 pxFATBuffers->pxBuffers[ 0 ] = pxBuffer;\r
495                         }\r
496                         else\r
497                         {\r
498                                 /* Or release it. */\r
499                                 xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );\r
500                         }\r
501                 }       /* if( FF_isERR( xError ) == pdFALSE ) */\r
502         }       /* else Handle FAT16, FAT32, and FAT12 (in case the entry lies on a single sector). */\r
503 \r
504         if( FF_isERR( xError ) )\r
505         {\r
506                 /* The sector address 0 is not meaningful and here it is used as the 'error value'. */\r
507                 ulFATEntry = 0UL;\r
508         }\r
509 \r
510         if( pxError != NULL )\r
511         {\r
512                 *pxError = xError;\r
513         }\r
514 \r
515         return ( int32_t )ulFATEntry;\r
516 }       /* FF_getFATEntry() */\r
517 /*-----------------------------------------------------------*/\r
518 \r
519 /* Write all zero's to all sectors of a given cluster. */\r
520 FF_Error_t FF_ClearCluster( FF_IOManager_t *pxIOManager, uint32_t ulCluster )\r
521 {\r
522 FF_Error_t xError = FF_ERR_NONE;\r
523 FF_Buffer_t *pxBuffer = NULL;\r
524 BaseType_t xIndex;\r
525 uint32_t ulBaseLBA;\r
526 \r
527         /* Calculate from cluster number to a real block address. */\r
528         ulBaseLBA = FF_Cluster2LBA( pxIOManager, ulCluster );\r
529         ulBaseLBA = FF_getRealLBA( pxIOManager, ulBaseLBA );\r
530 \r
531         for( xIndex = 0; xIndex < ( BaseType_t ) pxIOManager->xPartition.ulSectorsPerCluster; xIndex++ )\r
532         {\r
533                 if( xIndex == 0 )\r
534                 {\r
535                         /* When using the FF_MODE_WR_ONLY flag, the data will not be read from disk.\r
536                         Only in the first round a buffer will be claimed. */\r
537                         pxBuffer = FF_GetBuffer( pxIOManager, ulBaseLBA, FF_MODE_WR_ONLY );\r
538                         if( pxBuffer == NULL )\r
539                         {\r
540                                 xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_CLEARCLUSTER );\r
541                                 break;\r
542                         }\r
543                         memset( pxBuffer->pucBuffer, 0x00, pxIOManager->usSectorSize );\r
544                 }\r
545 \r
546                 xError = FF_BlockWrite( pxIOManager, ulBaseLBA + xIndex, 1, pxBuffer->pucBuffer, pdFALSE );\r
547                 if( FF_isERR( xError ) )\r
548                 {\r
549                         break;\r
550                 }\r
551         }\r
552 \r
553         if( pxBuffer != NULL )\r
554         {\r
555         FF_Error_t xTempError;\r
556 \r
557                 /* The contents of the buffer (all zero's) has been written explicitly to disk\r
558                 by calling FF_BlockWrite().  Therefore, the bModified should be cleared. */\r
559                 pxBuffer->bModified = pdFALSE;\r
560                 /* Releasing the handle will not write anything */\r
561                 xTempError = FF_ReleaseBuffer( pxIOManager, pxBuffer );\r
562 \r
563                 if( FF_isERR( xError ) == pdFALSE )\r
564                 {\r
565                         xError = xTempError;\r
566                 }\r
567         }\r
568 \r
569         return xError;\r
570 }\r
571 /*-----------------------------------------------------------*/\r
572 \r
573 /**\r
574  *      @private\r
575  *      @brief  Returns the Cluster address of the Cluster number from the beginning of a chain.\r
576  *\r
577  *      @param  pxIOManager     FF_IOManager_t Object\r
578  *      @param  ulStart         Cluster address of the first cluster in the chain.\r
579  *      @param  ulCount         Number of Cluster in the chain,\r
580  *\r
581  *\r
582  *\r
583  **/\r
584 uint32_t FF_TraverseFAT( FF_IOManager_t *pxIOManager, uint32_t ulStart, uint32_t ulCount, FF_Error_t *pxError )\r
585 {\r
586 FF_Error_t xError = FF_ERR_NONE;\r
587 uint32_t ulIndex;\r
588 uint32_t ulFatEntry = ulStart;\r
589 uint32_t ulCurrentCluster = ulStart;\r
590 FF_FATBuffers_t xFATBuffers;\r
591 BaseType_t xTakeLock = FF_Has_Lock( pxIOManager, FF_FAT_LOCK ) == pdFALSE;\r
592 \r
593         /* xFATBuffers is nothing more than an array of FF_Buffer_t's.\r
594         One buffer for each FAT copy on disk. */\r
595         FF_InitFATBuffers( &xFATBuffers, FF_MODE_READ );\r
596 \r
597         if( xTakeLock )\r
598         {\r
599                 FF_LockFAT( pxIOManager );\r
600         }\r
601         for( ulIndex = 0; ulIndex < ulCount; ulIndex++ )\r
602         {\r
603                 ulFatEntry = FF_getFATEntry( pxIOManager, ulCurrentCluster, &xError, &xFATBuffers );\r
604                 if( FF_isERR( xError ) )\r
605                 {\r
606                         ulFatEntry = 0;\r
607                         break;\r
608                 }\r
609 \r
610                 if( FF_isEndOfChain( pxIOManager, ulFatEntry ) )\r
611                 {\r
612                         ulFatEntry = ulCurrentCluster;\r
613                         break;\r
614                 }\r
615 \r
616                 ulCurrentCluster = ulFatEntry;\r
617         }\r
618         if( xTakeLock )\r
619         {\r
620                 FF_UnlockFAT( pxIOManager );\r
621         }\r
622 \r
623         {\r
624         FF_Error_t xTempError;\r
625 \r
626                 xTempError = FF_ReleaseFATBuffers( pxIOManager, &xFATBuffers );\r
627                 if( FF_isERR( xError ) == pdFALSE )\r
628                 {\r
629                         xError = xTempError;\r
630                 }\r
631         }\r
632 \r
633         *pxError = xError;\r
634 \r
635         return ulFatEntry;\r
636 }\r
637 /*-----------------------------------------------------------*/\r
638 \r
639 uint32_t FF_FindEndOfChain( FF_IOManager_t *pxIOManager, uint32_t ulStart, FF_Error_t *pxError )\r
640 {\r
641 uint32_t ulFatEntry = ulStart;\r
642 FF_Error_t xError;\r
643 \r
644         if( FF_isEndOfChain( pxIOManager, ulStart ) == pdFALSE )\r
645         {\r
646                 /* Traverse FAT for (2^32-1) items/clusters,\r
647                 or until end-of-chain is encountered. */\r
648                 ulFatEntry = FF_TraverseFAT( pxIOManager, ulStart, ~0UL, &xError );\r
649         }\r
650         else\r
651         {\r
652                 xError = FF_ERR_NONE;\r
653         }\r
654 \r
655         *pxError = xError;\r
656 \r
657         return ulFatEntry;\r
658 }\r
659 /*-----------------------------------------------------------*/\r
660 \r
661 /**\r
662  *      @private\r
663  *      @brief  Tests if the ulFATEntry is an End of Chain Marker.\r
664  *\r
665  *      @param  pxIOManager     FF_IOManager_t Object\r
666  *      @param  ulFATEntry      The fat entry from the FAT table to be checked.\r
667  *\r
668  *      @return pdTRUE if it is an end of chain, otherwise pdFALSE.\r
669  *\r
670  **/\r
671 BaseType_t FF_isEndOfChain( FF_IOManager_t *pxIOManager, uint32_t ulFATEntry )\r
672 {\r
673 BaseType_t      xResult = pdFALSE;\r
674 \r
675         if( pxIOManager->xPartition.ucType == FF_T_FAT32 )\r
676         {\r
677                 if( ( ulFATEntry & 0x0fffffff ) >= 0x0ffffff8 )\r
678                 {\r
679                         xResult = pdTRUE;\r
680                 }\r
681         }\r
682         else if( pxIOManager->xPartition.ucType == FF_T_FAT16 )\r
683         {\r
684                 if( ulFATEntry >= 0x0000fff8 )\r
685                 {\r
686                         xResult = pdTRUE;\r
687                 }\r
688         }\r
689         else\r
690         {\r
691                 if( ulFATEntry >= 0x00000ff8 )\r
692                 {\r
693                         xResult = pdTRUE;\r
694                 }\r
695         }\r
696 \r
697         if( ulFATEntry == 0x00000000 )\r
698         {\r
699                 xResult = pdTRUE;       /* Perhaps trying to read a deleted file! */\r
700         }\r
701 \r
702         return xResult;\r
703 }\r
704 /*-----------------------------------------------------------*/\r
705 \r
706 #if( ffconfigFAT12_SUPPORT != 0 )\r
707         static FF_Error_t prvPutFAT12Entry( FF_IOManager_t *pxIOManager, uint32_t ulCluster, uint32_t ulValue, FF_FATBuffers_t *pxFATBuffers,\r
708                 uint32_t ulFATSector )\r
709         {\r
710         FF_Buffer_t *pxBuffer = NULL;\r
711         /* For FAT12 FAT Table Across sector boundary traversal. */\r
712         uint8_t ucBytes[ 2 ];\r
713         /* The function result value. */\r
714         uint32_t ulFATEntry;\r
715         FF_Error_t xError = FF_ERR_NONE;\r
716         BaseType_t xIndex;\r
717         #if( ffconfigWRITE_BOTH_FATS != 0 )\r
718                 const BaseType_t xNumFATs = pxIOManager->xPartition.ucNumFATS;\r
719         #else\r
720                 const BaseType_t xNumFATs = 1;\r
721         #endif\r
722 \r
723                 /* This routine will only change 12 out of 16 bits.\r
724                 Get the current 16-bit value, 4 bits shall be preserved. */\r
725                 ulFATEntry = prvGetFAT12Entry( pxIOManager, &xError, pxFATBuffers, ulFATSector );\r
726 \r
727                 if( FF_isERR( xError ) == pdFALSE )\r
728                 {\r
729                         if( ( ulCluster & 0x0001 ) != 0 )\r
730                         {\r
731                                  ulFATEntry &= 0x000F;\r
732                                  ulValue         = ( ulValue << 4 );\r
733                                  ulValue    &= 0xFFF0;\r
734                         }\r
735                         else\r
736                         {\r
737                                  ulFATEntry     &= 0xF000;\r
738                                  ulValue        &= 0x0FFF;\r
739                         }\r
740                         ulFATEntry |= ulValue;\r
741 \r
742                         /* Write at offset 0 in the array ucBytes. */\r
743                         FF_putShort( ucBytes, 0, ( uint16_t ) ulFATEntry );\r
744 \r
745                         for( xIndex = 0;\r
746                                  xIndex < xNumFATs;\r
747                                  xIndex++, ulFATSector += pxIOManager->xPartition.ulSectorsPerFAT )\r
748                         {\r
749                                 /* Write the last byte in the first sector. */\r
750                                 pxBuffer = FF_GetBuffer( pxIOManager, ulFATSector, FF_MODE_WRITE );\r
751                                 {\r
752                                         if( pxBuffer == NULL )\r
753                                         {\r
754                                                 xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_PUTFATENTRY );\r
755                                                 break;\r
756                                         }\r
757                                         FF_putChar( pxBuffer->pucBuffer, ( uint16_t )( pxIOManager->usSectorSize - 1 ), ucBytes[ 0 ] );\r
758                                 }\r
759                                 xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );\r
760                                 if( FF_isERR( xError ) )\r
761                                 {\r
762                                         break;\r
763                                 }\r
764 \r
765                                 /* Write the first byte in the subsequent sector. */\r
766                                 pxBuffer = FF_GetBuffer( pxIOManager, ulFATSector + 1, FF_MODE_WRITE );\r
767                                 {\r
768                                         if( pxBuffer == NULL )\r
769                                         {\r
770                                                 xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_PUTFATENTRY );\r
771                                                 break;\r
772                                         }\r
773                                         FF_putChar( pxBuffer->pucBuffer, 0x0000, ucBytes[ 1 ] );\r
774                                 }\r
775                                 xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );\r
776                                 if( FF_isERR( xError ) )\r
777                                 {\r
778                                         break;\r
779                                 }\r
780                         } /* for ( xIndex = 0; xIndex < xNumFATs; xIndex++ ) */\r
781                 }\r
782 \r
783                 return xError;\r
784         }\r
785 #endif\r
786 \r
787 /**\r
788  *      @private\r
789  *      @brief  Writes a new Entry to the FAT Tables.\r
790  *\r
791  *      @param  pxIOManager             IOMAN object.\r
792  *      @param  ulCluster       Cluster Number to be modified.\r
793  *      @param  ulValue         The value to store.\r
794  **/\r
795 FF_Error_t FF_putFATEntry( FF_IOManager_t *pxIOManager, uint32_t ulCluster, uint32_t ulValue, FF_FATBuffers_t *pxFATBuffers )\r
796 {\r
797 FF_Buffer_t *pxBuffer;\r
798 uint32_t ulFATOffset;\r
799 uint32_t ulFATSector = 0;\r
800 uint32_t ulFATSectorEntry;\r
801 uint32_t ulFATEntry;\r
802 uint32_t ulLBAAdjust;\r
803 uint32_t ulRelClusterEntry = 0;\r
804 BaseType_t xIndex;\r
805 FF_Error_t xError = FF_ERR_NONE;\r
806 #if( ffconfigWRITE_BOTH_FATS != 0 )\r
807         const BaseType_t xNumFATs = pxIOManager->xPartition.ucNumFATS;\r
808 #else\r
809         const BaseType_t xNumFATs = 1;\r
810 #endif\r
811 \r
812 \r
813         FF_Assert_Lock( pxIOManager, FF_FAT_LOCK );\r
814 \r
815         /* Avoid corrupting the disk. */\r
816         if( ( ulCluster == 0ul ) || ( ulCluster >= pxIOManager->xPartition.ulNumClusters ) )\r
817         {\r
818                 /* find a more specific error code. */\r
819                 xError = ( FF_Error_t ) ( FF_ERR_IOMAN_NOT_ENOUGH_FREE_SPACE | FF_PUTFATENTRY );\r
820         }\r
821         else\r
822         {\r
823                 if( pxIOManager->xPartition.ucType == FF_T_FAT32 )\r
824                 {\r
825                         ulFATOffset = ulCluster * 4;\r
826                 }\r
827                 else if( pxIOManager->xPartition.ucType == FF_T_FAT16 )\r
828                 {\r
829                         ulFATOffset = ulCluster * 2;\r
830                 }\r
831                 else /* pxIOManager->xPartition.ucType == FF_T_FAT12 */\r
832                 {\r
833                         ulFATOffset = ulCluster + ( ulCluster / 2 );\r
834                 }\r
835 \r
836                 ulFATSector = pxIOManager->xPartition.ulFATBeginLBA + ( ulFATOffset / pxIOManager->xPartition.usBlkSize );\r
837                 ulFATSectorEntry = ulFATOffset % pxIOManager->xPartition.usBlkSize;\r
838 \r
839                 ulLBAAdjust = ulFATSectorEntry / ( ( uint32_t ) pxIOManager->usSectorSize );\r
840                 ulRelClusterEntry = ulFATSectorEntry % pxIOManager->usSectorSize;\r
841 \r
842                 ulFATSector = FF_getRealLBA( pxIOManager, ulFATSector );\r
843                 ulFATSector += ulLBAAdjust;\r
844         }\r
845 \r
846 #if( ffconfigFAT12_SUPPORT != 0 )\r
847         if( ( pxIOManager->xPartition.ucType == FF_T_FAT12 ) &&\r
848                 ( FF_isERR( xError ) == pdFALSE ) &&\r
849                 ( ulRelClusterEntry == ( uint32_t ) ( ( pxIOManager->usSectorSize - 1 ) ) ) )\r
850         {\r
851                 /* The special case in which one FAT12 entries is divided over 2 sectors.\r
852                 Treat this in a separate function. */\r
853                 xError = prvPutFAT12Entry( pxIOManager, ulCluster, ulValue, pxFATBuffers, ulFATSector );\r
854                 /* Return xError. */\r
855         }\r
856         else\r
857 #endif /* ffconfigFAT12_SUPPORT */\r
858         if( FF_isERR( xError ) == pdFALSE )\r
859         {\r
860                 /* Handle FAT16, FAT32, and FAT12 (in case the entry lies on a single sector). */\r
861                 for( xIndex = 0;\r
862                          xIndex < xNumFATs;\r
863                          xIndex++, ulFATSector += pxIOManager->xPartition.ulSectorsPerFAT )\r
864                 {\r
865                         pxBuffer = prvGetFromFATBuffers( pxIOManager, pxFATBuffers, xIndex, ulFATSector, &xError, FF_MODE_WRITE );\r
866 \r
867                         if( FF_isERR( xError ) )\r
868                         {\r
869                                 xError = FF_GETERROR( xError ) | FF_PUTFATENTRY;\r
870                                 break;\r
871                         }\r
872 \r
873                         if( pxIOManager->xPartition.ucType == FF_T_FAT32 )\r
874                         {\r
875                                 /* Clear the top 4 bits. */\r
876                                 ulValue &= 0x0fffffff;\r
877                                 FF_putLong( pxBuffer->pucBuffer, ulRelClusterEntry, ulValue );\r
878                         }\r
879                         else if( pxIOManager->xPartition.ucType == FF_T_FAT16 )\r
880                         {\r
881                                 FF_putShort( pxBuffer->pucBuffer, ulRelClusterEntry, ( uint16_t ) ulValue );\r
882                         }\r
883                         else\r
884                         {\r
885                                 ulFATEntry      = ( uint32_t ) FF_getShort( pxBuffer->pucBuffer, ulRelClusterEntry );\r
886                                 if( ( ulCluster & 0x0001 ) != 0 )\r
887                                 {\r
888                                         ulFATEntry &= 0x000F;\r
889                                         ulValue         = ( ulValue << 4 );\r
890                                         ulValue    &= 0xFFF0;\r
891                                 }\r
892                                 else\r
893                                 {\r
894                                         ulFATEntry      &= 0xF000;\r
895                                         ulValue         &= 0x0FFF;\r
896                                 }\r
897 \r
898                                 FF_putShort( pxBuffer->pucBuffer, ulRelClusterEntry, ( uint16_t ) ( ulFATEntry | ulValue ) );\r
899                         }\r
900 \r
901                         if( ( xIndex < ffconfigBUF_STORE_COUNT ) && ( pxFATBuffers != NULL ) )\r
902                         {\r
903                                 /* Store it for later use. */\r
904                                 pxFATBuffers->pxBuffers[ xIndex ] = pxBuffer;\r
905                                 pxFATBuffers->ucMode = FF_MODE_WRITE;\r
906                         }\r
907                         else\r
908                         {\r
909                                 xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );\r
910                                 if( FF_isERR( xError ) )\r
911                                 {\r
912                                         break;\r
913                                 }\r
914                         }\r
915                 }\r
916         }\r
917 \r
918         /* FF_putFATEntry() returns just an error code, not an address. */\r
919         return xError;\r
920 }       /* FF_putFATEntry() */\r
921 /*-----------------------------------------------------------*/\r
922 \r
923 /**\r
924  *      @private\r
925  *      @brief  Finds a Free Cluster and returns its number.\r
926  *\r
927  *      @param  pxIOManager     IOMAN Object.\r
928  *\r
929  *      @return The number of the cluster found to be free.\r
930  *      @return 0 on error.\r
931  **/\r
932 #if( ffconfigFAT12_SUPPORT != 0 )\r
933         static uint32_t prvFindFreeClusterSimple( FF_IOManager_t *pxIOManager, FF_Error_t *pxError )\r
934         {\r
935         FF_Error_t xError = FF_ERR_NONE;\r
936         uint32_t ulCluster = 0;\r
937         uint32_t ulFATEntry;\r
938         FF_FATBuffers_t xFATBuffers;\r
939 \r
940                 FF_InitFATBuffers( &xFATBuffers, FF_MODE_READ );\r
941 \r
942                 for( ulCluster = pxIOManager->xPartition.ulLastFreeCluster;\r
943                          ulCluster < pxIOManager->xPartition.ulNumClusters;\r
944                          ulCluster++ )\r
945                 {\r
946                         ulFATEntry = FF_getFATEntry( pxIOManager, ulCluster, &xError, &xFATBuffers );\r
947                         if( FF_isERR( xError ) )\r
948                         {\r
949                                 break;\r
950                         }\r
951                         if( ulFATEntry == 0 )\r
952                         {\r
953                                 pxIOManager->xPartition.ulLastFreeCluster = ulCluster;\r
954                                 break;\r
955 \r
956                         }\r
957                 }\r
958                 {\r
959                 FF_Error_t xTempError;\r
960 \r
961                         xTempError = FF_ReleaseFATBuffers( pxIOManager, &xFATBuffers );\r
962                         if( FF_isERR( xError ) == pdFALSE )\r
963                         {\r
964                                 xError = xTempError;\r
965                         }\r
966                 }\r
967                 if( ( FF_isERR( xError ) == pdFALSE ) &&\r
968                         ( ulCluster == pxIOManager->xPartition.ulNumClusters ) )\r
969                 {\r
970                         /* There is no free cluster any more. */\r
971                         ulCluster = 0;\r
972                         xError = FF_FINDFREECLUSTER | FF_ERR_IOMAN_NOT_ENOUGH_FREE_SPACE;\r
973                 }\r
974 \r
975                 *pxError = xError;\r
976 \r
977                 return ulCluster;\r
978         }\r
979 #endif\r
980 /*-----------------------------------------------------------*/\r
981 \r
982 uint32_t FF_FindFreeCluster( FF_IOManager_t *pxIOManager, FF_Error_t *pxError, BaseType_t xDoClaim )\r
983 {\r
984 FF_Error_t xError = FF_ERR_NONE;\r
985 FF_Buffer_t *pxBuffer = NULL;\r
986 uint32_t x, ulCluster;\r
987 uint32_t ulFATSectorEntry;\r
988 uint32_t ulEntriesPerSector;\r
989 uint32_t ulFATEntry = 1;\r
990 const BaseType_t xEntrySize = ( pxIOManager->xPartition.ucType == FF_T_FAT32 ) ? 4 : 2;\r
991 const uint32_t uNumClusters = pxIOManager->xPartition.ulNumClusters;\r
992 \r
993 BaseType_t xTakeLock = FF_Has_Lock( pxIOManager, FF_FAT_LOCK ) == pdFALSE;\r
994 \r
995         if( xTakeLock )\r
996         {\r
997                 FF_LockFAT( pxIOManager );\r
998         }\r
999 \r
1000         ulCluster = pxIOManager->xPartition.ulLastFreeCluster;\r
1001 \r
1002 #if( ffconfigFAT12_SUPPORT != 0 )\r
1003         /* FAT12 tables are too small to optimise, and would make it very complicated! */\r
1004         if( pxIOManager->xPartition.ucType == FF_T_FAT12 )\r
1005         {\r
1006                 ulCluster = prvFindFreeClusterSimple( pxIOManager, &xError );\r
1007         }\r
1008         else\r
1009 #endif\r
1010         {\r
1011                 #if( ffconfigFSINFO_TRUSTED != 0 )\r
1012                 {\r
1013                         /* If 'ffconfigFSINFO_TRUSTED', the contents of the field 'ulLastFreeCluster' is trusted.\r
1014                         Only ready it in case of FAT32 and only during the very first time, i.e. when\r
1015                         ulLastFreeCluster is still zero. */\r
1016                         if( ( pxIOManager->xPartition.ucType == FF_T_FAT32 ) && ( pxIOManager->xPartition.ulLastFreeCluster == 0ul ) )\r
1017                         {\r
1018                                 pxBuffer = FF_GetBuffer( pxIOManager, pxIOManager->xPartition.ulFSInfoLBA, FF_MODE_READ );\r
1019                                 if( pxBuffer == NULL )\r
1020                                 {\r
1021                                         xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_FINDFREECLUSTER );\r
1022                                 }\r
1023                                 else\r
1024                                 {\r
1025                                         if( ( FF_getLong(pxBuffer->pucBuffer, 0 ) == 0x41615252 ) &&\r
1026                                                 ( FF_getLong(pxBuffer->pucBuffer, 484 ) == 0x61417272 ) )\r
1027                                         {\r
1028                                                 ulCluster = FF_getLong( pxBuffer->pucBuffer, 492 );\r
1029                                         }\r
1030                                         xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );\r
1031                                         pxBuffer = NULL;\r
1032                                 }\r
1033 \r
1034                         }\r
1035                 }\r
1036                 #endif\r
1037                 if( FF_isERR( xError ) == pdFALSE )\r
1038                 {\r
1039                 uint32_t ulFATSector;\r
1040                 uint32_t ulFATOffset;\r
1041 \r
1042                         ulEntriesPerSector = pxIOManager->usSectorSize / xEntrySize;\r
1043                         ulFATOffset = ulCluster * xEntrySize;\r
1044 \r
1045                         /* Start from a sector where the first free entry is expected,\r
1046                         and iterate through every FAT sector. */\r
1047                         for( ulFATSector = ( ulFATOffset / pxIOManager->xPartition.usBlkSize );\r
1048                                  ulFATSector < pxIOManager->xPartition.ulSectorsPerFAT;\r
1049                                  ulFATSector++ )\r
1050                         {\r
1051                                 pxBuffer = FF_GetBuffer( pxIOManager, pxIOManager->xPartition.ulFATBeginLBA + ulFATSector, FF_MODE_READ );\r
1052                                 if( pxBuffer == NULL )\r
1053                                 {\r
1054                                         xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_FINDFREECLUSTER );\r
1055                                         break;\r
1056                                 }\r
1057                                 for( x = ( ulCluster % ulEntriesPerSector ); x < ulEntriesPerSector; x++ )\r
1058                                 {\r
1059                                         /* Double-check: don't use non-existing clusters */\r
1060                                         if( ulCluster >= uNumClusters )\r
1061                                         {\r
1062                                                 xError = ( FF_Error_t ) ( FF_ERR_IOMAN_NOT_ENOUGH_FREE_SPACE | FF_FINDFREECLUSTER );\r
1063                                                 break;\r
1064                                         }\r
1065                                         ulFATSectorEntry = ulFATOffset % pxIOManager->xPartition.usBlkSize;\r
1066                                         if( pxIOManager->xPartition.ucType == FF_T_FAT32 )\r
1067                                         {\r
1068                                                 ulFATEntry = FF_getLong( pxBuffer->pucBuffer, ulFATSectorEntry );\r
1069                                                 /* Clear the top 4 bits. */\r
1070                                                 ulFATEntry &= 0x0fffffff;\r
1071                                         }\r
1072                                         else\r
1073                                         {\r
1074                                                 ulFATEntry = ( uint32_t ) FF_getShort( pxBuffer->pucBuffer, ulFATSectorEntry );\r
1075                                         }\r
1076                                         if( ulFATEntry == 0x00000000 )\r
1077                                         {\r
1078                                                 /* Break and return 'ulCluster' */\r
1079                                                 break;\r
1080                                         }\r
1081                                         ulFATOffset += xEntrySize;\r
1082                                         ulCluster++;\r
1083                                 }\r
1084                                 xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );\r
1085                                 pxBuffer = NULL;\r
1086                                 if( FF_isERR( xError ) )\r
1087                                 {\r
1088                                         break;\r
1089                                 }\r
1090                                 if( ulFATEntry == 0x00000000 )\r
1091                                 {\r
1092                                         /* And break from the outer loop. */\r
1093                                         break;\r
1094                                 }\r
1095                         }\r
1096                         if( ( FF_isERR( xError ) == pdFALSE ) &&\r
1097                                 ( ulFATSector == pxIOManager->xPartition.ulSectorsPerFAT ) )\r
1098                         {\r
1099                                 xError = ( FF_Error_t ) ( FF_ERR_IOMAN_NOT_ENOUGH_FREE_SPACE | FF_FINDFREECLUSTER );\r
1100                         }\r
1101                 } /* if( FF_isERR( xError ) == pdFALSE ) */\r
1102         } /* if( pxIOManager->xPartition.ucType != FF_T_FAT12 ) */\r
1103 \r
1104         if( FF_isERR( xError ) )\r
1105         {\r
1106                 ulCluster = 0UL;\r
1107         }\r
1108         if( ( ulCluster != 0UL ) && ( xDoClaim != pdFALSE ) )\r
1109         {\r
1110         FF_Error_t xTempError;\r
1111 \r
1112                 /* Found a free cluster! */\r
1113                 pxIOManager->xPartition.ulLastFreeCluster = ulCluster + 1;\r
1114 \r
1115                 xTempError = FF_putFATEntry( pxIOManager, ulCluster, 0xFFFFFFFF, NULL );\r
1116                 if( FF_isERR( xError ) == pdFALSE )\r
1117                 {\r
1118                         xError = xTempError;\r
1119                 }\r
1120 \r
1121                 if( FF_isERR( xError ) )\r
1122                 {\r
1123                         ulCluster = 0UL;\r
1124                 }\r
1125         }\r
1126         if( xTakeLock )\r
1127         {\r
1128                 FF_UnlockFAT( pxIOManager );\r
1129         }\r
1130         *pxError = xError;\r
1131 \r
1132         return ulCluster;\r
1133 }       /* FF_FindFreeCluster */\r
1134 /*-----------------------------------------------------------*/\r
1135 \r
1136 /**\r
1137  * @private\r
1138  * @brief       Creates a Cluster Chain\r
1139  *      @return > 0 New created cluster\r
1140  *      @return = 0 See pxError\r
1141  **/\r
1142 uint32_t FF_CreateClusterChain( FF_IOManager_t *pxIOManager, FF_Error_t *pxError )\r
1143 {\r
1144 uint32_t ulStartCluster;\r
1145 FF_Error_t xError = FF_ERR_NONE;\r
1146 \r
1147         FF_LockFAT( pxIOManager );\r
1148         {\r
1149                 ulStartCluster = FF_FindFreeCluster( pxIOManager, &xError, pdTRUE );\r
1150         }\r
1151         FF_UnlockFAT( pxIOManager );\r
1152 \r
1153         if( ulStartCluster != 0L )\r
1154         {\r
1155                 xError = FF_DecreaseFreeClusters( pxIOManager, 1 );\r
1156         }\r
1157         *pxError = xError;\r
1158 \r
1159         return ulStartCluster;\r
1160 }\r
1161 /*-----------------------------------------------------------*/\r
1162 \r
1163 uint32_t FF_GetChainLength( FF_IOManager_t *pxIOManager, uint32_t ulStartCluster, uint32_t *pulEndOfChain, FF_Error_t *pxError )\r
1164 {\r
1165 uint32_t ulLength = 0;\r
1166 FF_FATBuffers_t xFATBuffers;\r
1167 FF_Error_t xError = FF_ERR_NONE;\r
1168 \r
1169         FF_InitFATBuffers( &xFATBuffers, FF_MODE_READ );\r
1170 \r
1171         FF_LockFAT( pxIOManager );\r
1172         {\r
1173                 while( FF_isEndOfChain( pxIOManager, ulStartCluster ) == pdFALSE )\r
1174                 {\r
1175                         ulStartCluster = FF_getFATEntry( pxIOManager, ulStartCluster, &xError, &xFATBuffers );\r
1176                         if( FF_isERR( xError ) )\r
1177                         {\r
1178                                 ulLength = 0;\r
1179                                 break;\r
1180                         }\r
1181                         ulLength++;\r
1182                 }\r
1183                 if( pulEndOfChain != NULL )\r
1184                 {\r
1185                         /* _HT_\r
1186                         ulStartCluster has just been tested as an end-of-chain token.\r
1187                         Not sure if the caller expects this. */\r
1188                         *pulEndOfChain = ulStartCluster;\r
1189                 }\r
1190                 xError = FF_ReleaseFATBuffers( pxIOManager, &xFATBuffers );\r
1191         }\r
1192         FF_UnlockFAT( pxIOManager );\r
1193 \r
1194         *pxError = xError;\r
1195 \r
1196         return ulLength;\r
1197 }\r
1198 /*-----------------------------------------------------------*/\r
1199 \r
1200 /**\r
1201  *      @private\r
1202  *      @brief Free's Disk space by freeing unused links on Cluster Chains\r
1203  *\r
1204  *      @param  pxIOManager,                    IOMAN object.\r
1205  *      @param  ulStartCluster  Cluster Number that starts the chain.\r
1206  *      @param  ulCount                 Number of Clusters from the end of the chain to unlink.\r
1207  *      @param  ulCount                 0 Means Free the entire chain (delete file).\r
1208  *      @param  ulCount                 1 Means mark the start cluster with EOF.\r
1209  *\r
1210  *      @return 0 On Success.\r
1211  *      @return -1 If the device driver failed to provide access.\r
1212  *\r
1213  **/\r
1214 FF_Error_t FF_UnlinkClusterChain( FF_IOManager_t *pxIOManager, uint32_t ulStartCluster, BaseType_t xDoTruncate )\r
1215 {\r
1216 uint32_t ulFATEntry;\r
1217 uint32_t ulCurrentCluster;\r
1218 uint32_t ulLength = 0;\r
1219 uint32_t ulLastFree = ulStartCluster;\r
1220 FF_Error_t xTempError;\r
1221 FF_Error_t xError = FF_ERR_NONE;\r
1222 FF_FATBuffers_t xFATBuffers;\r
1223 \r
1224 BaseType_t xTakeLock = FF_Has_Lock( pxIOManager, FF_FAT_LOCK ) == pdFALSE;\r
1225 \r
1226         if( xTakeLock )\r
1227         {\r
1228                 FF_LockFAT( pxIOManager );\r
1229         }\r
1230 \r
1231         FF_InitFATBuffers( &xFATBuffers, FF_MODE_WRITE );\r
1232 \r
1233         ulFATEntry = ulStartCluster;\r
1234 \r
1235         /* Free all clusters in the chain! */\r
1236         ulCurrentCluster = ulStartCluster;\r
1237         ulFATEntry = ulCurrentCluster;\r
1238         do\r
1239         {\r
1240                 /* Sector will now be fetched in write-mode. */\r
1241                 ulFATEntry = FF_getFATEntry( pxIOManager, ulFATEntry, &xError, &xFATBuffers );\r
1242                 if( FF_isERR( xError ) )\r
1243                 {\r
1244                         break;\r
1245                 }\r
1246 \r
1247                 if( ( xDoTruncate != pdFALSE ) && ( ulCurrentCluster == ulStartCluster ) )\r
1248                 {\r
1249                         xError = FF_putFATEntry( pxIOManager, ulCurrentCluster, 0xFFFFFFFF, &xFATBuffers );\r
1250                 }\r
1251                 else\r
1252                 {\r
1253                         xError = FF_putFATEntry( pxIOManager, ulCurrentCluster, 0x00000000, &xFATBuffers );\r
1254                         ulLength++;\r
1255                 }\r
1256                 if( FF_isERR( xError ) )\r
1257                 {\r
1258                         break;\r
1259                 }\r
1260 \r
1261                 if( ulLastFree > ulCurrentCluster )\r
1262                 {\r
1263                         ulLastFree = ulCurrentCluster;\r
1264                 }\r
1265                 ulCurrentCluster = ulFATEntry;\r
1266         } while( FF_isEndOfChain( pxIOManager, ulFATEntry ) == pdFALSE );\r
1267 \r
1268         if( FF_isERR( xError ) == pdFALSE )\r
1269         {\r
1270                 if( pxIOManager->xPartition.ulLastFreeCluster > ulLastFree )\r
1271                 {\r
1272                         pxIOManager->xPartition.ulLastFreeCluster = ulLastFree;\r
1273                 }\r
1274         }\r
1275 \r
1276         xTempError = FF_ReleaseFATBuffers( pxIOManager, &xFATBuffers );\r
1277         if( FF_isERR( xError ) == pdFALSE )\r
1278         {\r
1279                 xError = xTempError;\r
1280         }\r
1281 \r
1282         if( xTakeLock )\r
1283         {\r
1284                 FF_UnlockFAT( pxIOManager );\r
1285         }\r
1286         if( ulLength != 0 )\r
1287         {\r
1288                 xTempError = FF_IncreaseFreeClusters( pxIOManager, ulLength );\r
1289                 if( FF_isERR( xError ) == pdFALSE )\r
1290                 {\r
1291                         xError = xTempError;\r
1292                 }\r
1293         }\r
1294 \r
1295         return xError;\r
1296 }\r
1297 /*-----------------------------------------------------------*/\r
1298 \r
1299 #if( ffconfigFAT12_SUPPORT != 0 )\r
1300         static uint32_t prvCountFreeClustersSimple( FF_IOManager_t *pxIOManager, FF_Error_t *pxError )\r
1301         {\r
1302         FF_Error_t xError = FF_ERR_NONE;\r
1303         uint32_t ulIndex;\r
1304         uint32_t ulFATEntry;\r
1305         uint32_t ulFreeClusters = 0;\r
1306         const uint32_t xTotalClusters =\r
1307                 pxIOManager->xPartition.ulDataSectors / pxIOManager->xPartition.ulSectorsPerCluster;\r
1308 \r
1309                 for( ulIndex = 0; ulIndex < xTotalClusters; ulIndex++ )\r
1310                 {\r
1311                         ulFATEntry = FF_getFATEntry( pxIOManager, ulIndex, &xError, NULL );\r
1312                         if( FF_isERR( xError) )\r
1313                         {\r
1314                                 break;\r
1315                         }\r
1316                         if( ulFATEntry == 0UL )\r
1317                         {\r
1318                                 ulFreeClusters++;\r
1319                         }\r
1320                 }\r
1321 \r
1322                 *pxError = xError;\r
1323 \r
1324                 return ulFreeClusters;\r
1325         }\r
1326 #endif\r
1327 /*-----------------------------------------------------------*/\r
1328 \r
1329 \r
1330 uint32_t FF_CountFreeClusters( FF_IOManager_t *pxIOManager, FF_Error_t *pxError )\r
1331 {\r
1332 FF_Error_t xError = FF_ERR_NONE;\r
1333 FF_Buffer_t *pxBuffer;\r
1334 uint32_t ulIndex, x;\r
1335 uint32_t ulFATEntry;\r
1336 uint32_t ulEntriesPerSector;\r
1337 uint32_t ulFreeClusters = 0;\r
1338 uint32_t ClusterNum = 0;\r
1339 BaseType_t xInfoKnown = pdFALSE;\r
1340 BaseType_t xTakeLock = FF_Has_Lock( pxIOManager, FF_FAT_LOCK ) == pdFALSE;\r
1341 \r
1342         if( xTakeLock )\r
1343         {\r
1344                 FF_LockFAT( pxIOManager );\r
1345         }\r
1346 \r
1347 #if( ffconfigFAT12_SUPPORT != 0 )\r
1348         /* FAT12 tables are too small to optimise, and would make it very complicated! */\r
1349         if( pxIOManager->xPartition.ucType == FF_T_FAT12 )\r
1350         {\r
1351                 ulFreeClusters = prvCountFreeClustersSimple( pxIOManager, &xError );\r
1352         }\r
1353         else\r
1354 #endif\r
1355         {\r
1356                 /* For FAT16 and FAT32 */\r
1357                 #if( ffconfigFSINFO_TRUSTED != 0 )\r
1358                 {\r
1359                         /* If 'ffconfigFSINFO_TRUSTED', the contents of the field 'ulFreeClusterCount' is trusted. */\r
1360                         if( pxIOManager->xPartition.ucType == FF_T_FAT32 )\r
1361                         {\r
1362                                 pxBuffer = FF_GetBuffer( pxIOManager, pxIOManager->xPartition.ulFSInfoLBA, FF_MODE_READ );\r
1363                                 if( pxBuffer == NULL )\r
1364                                 {\r
1365                                         xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_COUNTFREECLUSTERS );\r
1366                                 }\r
1367                                 else\r
1368                                 {\r
1369                                         if( ( FF_getLong( pxBuffer->pucBuffer, 0 ) == 0x41615252 ) &&\r
1370                                                 ( FF_getLong( pxBuffer->pucBuffer, 484 ) == 0x61417272 ) )\r
1371                                         {\r
1372                                                 ulFreeClusters = FF_getLong( pxBuffer->pucBuffer, 488 );\r
1373 \r
1374                                                 if( ulFreeClusters != ~0ul )\r
1375                                                 {\r
1376                                                         xInfoKnown = pdTRUE;\r
1377                                                 }\r
1378                                                 else\r
1379                                                 {\r
1380                                                         ulFreeClusters = 0ul;\r
1381                                                 }\r
1382                                         }\r
1383 \r
1384                                         xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );\r
1385                                         pxBuffer = NULL;\r
1386 \r
1387                                         if( xInfoKnown != pdFALSE )\r
1388                                         {\r
1389                                                 pxIOManager->xPartition.ulFreeClusterCount = ulFreeClusters;\r
1390                                         }\r
1391                                 }\r
1392                         }\r
1393                 }\r
1394                 #endif\r
1395                 if( ( xInfoKnown == pdFALSE ) && ( pxIOManager->xPartition.usBlkSize != 0 ) )\r
1396                 {\r
1397                         if( pxIOManager->xPartition.ucType == FF_T_FAT32 )\r
1398                         {\r
1399                                 ulEntriesPerSector = pxIOManager->usSectorSize / 4;\r
1400                         }\r
1401                         else\r
1402                         {\r
1403                                 ulEntriesPerSector = pxIOManager->usSectorSize / 2;\r
1404                         }\r
1405                         for( ulIndex = 0; ulIndex < pxIOManager->xPartition.ulSectorsPerFAT; ulIndex++ )\r
1406                         {\r
1407                                 pxBuffer = FF_GetBuffer( pxIOManager, pxIOManager->xPartition.ulFATBeginLBA + ulIndex, FF_MODE_READ );\r
1408 \r
1409                                 if( pxBuffer == NULL )\r
1410                                 {\r
1411                                         xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_COUNTFREECLUSTERS );\r
1412                                         break;\r
1413                                 }\r
1414                                 #if USE_SOFT_WDT\r
1415                                 {\r
1416                                         /* _HT_ : FF_CountFreeClusters was a little too busy, have it call the WDT and sleep */\r
1417                                         clearWDT( );\r
1418                                         if( ( ( ulIndex + 1 ) % 32 ) == 0 )\r
1419                                         {\r
1420                                                 FF_Sleep( 1 );\r
1421                                         }\r
1422                                 }\r
1423                                 #endif\r
1424                                 for( x = 0; x < ulEntriesPerSector; x++ )\r
1425                                 {\r
1426                                         if( pxIOManager->xPartition.ucType == FF_T_FAT32 )\r
1427                                         {\r
1428                                                 /* Clearing the top 4 bits. */\r
1429                                                 ulFATEntry = FF_getLong( pxBuffer->pucBuffer, x * 4 ) & 0x0fffffff;\r
1430                                         }\r
1431                                         else\r
1432                                         {\r
1433                                                 ulFATEntry = ( uint32_t ) FF_getShort( pxBuffer->pucBuffer, x * 2 );\r
1434                                         }\r
1435                                         if( ulFATEntry == 0ul )\r
1436                                         {\r
1437                                                 ulFreeClusters++;\r
1438                                         }\r
1439                                         /* FAT table might not be cluster aligned. */\r
1440                                         if( ClusterNum > pxIOManager->xPartition.ulNumClusters )\r
1441                                         {\r
1442                                                 /* Stop counting if that's the case. */\r
1443                                                 break;\r
1444                                         }\r
1445                                         ClusterNum++;\r
1446                                 }\r
1447 \r
1448                                 xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );\r
1449                                 pxBuffer = NULL;\r
1450                                 if( FF_isERR( xError ) )\r
1451                                 {\r
1452                                         break;\r
1453                                 }\r
1454                                 if( ClusterNum > pxIOManager->xPartition.ulNumClusters )\r
1455                                 {\r
1456                                         /* Break out of 2nd loop too ^^ */\r
1457                                         break;\r
1458                                 }\r
1459                                 /* ulFreeClusters is -2 because the first 2 fat entries in the table are reserved. */\r
1460                                 if( ulFreeClusters > pxIOManager->xPartition.ulNumClusters )\r
1461                                 {\r
1462                                         ulFreeClusters = pxIOManager->xPartition.ulNumClusters;\r
1463                                 }\r
1464                         }       /* for( ulIndex = 0; ulIndex < pxIOManager->xPartition.ulSectorsPerFAT; ulIndex++ ) */\r
1465                 }\r
1466         }\r
1467 \r
1468         if( xTakeLock )\r
1469         {\r
1470                 FF_UnlockFAT( pxIOManager );\r
1471         }\r
1472 \r
1473         if( FF_isERR( xError ) )\r
1474         {\r
1475                 ulFreeClusters = 0;\r
1476         }\r
1477         *pxError = xError;\r
1478 \r
1479         return ulFreeClusters;\r
1480 }\r
1481 /*-----------------------------------------------------------*/\r
1482 \r
1483 #if( ffconfig64_NUM_SUPPORT != 0 )\r
1484         uint64_t FF_GetFreeSize( FF_IOManager_t *pxIOManager, FF_Error_t *pxError )\r
1485         {\r
1486         FF_Error_t xError = FF_ERR_NONE;\r
1487         uint32_t ulFreeClusters;\r
1488         uint64_t ulFreeSize = 0;\r
1489 \r
1490                 if( pxIOManager != NULL )\r
1491                 {\r
1492                         if( pxIOManager->xPartition.ulFreeClusterCount == 0ul )\r
1493                         {\r
1494                                 FF_LockFAT( pxIOManager );\r
1495                                 {\r
1496                                         pxIOManager->xPartition.ulFreeClusterCount = FF_CountFreeClusters( pxIOManager, &xError );\r
1497                                 }\r
1498                                 FF_UnlockFAT( pxIOManager );\r
1499                         }\r
1500                         ulFreeClusters = pxIOManager->xPartition.ulFreeClusterCount;\r
1501                         ulFreeSize = ( uint64_t )\r
1502                                 ( ( uint64_t ) ulFreeClusters * ( uint64_t )\r
1503                                 ( ( uint64_t ) pxIOManager->xPartition.ulSectorsPerCluster *\r
1504                                   ( uint64_t ) pxIOManager->xPartition.usBlkSize ) );\r
1505                 }\r
1506                 if( pxError != NULL )\r
1507                 {\r
1508                         *pxError = xError;\r
1509                 }\r
1510 \r
1511                 return ulFreeSize;\r
1512         }\r
1513 #else\r
1514         uint32_t FF_GetFreeSize( FF_IOManager_t *pxIOManager, FF_Error_t *pxError )\r
1515         {\r
1516         FF_Error_t xError = FF_ERR_NONE;\r
1517         uint32_t ulFreeClusters;\r
1518         uint32_t ulFreeSize = 0;\r
1519 \r
1520                 if( pxIOManager != NULL )\r
1521                 {\r
1522                         if( pxIOManager->xPartition.ulFreeClusterCount == 0ul )\r
1523                         {\r
1524                                 FF_LockFAT( pxIOManager );\r
1525                                 {\r
1526                                          pxIOManager->xPartition.ulFreeClusterCount = FF_CountFreeClusters( pxIOManager, &xError );\r
1527                                 }\r
1528                                 FF_UnlockFAT( pxIOManager );\r
1529                         }\r
1530                         ulFreeClusters = pxIOManager->xPartition.ulFreeClusterCount;\r
1531                         ulFreeSize = ( uint32_t )\r
1532                                 ( ( uint32_t ) ulFreeClusters * ( uint32_t )\r
1533                                 ( ( uint32_t ) pxIOManager->xPartition.ulSectorsPerCluster *\r
1534                                   ( uint32_t ) pxIOManager->xPartition.usBlkSize ) );\r
1535                 }\r
1536 \r
1537                 if( pxError != NULL )\r
1538                 {\r
1539                         *pxError = xError;\r
1540                 }\r
1541 \r
1542                 return ulFreeSize;\r
1543         }\r
1544 #endif  /* ffconfig64_NUM_SUPPORT */\r
1545 /*-----------------------------------------------------------*/\r
1546 \r