static FF_Error_t FF_ExtendFile()

in ff_file.c [1291:1474]


static FF_Error_t FF_ExtendFile( FF_FILE * pxFile,
                                 uint32_t ulSize )
{
    FF_IOManager_t * pxIOManager = pxFile->pxIOManager;
    uint32_t ulBytesPerCluster = pxIOManager->xPartition.usBlkSize * pxIOManager->xPartition.ulSectorsPerCluster;
    uint32_t ulTotalClustersNeeded = ( ulSize + ulBytesPerCluster - 1 ) / ulBytesPerCluster;
    uint32_t ulClusterToExtend;
/* Initialise xIndex just for the compiler. */
    BaseType_t xIndex = 0;
    FF_DirEnt_t xOriginalEntry;
    FF_Error_t xError = FF_ERR_NONE;
    FF_FATBuffers_t xFATBuffers;

    if( ( pxFile->ucMode & FF_MODE_WRITE ) != FF_MODE_WRITE )
    {
        xError = ( FF_Error_t ) ( FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE | FF_EXTENDFILE );
    }
    else
    {
        if( ( pxFile->ulFileSize == 0 ) && ( pxFile->ulObjectCluster == 0 ) )
        {
            /* If there is no object cluster yet, create it.*/
            pxFile->ulAddrCurrentCluster = FF_CreateClusterChain( pxFile->pxIOManager, &xError );

            if( FF_isERR( xError ) == pdFALSE )
            {
                /* The directory denotes the address of the first data cluster of every file.
                 * Now change it to 'ulAddrCurrentCluster': */
                xError = FF_GetEntry( pxIOManager, pxFile->usDirEntry, pxFile->ulDirCluster, &xOriginalEntry );

                if( FF_isERR( xError ) == pdFALSE )
                {
                    xOriginalEntry.ulObjectCluster = pxFile->ulAddrCurrentCluster;
                    xError = FF_PutEntry( pxIOManager, pxFile->usDirEntry, pxFile->ulDirCluster, &xOriginalEntry, NULL );

                    if( FF_isERR( xError ) == pdFALSE )
                    {
                        pxFile->ulObjectCluster = pxFile->ulAddrCurrentCluster;
                        pxFile->ulChainLength = 1;
                        pxFile->ulCurrentCluster = 0;
                        pxFile->ulEndOfChain = pxFile->ulAddrCurrentCluster;
                    }
                }
            }
        }
        else
        {
            /* This file already has at least one cluster. */
        }
    }

    if( FF_isERR( xError ) == pdFALSE )
    {
        if( pxFile->ulChainLength == 0 )
        {
            /* This is the first extension requiring the chain length.
             * Calculate it now: */
            pxFile->ulChainLength = FF_GetChainLength( pxIOManager, pxFile->ulObjectCluster, &pxFile->ulEndOfChain, &xError );
        }
    }

    if( ( FF_isERR( xError ) == pdFALSE ) && ( ulTotalClustersNeeded > pxFile->ulChainLength ) )
    {
        uint32_t ulCurrentCluster, ulNextCluster;

        ulClusterToExtend = ( ulTotalClustersNeeded - pxFile->ulChainLength );
        /* Now the file has at least 1 cluster, but it needs more clusters. */
        ulNextCluster = pxFile->ulAddrCurrentCluster;
        FF_LockFAT( pxIOManager );

        ulCurrentCluster = FF_FindEndOfChain( pxIOManager, ulNextCluster, &xError );

        if( FF_isERR( xError ) == pdFALSE )
        {
            for( xIndex = 0; xIndex < ( BaseType_t ) ulClusterToExtend; xIndex++ )
            {
                /* In FF_ExtendFile() */
                ulNextCluster = FF_FindFreeCluster( pxIOManager, &xError, pdTRUE );

                if( ( FF_isERR( xError ) == pdFALSE ) && ( ulNextCluster == 0UL ) )
                {
                    xError = ( FF_Error_t ) ( FF_ERR_FAT_NO_FREE_CLUSTERS | FF_EXTENDFILE );
                }

                if( FF_isERR( xError ) )
                {
                    break;
                }

                /* Can not use this buffer earlier because of FF_FindEndOfChain/FF_FindFreeCluster */
                FF_InitFATBuffers( &xFATBuffers, FF_MODE_WRITE );
                xError = FF_putFATEntry( pxIOManager, ulCurrentCluster, ulNextCluster, &xFATBuffers );

                if( FF_isERR( xError ) )
                {
                    break;
                }

                xError = FF_ReleaseFATBuffers( pxIOManager, &xFATBuffers );

                if( FF_isERR( xError ) )
                {
                    break;
                }

                ulCurrentCluster = ulNextCluster;
            }

            if( FF_isERR( xError ) == pdFALSE )
            {
                pxFile->ulEndOfChain = ulCurrentCluster;
            }

            pxFile->ulChainLength += xIndex;
        }

        FF_UnlockFAT( pxIOManager );

        {
            FF_Error_t xTempError;
            xTempError = FF_DecreaseFreeClusters( pxIOManager, ( uint32_t ) xIndex );   /* Keep Tab of Numbers for fast FreeSize() */

            if( FF_isERR( xError ) == pdFALSE )
            {
                xError = xTempError;
            }
        }

        /* We must ensure that the ulAddrCurrentCluster is not out-of-sync with the CurrentCluster number.
         * This could have occurred in append mode, where the file was opened with a filesize % clustersize == 0
         * because of a seek, where the ulAddrCurrentCluster was not updated after extending. This caused the data to
         * be written to the previous cluster(s). */
        if( ( pxFile->ulCurrentCluster == pxFile->ulChainLength - 1 ) &&
            ( pxFile->ulAddrCurrentCluster != pxFile->ulEndOfChain ) )
        {
            pxFile->ulAddrCurrentCluster = pxFile->ulEndOfChain;
        }

        /* By default, 'ffconfigFILE_EXTEND_FLUSHES_BUFFERS' is
         * defined as 1.
         * Users may set it to zero in order to increase the
         * speed of writing to disk. */

        #if ( ffconfigFILE_EXTEND_FLUSHES_BUFFERS != 0 )
            {
                FF_Error_t xTempError;

                xTempError = FF_FlushCache( pxIOManager );

                if( FF_isERR( xError ) == pdFALSE )
                {
                    xError = xTempError;
                }
            }
        #endif /* ffconfigFILE_EXTEND_FLUSHES_BUFFERS */

        if( pxFile->ulFilePointer == pxFile->ulFileSize )
        {
            /* Writing at the end of a file, while new clusters have just been added.
             * Make sure that the fields 'ulCurrentCluster' and 'ulAddrCurrentCluster' are
             * set correctly.
             */
            if( ( pxFile->ulValidFlags & FF_VALID_FLAG_EXTENDED ) == 0U )
            {
                pxFile->ulValidFlags |= FF_VALID_FLAG_EXTENDED;
                FF_Error_t xTempError = FF_ERR_NONE;
                uint32_t ulNewCluster = FF_getClusterChainNumber( pxIOManager, pxFile->ulFilePointer, 1 );
                FF_LockFAT( pxIOManager );
                {
                    pxFile->ulAddrCurrentCluster = FF_TraverseFAT( pxIOManager, pxFile->ulObjectCluster, ulNewCluster, &( xTempError ) );
                    pxFile->ulCurrentCluster = ulNewCluster;
                }
                FF_UnlockFAT( pxIOManager );

                if( FF_isERR( xError ) == pdFALSE )
                {
                    xError = xTempError;
                }
            }
        }
    } /* if( ulTotalClustersNeeded > pxFile->ulChainLength ) */

    return xError;
}   /* FF_ExtendFile() */