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
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
13 * The above copyright notice and this permission notice shall be included in all
\r
14 * copies or substantial portions of the Software.
\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
23 * https://www.FreeRTOS.org
\r
31 * @defgroup FAT Fat File-System
\r
32 * @brief Handles FAT access and traversal.
\r
34 * Provides file-system interfaces for the FAT file-system.
\r
37 #include "ff_headers.h"
\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
45 struct SFatStat fatStat;
\r
46 #endif /* ffconfigFAT_USES_STAT */
\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
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
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
61 static uint32_t prvGetFAT12Entry( FF_IOManager_t *pxIOManager, FF_Error_t *pxError, FF_FATBuffers_t *pxFATBuffers, uint32_t ulFATSector );
\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
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
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
77 static uint32_t prvFindFreeClusterSimple( FF_IOManager_t *pxIOManager, FF_Error_t *pxError );
\r
78 #endif /* ffconfigFAT12_SUPPORT */
\r
80 #if( ffconfigFAT12_SUPPORT != 0 )
\r
81 /* A generic less-optimised way of counting free clusters.
\r
82 * Used for FAT12 only.
\r
84 static uint32_t prvCountFreeClustersSimple( FF_IOManager_t *pxIOManager, FF_Error_t *pxError );
\r
85 #endif /* ffconfigFAT12_SUPPORT */
\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
93 uint32_t FF_Cluster2LBA( FF_IOManager_t *pxIOManager, uint32_t ulCluster )
\r
96 FF_Partition_t *pxPartition;
\r
98 if( pxIOManager != NULL )
\r
100 pxPartition = &( pxIOManager->xPartition );
\r
102 if( ulCluster >= 2 )
\r
104 ulLBA = ( ( ulCluster - 2 ) * pxPartition->ulSectorsPerCluster ) + pxPartition->ulFirstDataSector;
\r
108 ulLBA = pxPartition->ulClusterBeginLBA;
\r
114 /*-----------------------------------------------------------*/
\r
117 * Major and Minor sectors/blocks:
\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
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
125 * In most cases, Major == Minor == 512 bytes.
\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
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
136 uint32_t FF_getClusterChainNumber( FF_IOManager_t *pxIOManager, uint32_t ulEntry, uint32_t ulEntrySize )
\r
138 uint32_t ulBytesPerCluster = pxIOManager->xPartition.usBlkSize * pxIOManager->xPartition.ulSectorsPerCluster;
\r
139 uint32_t ulEntriesPerCluster = ( ulBytesPerCluster / ulEntrySize );
\r
141 /* E.g. ulBytesPerCluster = 16384, ulEntrySize = 32: 16384 / 32 = 512 entries per cluster. */
\r
142 return ulEntry / ulEntriesPerCluster;
\r
144 /*-----------------------------------------------------------*/
\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
150 uint32_t ulBytesPerCluster = pxIOManager->xPartition.usBlkSize * pxIOManager->xPartition.ulSectorsPerCluster;
\r
151 uint32_t ulEntriesPerCluster = ( ulBytesPerCluster / ulEntrySize );
\r
153 /* Return the block offset within the current cluster: */
\r
154 return ( ulEntry % ulEntriesPerCluster ) * ulEntrySize;
\r
156 /*-----------------------------------------------------------*/
\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
161 uint32_t ulBytesPerCluster = pxIOManager->xPartition.usBlkSize * pxIOManager->xPartition.ulSectorsPerCluster;
\r
162 uint32_t ulEntriesPerCluster = ( ulBytesPerCluster / ulEntrySize );
\r
163 uint32_t ulRelClusterEntry;
\r
165 /* Calculate the entry number within a cluster: */
\r
166 ulRelClusterEntry = ulEntry % ulEntriesPerCluster;
\r
168 /* Return the block offset within the current cluster: */
\r
169 return ulRelClusterEntry / ( pxIOManager->xPartition.usBlkSize / ulEntrySize );
\r
171 /*-----------------------------------------------------------*/
\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
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
181 /* Calculate the entry number within a cluster: */
\r
182 ulRelClusterEntry = ulEntry % ulEntriesPerCluster;
\r
184 ulRelMajorBlockEntry = ulRelClusterEntry % ( pxIOManager->xPartition.usBlkSize / ulEntrySize );
\r
186 return ulRelMajorBlockEntry / ( pxIOManager->usSectorSize / ulEntrySize );
\r
188 /*-----------------------------------------------------------*/
\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
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
198 /* Calculate the entry number within a cluster: */
\r
199 ulRelClusterEntry = ulEntry % ulEntriesPerCluster;
\r
201 ulRelMajorBlockEntry = ulRelClusterEntry % ( pxIOManager->xPartition.usBlkSize / ulEntrySize );
\r
203 return ulRelMajorBlockEntry % ( pxIOManager->usSectorSize / ulEntrySize );
\r
205 /*-----------------------------------------------------------*/
\r
207 FF_Error_t FF_ReleaseFATBuffers( FF_IOManager_t *pxIOManager, FF_FATBuffers_t *pxFATBuffers )
\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
215 /* 'ffconfigBUF_STORE_COUNT' equals to the number of FAT tables. */
\r
216 for( xIndex = 0; xIndex < ffconfigBUF_STORE_COUNT; xIndex++ )
\r
218 pxBuffer = pxFATBuffers->pxBuffers[ xIndex ];
\r
219 if( pxBuffer != NULL )
\r
221 FF_Error_t xTempError = FF_ERR_NONE;
\r
223 pxFATBuffers->pxBuffers[ xIndex ] = NULL;
\r
224 xTempError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
\r
225 if( FF_isERR( xError ) == pdFALSE )
\r
227 /* as everywhere, this function will return
\r
228 the first error that occurred, if any. */
\r
229 xError = xTempError;
\r
233 #if ffconfigFAT_USES_STAT
\r
235 fatStat.clearCount++;
\r
237 #endif /* ffconfigFAT_USES_STAT */
\r
241 /*-----------------------------------------------------------*/
\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
246 FF_Error_t xError = FF_ERR_NONE;
\r
247 FF_Buffer_t *pxBuffer = NULL;
\r
249 if( pxFATBuffers != NULL )
\r
251 /* See if the same buffer can be reused. */
\r
252 pxBuffer = pxFATBuffers->pxBuffers[ xBufferIndex ];
\r
254 if( pxBuffer != NULL )
\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
261 ( pxBuffer->ulSector == ulFATSector ) &&
\r
262 ( ( ( ucMode & FF_MODE_WRITE ) == 0 ) ||
\r
263 ( ( pxBuffer->ucMode & FF_MODE_WRITE ) != 0 ) )
\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
271 fatStat.reuseCount[ ( ucMode & FF_MODE_WRITE ) ? 1 : 0 ]++;
\r
273 #endif /* ffconfigFAT_USES_STAT */
\r
277 xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
\r
279 #if ffconfigFAT_USES_STAT
\r
281 fatStat.missCount[ ( ucMode & FF_MODE_WRITE ) ? 1 : 0 ]++;
\r
283 #endif /* ffconfigFAT_USES_STAT */
\r
288 #if ffconfigFAT_USES_STAT
\r
290 fatStat.getCount[ ( ucMode & FF_MODE_WRITE ) ? 1 : 0 ]++;
\r
292 #endif /* ffconfigFAT_USES_STAT */
\r
296 if( ( pxBuffer == NULL ) && ( FF_isERR( xError ) == pdFALSE ) )
\r
298 pxBuffer = FF_GetBuffer( pxIOManager, ulFATSector, ucMode );
\r
299 if( pxBuffer == NULL )
\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
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
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
327 pxBuffer = prvGetFromFATBuffers( pxIOManager, pxFATBuffers, 0, ulFATSector, &xError, ucMode );
\r
329 if( FF_isERR( xError ) )
\r
331 xError = FF_GETERROR( xError ) | FF_GETFATENTRY;
\r
335 /* Fetch the very last byte of this segment. */
\r
336 ucBytes[ 0 ] = FF_getChar( pxBuffer->pucBuffer, ( uint16_t ) ( pxIOManager->usSectorSize - 1 ) );
\r
338 xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
\r
340 /* release the other buffer as well. */
\r
341 if( ( FF_isERR( xError ) == pdFALSE ) && ( pxFATBuffers != NULL ) )
\r
343 xError = FF_ReleaseFATBuffers( pxIOManager, pxFATBuffers );
\r
346 if( FF_isERR( xError ) == pdFALSE )
\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
352 xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_GETFATENTRY );
\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
362 /* Join the two bytes: */
\r
363 ulFATEntry = ( uint32_t ) FF_getShort( ( uint8_t * )ucBytes, 0 );
\r
370 return ( int32_t ) ulFATEntry;
\r
372 #endif /* ffconfigFAT12_SUPPORT */
\r
373 /*-----------------------------------------------------------*/
\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
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
391 FF_Assert_Lock( pxIOManager, FF_FAT_LOCK );
\r
393 if( ulCluster >= pxIOManager->xPartition.ulNumClusters )
\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
401 if( pxIOManager->xPartition.ucType == FF_T_FAT32 )
\r
403 ulFATOffset = ulCluster * 4;
\r
405 else if( pxIOManager->xPartition.ucType == FF_T_FAT16 )
\r
407 ulFATOffset = ulCluster * 2;
\r
409 else /* pxIOManager->xPartition.ucType == FF_T_FAT12 */
\r
411 ulFATOffset = ulCluster + ( ulCluster / 2 );
\r
414 ulFATSector = pxIOManager->xPartition.ulFATBeginLBA + ( ulFATOffset / pxIOManager->xPartition.usBlkSize );
\r
415 ulFATSectorEntry = ulFATOffset % pxIOManager->xPartition.usBlkSize;
\r
417 ulLBAAdjust = ulFATSectorEntry / ( ( uint32_t ) pxIOManager->usSectorSize );
\r
418 ulRelClusterEntry = ulFATSectorEntry % pxIOManager->usSectorSize;
\r
420 ulFATSector = FF_getRealLBA( pxIOManager, ulFATSector );
\r
421 ulFATSector += ulLBAAdjust;
\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
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
434 if( ( ulCluster & 0x0001 ) != 0 )
\r
436 /* For odd clusters, shift the address 4 bits to the right: */
\r
437 ulFATEntry = ( ulFATEntry & 0xfff0 ) >> 4;
\r
441 /* For even clusters, take the lower 12 bits: */
\r
442 ulFATEntry = ( ulFATEntry & 0x0fff );
\r
444 /* Return ulFATEntry, unless xError contains an error. */
\r
447 #endif /* ffconfigFAT12_SUPPORT */
\r
448 if( FF_isERR( xError ) == pdFALSE )
\r
450 /* Handle FAT16, FAT32, and FAT12 (in case the entry lies on a single sector). */
\r
452 pxBuffer = prvGetFromFATBuffers( pxIOManager, pxFATBuffers, 0, ulFATSector, &xError, ucMode );
\r
453 if( FF_isERR( xError ) )
\r
455 xError = FF_GETERROR( xError ) | FF_GETFATENTRY;
\r
459 switch( pxIOManager->xPartition.ucType )
\r
462 ulFATEntry = FF_getLong( pxBuffer->pucBuffer, ulRelClusterEntry );
\r
463 /* Clear the top 4 bits. */
\r
464 ulFATEntry &= 0x0fffffff;
\r
467 ulFATEntry = ( uint32_t ) FF_getShort( pxBuffer->pucBuffer, ulRelClusterEntry );
\r
469 #if( ffconfigFAT12_SUPPORT != 0 )
\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
476 /* For odd clusters, shift the address 4 bits to the right: */
\r
477 ulFATEntry = ( ulFATEntry & 0xfff0 ) >> 4;
\r
481 /* For even clusters, take the lower 12 bits: */
\r
482 ulFATEntry = ( ulFATEntry & 0x0fff );
\r
491 if( pxFATBuffers != NULL )
\r
493 /* Store the buffer. */
\r
494 pxFATBuffers->pxBuffers[ 0 ] = pxBuffer;
\r
498 /* Or release it. */
\r
499 xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
\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
504 if( FF_isERR( xError ) )
\r
506 /* The sector address 0 is not meaningful and here it is used as the 'error value'. */
\r
510 if( pxError != NULL )
\r
515 return ( int32_t )ulFATEntry;
\r
516 } /* FF_getFATEntry() */
\r
517 /*-----------------------------------------------------------*/
\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
522 FF_Error_t xError = FF_ERR_NONE;
\r
523 FF_Buffer_t *pxBuffer = NULL;
\r
525 uint32_t ulBaseLBA;
\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
531 for( xIndex = 0; xIndex < ( BaseType_t ) pxIOManager->xPartition.ulSectorsPerCluster; xIndex++ )
\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
540 xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_CLEARCLUSTER );
\r
543 memset( pxBuffer->pucBuffer, 0x00, pxIOManager->usSectorSize );
\r
546 xError = FF_BlockWrite( pxIOManager, ulBaseLBA + xIndex, 1, pxBuffer->pucBuffer, pdFALSE );
\r
547 if( FF_isERR( xError ) )
\r
553 if( pxBuffer != NULL )
\r
555 FF_Error_t xTempError;
\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
563 if( FF_isERR( xError ) == pdFALSE )
\r
565 xError = xTempError;
\r
571 /*-----------------------------------------------------------*/
\r
575 * @brief Returns the Cluster address of the Cluster number from the beginning of a chain.
\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
584 uint32_t FF_TraverseFAT( FF_IOManager_t *pxIOManager, uint32_t ulStart, uint32_t ulCount, FF_Error_t *pxError )
\r
586 FF_Error_t xError = FF_ERR_NONE;
\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
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
599 FF_LockFAT( pxIOManager );
\r
601 for( ulIndex = 0; ulIndex < ulCount; ulIndex++ )
\r
603 ulFatEntry = FF_getFATEntry( pxIOManager, ulCurrentCluster, &xError, &xFATBuffers );
\r
604 if( FF_isERR( xError ) )
\r
610 if( FF_isEndOfChain( pxIOManager, ulFatEntry ) )
\r
612 ulFatEntry = ulCurrentCluster;
\r
616 ulCurrentCluster = ulFatEntry;
\r
620 FF_UnlockFAT( pxIOManager );
\r
624 FF_Error_t xTempError;
\r
626 xTempError = FF_ReleaseFATBuffers( pxIOManager, &xFATBuffers );
\r
627 if( FF_isERR( xError ) == pdFALSE )
\r
629 xError = xTempError;
\r
637 /*-----------------------------------------------------------*/
\r
639 uint32_t FF_FindEndOfChain( FF_IOManager_t *pxIOManager, uint32_t ulStart, FF_Error_t *pxError )
\r
641 uint32_t ulFatEntry = ulStart;
\r
644 if( FF_isEndOfChain( pxIOManager, ulStart ) == pdFALSE )
\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
652 xError = FF_ERR_NONE;
\r
659 /*-----------------------------------------------------------*/
\r
663 * @brief Tests if the ulFATEntry is an End of Chain Marker.
\r
665 * @param pxIOManager FF_IOManager_t Object
\r
666 * @param ulFATEntry The fat entry from the FAT table to be checked.
\r
668 * @return pdTRUE if it is an end of chain, otherwise pdFALSE.
\r
671 BaseType_t FF_isEndOfChain( FF_IOManager_t *pxIOManager, uint32_t ulFATEntry )
\r
673 BaseType_t xResult = pdFALSE;
\r
675 if( pxIOManager->xPartition.ucType == FF_T_FAT32 )
\r
677 if( ( ulFATEntry & 0x0fffffff ) >= 0x0ffffff8 )
\r
682 else if( pxIOManager->xPartition.ucType == FF_T_FAT16 )
\r
684 if( ulFATEntry >= 0x0000fff8 )
\r
691 if( ulFATEntry >= 0x00000ff8 )
\r
697 if( ulFATEntry == 0x00000000 )
\r
699 xResult = pdTRUE; /* Perhaps trying to read a deleted file! */
\r
704 /*-----------------------------------------------------------*/
\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
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
717 #if( ffconfigWRITE_BOTH_FATS != 0 )
\r
718 const BaseType_t xNumFATs = pxIOManager->xPartition.ucNumFATS;
\r
720 const BaseType_t xNumFATs = 1;
\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
727 if( FF_isERR( xError ) == pdFALSE )
\r
729 if( ( ulCluster & 0x0001 ) != 0 )
\r
731 ulFATEntry &= 0x000F;
\r
732 ulValue = ( ulValue << 4 );
\r
737 ulFATEntry &= 0xF000;
\r
740 ulFATEntry |= ulValue;
\r
742 /* Write at offset 0 in the array ucBytes. */
\r
743 FF_putShort( ucBytes, 0, ( uint16_t ) ulFATEntry );
\r
747 xIndex++, ulFATSector += pxIOManager->xPartition.ulSectorsPerFAT )
\r
749 /* Write the last byte in the first sector. */
\r
750 pxBuffer = FF_GetBuffer( pxIOManager, ulFATSector, FF_MODE_WRITE );
\r
752 if( pxBuffer == NULL )
\r
754 xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_PUTFATENTRY );
\r
757 FF_putChar( pxBuffer->pucBuffer, ( uint16_t )( pxIOManager->usSectorSize - 1 ), ucBytes[ 0 ] );
\r
759 xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
\r
760 if( FF_isERR( xError ) )
\r
765 /* Write the first byte in the subsequent sector. */
\r
766 pxBuffer = FF_GetBuffer( pxIOManager, ulFATSector + 1, FF_MODE_WRITE );
\r
768 if( pxBuffer == NULL )
\r
770 xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_PUTFATENTRY );
\r
773 FF_putChar( pxBuffer->pucBuffer, 0x0000, ucBytes[ 1 ] );
\r
775 xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
\r
776 if( FF_isERR( xError ) )
\r
780 } /* for ( xIndex = 0; xIndex < xNumFATs; xIndex++ ) */
\r
789 * @brief Writes a new Entry to the FAT Tables.
\r
791 * @param pxIOManager IOMAN object.
\r
792 * @param ulCluster Cluster Number to be modified.
\r
793 * @param ulValue The value to store.
\r
795 FF_Error_t FF_putFATEntry( FF_IOManager_t *pxIOManager, uint32_t ulCluster, uint32_t ulValue, FF_FATBuffers_t *pxFATBuffers )
\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
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
809 const BaseType_t xNumFATs = 1;
\r
813 FF_Assert_Lock( pxIOManager, FF_FAT_LOCK );
\r
815 /* Avoid corrupting the disk. */
\r
816 if( ( ulCluster == 0ul ) || ( ulCluster >= pxIOManager->xPartition.ulNumClusters ) )
\r
818 /* find a more specific error code. */
\r
819 xError = ( FF_Error_t ) ( FF_ERR_IOMAN_NOT_ENOUGH_FREE_SPACE | FF_PUTFATENTRY );
\r
823 if( pxIOManager->xPartition.ucType == FF_T_FAT32 )
\r
825 ulFATOffset = ulCluster * 4;
\r
827 else if( pxIOManager->xPartition.ucType == FF_T_FAT16 )
\r
829 ulFATOffset = ulCluster * 2;
\r
831 else /* pxIOManager->xPartition.ucType == FF_T_FAT12 */
\r
833 ulFATOffset = ulCluster + ( ulCluster / 2 );
\r
836 ulFATSector = pxIOManager->xPartition.ulFATBeginLBA + ( ulFATOffset / pxIOManager->xPartition.usBlkSize );
\r
837 ulFATSectorEntry = ulFATOffset % pxIOManager->xPartition.usBlkSize;
\r
839 ulLBAAdjust = ulFATSectorEntry / ( ( uint32_t ) pxIOManager->usSectorSize );
\r
840 ulRelClusterEntry = ulFATSectorEntry % pxIOManager->usSectorSize;
\r
842 ulFATSector = FF_getRealLBA( pxIOManager, ulFATSector );
\r
843 ulFATSector += ulLBAAdjust;
\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
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
857 #endif /* ffconfigFAT12_SUPPORT */
\r
858 if( FF_isERR( xError ) == pdFALSE )
\r
860 /* Handle FAT16, FAT32, and FAT12 (in case the entry lies on a single sector). */
\r
863 xIndex++, ulFATSector += pxIOManager->xPartition.ulSectorsPerFAT )
\r
865 pxBuffer = prvGetFromFATBuffers( pxIOManager, pxFATBuffers, xIndex, ulFATSector, &xError, FF_MODE_WRITE );
\r
867 if( FF_isERR( xError ) )
\r
869 xError = FF_GETERROR( xError ) | FF_PUTFATENTRY;
\r
873 if( pxIOManager->xPartition.ucType == FF_T_FAT32 )
\r
875 /* Clear the top 4 bits. */
\r
876 ulValue &= 0x0fffffff;
\r
877 FF_putLong( pxBuffer->pucBuffer, ulRelClusterEntry, ulValue );
\r
879 else if( pxIOManager->xPartition.ucType == FF_T_FAT16 )
\r
881 FF_putShort( pxBuffer->pucBuffer, ulRelClusterEntry, ( uint16_t ) ulValue );
\r
885 ulFATEntry = ( uint32_t ) FF_getShort( pxBuffer->pucBuffer, ulRelClusterEntry );
\r
886 if( ( ulCluster & 0x0001 ) != 0 )
\r
888 ulFATEntry &= 0x000F;
\r
889 ulValue = ( ulValue << 4 );
\r
894 ulFATEntry &= 0xF000;
\r
898 FF_putShort( pxBuffer->pucBuffer, ulRelClusterEntry, ( uint16_t ) ( ulFATEntry | ulValue ) );
\r
901 if( ( xIndex < ffconfigBUF_STORE_COUNT ) && ( pxFATBuffers != NULL ) )
\r
903 /* Store it for later use. */
\r
904 pxFATBuffers->pxBuffers[ xIndex ] = pxBuffer;
\r
905 pxFATBuffers->ucMode = FF_MODE_WRITE;
\r
909 xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
\r
910 if( FF_isERR( xError ) )
\r
918 /* FF_putFATEntry() returns just an error code, not an address. */
\r
920 } /* FF_putFATEntry() */
\r
921 /*-----------------------------------------------------------*/
\r
925 * @brief Finds a Free Cluster and returns its number.
\r
927 * @param pxIOManager IOMAN Object.
\r
929 * @return The number of the cluster found to be free.
\r
930 * @return 0 on error.
\r
932 #if( ffconfigFAT12_SUPPORT != 0 )
\r
933 static uint32_t prvFindFreeClusterSimple( FF_IOManager_t *pxIOManager, FF_Error_t *pxError )
\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
940 FF_InitFATBuffers( &xFATBuffers, FF_MODE_READ );
\r
942 for( ulCluster = pxIOManager->xPartition.ulLastFreeCluster;
\r
943 ulCluster < pxIOManager->xPartition.ulNumClusters;
\r
946 ulFATEntry = FF_getFATEntry( pxIOManager, ulCluster, &xError, &xFATBuffers );
\r
947 if( FF_isERR( xError ) )
\r
951 if( ulFATEntry == 0 )
\r
953 pxIOManager->xPartition.ulLastFreeCluster = ulCluster;
\r
959 FF_Error_t xTempError;
\r
961 xTempError = FF_ReleaseFATBuffers( pxIOManager, &xFATBuffers );
\r
962 if( FF_isERR( xError ) == pdFALSE )
\r
964 xError = xTempError;
\r
967 if( ( FF_isERR( xError ) == pdFALSE ) &&
\r
968 ( ulCluster == pxIOManager->xPartition.ulNumClusters ) )
\r
970 /* There is no free cluster any more. */
\r
972 xError = FF_FINDFREECLUSTER | FF_ERR_IOMAN_NOT_ENOUGH_FREE_SPACE;
\r
980 /*-----------------------------------------------------------*/
\r
982 uint32_t FF_FindFreeCluster( FF_IOManager_t *pxIOManager, FF_Error_t *pxError, BaseType_t xDoClaim )
\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
993 BaseType_t xTakeLock = FF_Has_Lock( pxIOManager, FF_FAT_LOCK ) == pdFALSE;
\r
997 FF_LockFAT( pxIOManager );
\r
1000 ulCluster = pxIOManager->xPartition.ulLastFreeCluster;
\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
1006 ulCluster = prvFindFreeClusterSimple( pxIOManager, &xError );
\r
1011 #if( ffconfigFSINFO_TRUSTED != 0 )
\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
1018 pxBuffer = FF_GetBuffer( pxIOManager, pxIOManager->xPartition.ulFSInfoLBA, FF_MODE_READ );
\r
1019 if( pxBuffer == NULL )
\r
1021 xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_FINDFREECLUSTER );
\r
1025 if( ( FF_getLong(pxBuffer->pucBuffer, 0 ) == 0x41615252 ) &&
\r
1026 ( FF_getLong(pxBuffer->pucBuffer, 484 ) == 0x61417272 ) )
\r
1028 ulCluster = FF_getLong( pxBuffer->pucBuffer, 492 );
\r
1030 xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
\r
1037 if( FF_isERR( xError ) == pdFALSE )
\r
1039 uint32_t ulFATSector;
\r
1040 uint32_t ulFATOffset;
\r
1042 ulEntriesPerSector = pxIOManager->usSectorSize / xEntrySize;
\r
1043 ulFATOffset = ulCluster * xEntrySize;
\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
1051 pxBuffer = FF_GetBuffer( pxIOManager, pxIOManager->xPartition.ulFATBeginLBA + ulFATSector, FF_MODE_READ );
\r
1052 if( pxBuffer == NULL )
\r
1054 xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_FINDFREECLUSTER );
\r
1057 for( x = ( ulCluster % ulEntriesPerSector ); x < ulEntriesPerSector; x++ )
\r
1059 /* Double-check: don't use non-existing clusters */
\r
1060 if( ulCluster >= uNumClusters )
\r
1062 xError = ( FF_Error_t ) ( FF_ERR_IOMAN_NOT_ENOUGH_FREE_SPACE | FF_FINDFREECLUSTER );
\r
1065 ulFATSectorEntry = ulFATOffset % pxIOManager->xPartition.usBlkSize;
\r
1066 if( pxIOManager->xPartition.ucType == FF_T_FAT32 )
\r
1068 ulFATEntry = FF_getLong( pxBuffer->pucBuffer, ulFATSectorEntry );
\r
1069 /* Clear the top 4 bits. */
\r
1070 ulFATEntry &= 0x0fffffff;
\r
1074 ulFATEntry = ( uint32_t ) FF_getShort( pxBuffer->pucBuffer, ulFATSectorEntry );
\r
1076 if( ulFATEntry == 0x00000000 )
\r
1078 /* Break and return 'ulCluster' */
\r
1081 ulFATOffset += xEntrySize;
\r
1084 xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
\r
1086 if( FF_isERR( xError ) )
\r
1090 if( ulFATEntry == 0x00000000 )
\r
1092 /* And break from the outer loop. */
\r
1096 if( ( FF_isERR( xError ) == pdFALSE ) &&
\r
1097 ( ulFATSector == pxIOManager->xPartition.ulSectorsPerFAT ) )
\r
1099 xError = ( FF_Error_t ) ( FF_ERR_IOMAN_NOT_ENOUGH_FREE_SPACE | FF_FINDFREECLUSTER );
\r
1101 } /* if( FF_isERR( xError ) == pdFALSE ) */
\r
1102 } /* if( pxIOManager->xPartition.ucType != FF_T_FAT12 ) */
\r
1104 if( FF_isERR( xError ) )
\r
1108 if( ( ulCluster != 0UL ) && ( xDoClaim != pdFALSE ) )
\r
1110 FF_Error_t xTempError;
\r
1112 /* Found a free cluster! */
\r
1113 pxIOManager->xPartition.ulLastFreeCluster = ulCluster + 1;
\r
1115 xTempError = FF_putFATEntry( pxIOManager, ulCluster, 0xFFFFFFFF, NULL );
\r
1116 if( FF_isERR( xError ) == pdFALSE )
\r
1118 xError = xTempError;
\r
1121 if( FF_isERR( xError ) )
\r
1128 FF_UnlockFAT( pxIOManager );
\r
1130 *pxError = xError;
\r
1133 } /* FF_FindFreeCluster */
\r
1134 /*-----------------------------------------------------------*/
\r
1138 * @brief Creates a Cluster Chain
\r
1139 * @return > 0 New created cluster
\r
1140 * @return = 0 See pxError
\r
1142 uint32_t FF_CreateClusterChain( FF_IOManager_t *pxIOManager, FF_Error_t *pxError )
\r
1144 uint32_t ulStartCluster;
\r
1145 FF_Error_t xError = FF_ERR_NONE;
\r
1147 FF_LockFAT( pxIOManager );
\r
1149 ulStartCluster = FF_FindFreeCluster( pxIOManager, &xError, pdTRUE );
\r
1151 FF_UnlockFAT( pxIOManager );
\r
1153 if( ulStartCluster != 0L )
\r
1155 xError = FF_DecreaseFreeClusters( pxIOManager, 1 );
\r
1157 *pxError = xError;
\r
1159 return ulStartCluster;
\r
1161 /*-----------------------------------------------------------*/
\r
1163 uint32_t FF_GetChainLength( FF_IOManager_t *pxIOManager, uint32_t ulStartCluster, uint32_t *pulEndOfChain, FF_Error_t *pxError )
\r
1165 uint32_t ulLength = 0;
\r
1166 FF_FATBuffers_t xFATBuffers;
\r
1167 FF_Error_t xError = FF_ERR_NONE;
\r
1169 FF_InitFATBuffers( &xFATBuffers, FF_MODE_READ );
\r
1171 FF_LockFAT( pxIOManager );
\r
1173 while( FF_isEndOfChain( pxIOManager, ulStartCluster ) == pdFALSE )
\r
1175 ulStartCluster = FF_getFATEntry( pxIOManager, ulStartCluster, &xError, &xFATBuffers );
\r
1176 if( FF_isERR( xError ) )
\r
1183 if( pulEndOfChain != NULL )
\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
1190 xError = FF_ReleaseFATBuffers( pxIOManager, &xFATBuffers );
\r
1192 FF_UnlockFAT( pxIOManager );
\r
1194 *pxError = xError;
\r
1198 /*-----------------------------------------------------------*/
\r
1202 * @brief Free's Disk space by freeing unused links on Cluster Chains
\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
1210 * @return 0 On Success.
\r
1211 * @return -1 If the device driver failed to provide access.
\r
1214 FF_Error_t FF_UnlinkClusterChain( FF_IOManager_t *pxIOManager, uint32_t ulStartCluster, BaseType_t xDoTruncate )
\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
1224 BaseType_t xTakeLock = FF_Has_Lock( pxIOManager, FF_FAT_LOCK ) == pdFALSE;
\r
1228 FF_LockFAT( pxIOManager );
\r
1231 FF_InitFATBuffers( &xFATBuffers, FF_MODE_WRITE );
\r
1233 ulFATEntry = ulStartCluster;
\r
1235 /* Free all clusters in the chain! */
\r
1236 ulCurrentCluster = ulStartCluster;
\r
1237 ulFATEntry = ulCurrentCluster;
\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
1247 if( ( xDoTruncate != pdFALSE ) && ( ulCurrentCluster == ulStartCluster ) )
\r
1249 xError = FF_putFATEntry( pxIOManager, ulCurrentCluster, 0xFFFFFFFF, &xFATBuffers );
\r
1253 xError = FF_putFATEntry( pxIOManager, ulCurrentCluster, 0x00000000, &xFATBuffers );
\r
1256 if( FF_isERR( xError ) )
\r
1261 if( ulLastFree > ulCurrentCluster )
\r
1263 ulLastFree = ulCurrentCluster;
\r
1265 ulCurrentCluster = ulFATEntry;
\r
1266 } while( FF_isEndOfChain( pxIOManager, ulFATEntry ) == pdFALSE );
\r
1268 if( FF_isERR( xError ) == pdFALSE )
\r
1270 if( pxIOManager->xPartition.ulLastFreeCluster > ulLastFree )
\r
1272 pxIOManager->xPartition.ulLastFreeCluster = ulLastFree;
\r
1276 xTempError = FF_ReleaseFATBuffers( pxIOManager, &xFATBuffers );
\r
1277 if( FF_isERR( xError ) == pdFALSE )
\r
1279 xError = xTempError;
\r
1284 FF_UnlockFAT( pxIOManager );
\r
1286 if( ulLength != 0 )
\r
1288 xTempError = FF_IncreaseFreeClusters( pxIOManager, ulLength );
\r
1289 if( FF_isERR( xError ) == pdFALSE )
\r
1291 xError = xTempError;
\r
1297 /*-----------------------------------------------------------*/
\r
1299 #if( ffconfigFAT12_SUPPORT != 0 )
\r
1300 static uint32_t prvCountFreeClustersSimple( FF_IOManager_t *pxIOManager, FF_Error_t *pxError )
\r
1302 FF_Error_t xError = FF_ERR_NONE;
\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
1309 for( ulIndex = 0; ulIndex < xTotalClusters; ulIndex++ )
\r
1311 ulFATEntry = FF_getFATEntry( pxIOManager, ulIndex, &xError, NULL );
\r
1312 if( FF_isERR( xError) )
\r
1316 if( ulFATEntry == 0UL )
\r
1322 *pxError = xError;
\r
1324 return ulFreeClusters;
\r
1327 /*-----------------------------------------------------------*/
\r
1330 uint32_t FF_CountFreeClusters( FF_IOManager_t *pxIOManager, FF_Error_t *pxError )
\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
1344 FF_LockFAT( pxIOManager );
\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
1351 ulFreeClusters = prvCountFreeClustersSimple( pxIOManager, &xError );
\r
1356 /* For FAT16 and FAT32 */
\r
1357 #if( ffconfigFSINFO_TRUSTED != 0 )
\r
1359 /* If 'ffconfigFSINFO_TRUSTED', the contents of the field 'ulFreeClusterCount' is trusted. */
\r
1360 if( pxIOManager->xPartition.ucType == FF_T_FAT32 )
\r
1362 pxBuffer = FF_GetBuffer( pxIOManager, pxIOManager->xPartition.ulFSInfoLBA, FF_MODE_READ );
\r
1363 if( pxBuffer == NULL )
\r
1365 xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_COUNTFREECLUSTERS );
\r
1369 if( ( FF_getLong( pxBuffer->pucBuffer, 0 ) == 0x41615252 ) &&
\r
1370 ( FF_getLong( pxBuffer->pucBuffer, 484 ) == 0x61417272 ) )
\r
1372 ulFreeClusters = FF_getLong( pxBuffer->pucBuffer, 488 );
\r
1374 if( ulFreeClusters != ~0ul )
\r
1376 xInfoKnown = pdTRUE;
\r
1380 ulFreeClusters = 0ul;
\r
1384 xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
\r
1387 if( xInfoKnown != pdFALSE )
\r
1389 pxIOManager->xPartition.ulFreeClusterCount = ulFreeClusters;
\r
1395 if( ( xInfoKnown == pdFALSE ) && ( pxIOManager->xPartition.usBlkSize != 0 ) )
\r
1397 if( pxIOManager->xPartition.ucType == FF_T_FAT32 )
\r
1399 ulEntriesPerSector = pxIOManager->usSectorSize / 4;
\r
1403 ulEntriesPerSector = pxIOManager->usSectorSize / 2;
\r
1405 for( ulIndex = 0; ulIndex < pxIOManager->xPartition.ulSectorsPerFAT; ulIndex++ )
\r
1407 pxBuffer = FF_GetBuffer( pxIOManager, pxIOManager->xPartition.ulFATBeginLBA + ulIndex, FF_MODE_READ );
\r
1409 if( pxBuffer == NULL )
\r
1411 xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_COUNTFREECLUSTERS );
\r
1416 /* _HT_ : FF_CountFreeClusters was a little too busy, have it call the WDT and sleep */
\r
1418 if( ( ( ulIndex + 1 ) % 32 ) == 0 )
\r
1424 for( x = 0; x < ulEntriesPerSector; x++ )
\r
1426 if( pxIOManager->xPartition.ucType == FF_T_FAT32 )
\r
1428 /* Clearing the top 4 bits. */
\r
1429 ulFATEntry = FF_getLong( pxBuffer->pucBuffer, x * 4 ) & 0x0fffffff;
\r
1433 ulFATEntry = ( uint32_t ) FF_getShort( pxBuffer->pucBuffer, x * 2 );
\r
1435 if( ulFATEntry == 0ul )
\r
1439 /* FAT table might not be cluster aligned. */
\r
1440 if( ClusterNum > pxIOManager->xPartition.ulNumClusters )
\r
1442 /* Stop counting if that's the case. */
\r
1448 xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
\r
1450 if( FF_isERR( xError ) )
\r
1454 if( ClusterNum > pxIOManager->xPartition.ulNumClusters )
\r
1456 /* Break out of 2nd loop too ^^ */
\r
1459 /* ulFreeClusters is -2 because the first 2 fat entries in the table are reserved. */
\r
1460 if( ulFreeClusters > pxIOManager->xPartition.ulNumClusters )
\r
1462 ulFreeClusters = pxIOManager->xPartition.ulNumClusters;
\r
1464 } /* for( ulIndex = 0; ulIndex < pxIOManager->xPartition.ulSectorsPerFAT; ulIndex++ ) */
\r
1470 FF_UnlockFAT( pxIOManager );
\r
1473 if( FF_isERR( xError ) )
\r
1475 ulFreeClusters = 0;
\r
1477 *pxError = xError;
\r
1479 return ulFreeClusters;
\r
1481 /*-----------------------------------------------------------*/
\r
1483 #if( ffconfig64_NUM_SUPPORT != 0 )
\r
1484 uint64_t FF_GetFreeSize( FF_IOManager_t *pxIOManager, FF_Error_t *pxError )
\r
1486 FF_Error_t xError = FF_ERR_NONE;
\r
1487 uint32_t ulFreeClusters;
\r
1488 uint64_t ulFreeSize = 0;
\r
1490 if( pxIOManager != NULL )
\r
1492 if( pxIOManager->xPartition.ulFreeClusterCount == 0ul )
\r
1494 FF_LockFAT( pxIOManager );
\r
1496 pxIOManager->xPartition.ulFreeClusterCount = FF_CountFreeClusters( pxIOManager, &xError );
\r
1498 FF_UnlockFAT( pxIOManager );
\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
1506 if( pxError != NULL )
\r
1508 *pxError = xError;
\r
1511 return ulFreeSize;
\r
1514 uint32_t FF_GetFreeSize( FF_IOManager_t *pxIOManager, FF_Error_t *pxError )
\r
1516 FF_Error_t xError = FF_ERR_NONE;
\r
1517 uint32_t ulFreeClusters;
\r
1518 uint32_t ulFreeSize = 0;
\r
1520 if( pxIOManager != NULL )
\r
1522 if( pxIOManager->xPartition.ulFreeClusterCount == 0ul )
\r
1524 FF_LockFAT( pxIOManager );
\r
1526 pxIOManager->xPartition.ulFreeClusterCount = FF_CountFreeClusters( pxIOManager, &xError );
\r
1528 FF_UnlockFAT( pxIOManager );
\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
1537 if( pxError != NULL )
\r
1539 *pxError = xError;
\r
1542 return ulFreeSize;
\r
1544 #endif /* ffconfig64_NUM_SUPPORT */
\r
1545 /*-----------------------------------------------------------*/
\r