in ff_fat.c [1073:1242]
uint32_t FF_FindFreeCluster( FF_IOManager_t * pxIOManager,
FF_Error_t * pxError,
BaseType_t xDoClaim )
{
FF_Error_t xError = FF_ERR_NONE;
FF_Buffer_t * pxBuffer = NULL;
uint32_t x, ulCluster;
uint32_t ulFATSectorEntry;
uint32_t ulEntriesPerSector;
uint32_t ulFATEntry = 1;
const BaseType_t xEntrySize = ( pxIOManager->xPartition.ucType == FF_T_FAT32 ) ? 4 : 2;
const uint32_t uNumClusters = pxIOManager->xPartition.ulNumClusters;
BaseType_t xTakeLock = FF_Has_Lock( pxIOManager, FF_FAT_LOCK ) == pdFALSE;
if( xTakeLock )
{
FF_LockFAT( pxIOManager );
}
ulCluster = pxIOManager->xPartition.ulLastFreeCluster;
#if ( ffconfigFAT12_SUPPORT != 0 )
/* FAT12 tables are too small to optimise, and would make it very complicated! */
if( pxIOManager->xPartition.ucType == FF_T_FAT12 )
{
ulCluster = prvFindFreeClusterSimple( pxIOManager, &xError );
}
else
#endif
{
#if ( ffconfigFSINFO_TRUSTED != 0 )
{
/* If 'ffconfigFSINFO_TRUSTED', the contents of the field 'ulLastFreeCluster' is trusted.
* Only ready it in case of FAT32 and only during the very first time, i.e. when
* ulLastFreeCluster is still zero. */
if( ( pxIOManager->xPartition.ucType == FF_T_FAT32 ) && ( pxIOManager->xPartition.ulLastFreeCluster == 0ul ) )
{
pxBuffer = FF_GetBuffer( pxIOManager, pxIOManager->xPartition.ulFSInfoLBA, FF_MODE_READ );
if( pxBuffer == NULL )
{
xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_FINDFREECLUSTER );
}
else
{
if( ( FF_getLong( pxBuffer->pucBuffer, 0 ) == 0x41615252 ) &&
( FF_getLong( pxBuffer->pucBuffer, 484 ) == 0x61417272 ) )
{
ulCluster = FF_getLong( pxBuffer->pucBuffer, 492 );
}
xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
pxBuffer = NULL;
}
}
}
#endif /* if ( ffconfigFSINFO_TRUSTED != 0 ) */
if( FF_isERR( xError ) == pdFALSE )
{
uint32_t ulFATSector;
uint32_t ulFATOffset;
ulEntriesPerSector = pxIOManager->usSectorSize / xEntrySize;
ulFATOffset = ulCluster * xEntrySize;
/* Start from a sector where the first free entry is expected,
* and iterate through every FAT sector. */
for( ulFATSector = ( ulFATOffset / pxIOManager->xPartition.usBlkSize );
ulFATSector < pxIOManager->xPartition.ulSectorsPerFAT;
ulFATSector++ )
{
pxBuffer = FF_GetBuffer( pxIOManager, pxIOManager->xPartition.ulFATBeginLBA + ulFATSector, FF_MODE_READ );
if( pxBuffer == NULL )
{
xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_FINDFREECLUSTER );
break;
}
for( x = ( ulCluster % ulEntriesPerSector ); x < ulEntriesPerSector; x++ )
{
/* Double-check: don't use non-existing clusters */
if( ulCluster >= uNumClusters )
{
xError = ( FF_Error_t ) ( FF_ERR_IOMAN_NOT_ENOUGH_FREE_SPACE | FF_FINDFREECLUSTER );
break;
}
ulFATSectorEntry = ulFATOffset % pxIOManager->xPartition.usBlkSize;
if( pxIOManager->xPartition.ucType == FF_T_FAT32 )
{
ulFATEntry = FF_getLong( pxBuffer->pucBuffer, ulFATSectorEntry );
/* Clear the top 4 bits. */
ulFATEntry &= 0x0fffffff;
}
else
{
ulFATEntry = ( uint32_t ) FF_getShort( pxBuffer->pucBuffer, ulFATSectorEntry );
}
if( ulFATEntry == 0x00000000 )
{
/* Break and return 'ulCluster' */
break;
}
ulFATOffset += xEntrySize;
ulCluster++;
}
xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
pxBuffer = NULL;
if( FF_isERR( xError ) )
{
break;
}
if( ulFATEntry == 0x00000000 )
{
/* And break from the outer loop. */
break;
}
}
if( ( FF_isERR( xError ) == pdFALSE ) &&
( ulFATSector == pxIOManager->xPartition.ulSectorsPerFAT ) )
{
xError = ( FF_Error_t ) ( FF_ERR_IOMAN_NOT_ENOUGH_FREE_SPACE | FF_FINDFREECLUSTER );
}
} /* if( FF_isERR( xError ) == pdFALSE ) */
} /* if( pxIOManager->xPartition.ucType != FF_T_FAT12 ) */
if( FF_isERR( xError ) )
{
ulCluster = 0UL;
}
if( ( ulCluster != 0UL ) && ( xDoClaim != pdFALSE ) )
{
FF_Error_t xTempError;
/* Found a free cluster! */
pxIOManager->xPartition.ulLastFreeCluster = ulCluster + 1;
xTempError = FF_putFATEntry( pxIOManager, ulCluster, 0xFFFFFFFF, NULL );
if( FF_isERR( xError ) == pdFALSE )
{
xError = xTempError;
}
if( FF_isERR( xError ) )
{
ulCluster = 0UL;
}
}
if( xTakeLock )
{
FF_UnlockFAT( pxIOManager );
}
*pxError = xError;
return ulCluster;
} /* FF_FindFreeCluster */