uint32_t FF_CountFreeClusters()

in ff_fat.c [1460:1624]


uint32_t FF_CountFreeClusters( FF_IOManager_t * pxIOManager,
                               FF_Error_t * pxError )
{
    FF_Error_t xError = FF_ERR_NONE;
    FF_Buffer_t * pxBuffer;
    uint32_t ulIndex, x;
    uint32_t ulFATEntry;
    uint32_t ulEntriesPerSector;
    uint32_t ulFreeClusters = 0;
    uint32_t ClusterNum = 0;
    BaseType_t xInfoKnown = pdFALSE;
    BaseType_t xTakeLock = FF_Has_Lock( pxIOManager, FF_FAT_LOCK ) == pdFALSE;

    if( xTakeLock )
    {
        FF_LockFAT( pxIOManager );
    }

    #if ( ffconfigFAT12_SUPPORT != 0 )
        /* FAT12 tables are too small to optimise, and would make it very complicated! */
        if( pxIOManager->xPartition.ucType == FF_T_FAT12 )
        {
            ulFreeClusters = prvCountFreeClustersSimple( pxIOManager, &xError );
        }
        else
    #endif
    {
        /* For FAT16 and FAT32 */
        #if ( ffconfigFSINFO_TRUSTED != 0 )
            {
                /* If 'ffconfigFSINFO_TRUSTED', the contents of the field 'ulFreeClusterCount' is trusted. */
                if( pxIOManager->xPartition.ucType == FF_T_FAT32 )
                {
                    pxBuffer = FF_GetBuffer( pxIOManager, pxIOManager->xPartition.ulFSInfoLBA, FF_MODE_READ );

                    if( pxBuffer == NULL )
                    {
                        xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_COUNTFREECLUSTERS );
                    }
                    else
                    {
                        if( ( FF_getLong( pxBuffer->pucBuffer, 0 ) == 0x41615252 ) &&
                            ( FF_getLong( pxBuffer->pucBuffer, 484 ) == 0x61417272 ) )
                        {
                            ulFreeClusters = FF_getLong( pxBuffer->pucBuffer, 488 );

                            if( ulFreeClusters != ~0ul )
                            {
                                xInfoKnown = pdTRUE;
                            }
                            else
                            {
                                ulFreeClusters = 0ul;
                            }
                        }

                        xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
                        pxBuffer = NULL;

                        if( xInfoKnown != pdFALSE )
                        {
                            pxIOManager->xPartition.ulFreeClusterCount = ulFreeClusters;
                        }
                    }
                }
            }
        #endif /* if ( ffconfigFSINFO_TRUSTED != 0 ) */

        if( ( xInfoKnown == pdFALSE ) && ( pxIOManager->xPartition.usBlkSize != 0 ) )
        {
            if( pxIOManager->xPartition.ucType == FF_T_FAT32 )
            {
                ulEntriesPerSector = pxIOManager->usSectorSize / 4;
            }
            else
            {
                ulEntriesPerSector = pxIOManager->usSectorSize / 2;
            }

            for( ulIndex = 0; ulIndex < pxIOManager->xPartition.ulSectorsPerFAT; ulIndex++ )
            {
                pxBuffer = FF_GetBuffer( pxIOManager, pxIOManager->xPartition.ulFATBeginLBA + ulIndex, FF_MODE_READ );

                if( pxBuffer == NULL )
                {
                    xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_COUNTFREECLUSTERS );
                    break;
                }

                #if USE_SOFT_WDT
                    {
                        /* _HT_ : FF_CountFreeClusters was a little too busy, have it call the WDT and sleep */
                        clearWDT();

                        if( ( ( ulIndex + 1 ) % 32 ) == 0 )
                        {
                            FF_Sleep( 1 );
                        }
                    }
                #endif

                for( x = 0; x < ulEntriesPerSector; x++ )
                {
                    if( pxIOManager->xPartition.ucType == FF_T_FAT32 )
                    {
                        /* Clearing the top 4 bits. */
                        ulFATEntry = FF_getLong( pxBuffer->pucBuffer, x * 4 ) & 0x0fffffff;
                    }
                    else
                    {
                        ulFATEntry = ( uint32_t ) FF_getShort( pxBuffer->pucBuffer, x * 2 );
                    }

                    if( ulFATEntry == 0ul )
                    {
                        ulFreeClusters++;
                    }

                    /* FAT table might not be cluster aligned. */
                    if( ClusterNum > pxIOManager->xPartition.ulNumClusters )
                    {
                        /* Stop counting if that's the case. */
                        break;
                    }

                    ClusterNum++;
                }

                xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
                pxBuffer = NULL;

                if( FF_isERR( xError ) )
                {
                    break;
                }

                if( ClusterNum > pxIOManager->xPartition.ulNumClusters )
                {
                    /* Break out of 2nd loop too ^^ */
                    break;
                }

                /* ulFreeClusters is -2 because the first 2 fat entries in the table are reserved. */
                if( ulFreeClusters > pxIOManager->xPartition.ulNumClusters )
                {
                    ulFreeClusters = pxIOManager->xPartition.ulNumClusters;
                }
            } /* for( ulIndex = 0; ulIndex < pxIOManager->xPartition.ulSectorsPerFAT; ulIndex++ ) */
        }
    }

    if( xTakeLock )
    {
        FF_UnlockFAT( pxIOManager );
    }

    if( FF_isERR( xError ) )
    {
        ulFreeClusters = 0;
    }

    *pxError = xError;

    return ulFreeClusters;
}