uint32_t FF_FindFreeCluster()

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 */