int32_t FF_Write()

in ff_file.c [2219:2449]


int32_t FF_Write( FF_FILE * pxFile,
                  uint32_t ulElementSize,
                  uint32_t ulCount,
                  uint8_t * pucBuffer )
{
    uint32_t ulBytesLeft = ulElementSize * ulCount;
    uint32_t nBytesWritten = 0;
    uint32_t nBytesToWrite;
    FF_IOManager_t * pxIOManager;
    uint32_t ulRelBlockPos;
    uint32_t ulItemLBA;
    int32_t lResult;
    uint32_t ulSectors;
    uint32_t ulRelClusterPos;
    uint32_t ulBytesPerCluster;
    FF_Error_t xError;

    if( pxFile == NULL )
    {
        xError = ( FF_Error_t ) ( FF_ERR_NULL_POINTER | FF_READ );
    }
    else
    {
        /* Check validity of the handle and the current position within the file. */
        xError = FF_CheckValid( pxFile );

        if( FF_isERR( xError ) == pdFALSE )
        {
            if( ( pxFile->ucMode & FF_MODE_WRITE ) == 0 )
            {
                xError = ( FF_Error_t ) ( FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE | FF_WRITE );
            }
            /* Make sure a write is after the append point. */
            else if( ( pxFile->ucMode & FF_MODE_APPEND ) != 0 )
            {
                if( pxFile->ulFilePointer < pxFile->ulFileSize )
                {
                    xError = FF_Seek( pxFile, 0, FF_SEEK_END );
                }
            }
        }
    }

    if( FF_isERR( xError ) == pdFALSE )
    {
        pxIOManager = pxFile->pxIOManager;

        /* Open a do{} while( 0 ) loop to allow the use of breaks */
        do
        {
            /* Extend File for at least ulBytesLeft!
             * Handle file-space allocation
             + 1 byte because the code assumes there is always a next cluster */
            xError = FF_ExtendFile( pxFile, pxFile->ulFilePointer + ulBytesLeft + 1 );

            if( FF_isERR( xError ) )
            {
                /* On every error, break from the while( 0 ) loop. */
                break;
            }

            ulRelBlockPos = FF_getMinorBlockEntry( pxIOManager, pxFile->ulFilePointer, 1 ); /* Get the position within a block. */
            ulItemLBA = FF_SetCluster( pxFile, &xError );

            if( FF_isERR( xError ) )
            {
                break;
            }

            if( ( ulRelBlockPos + ulBytesLeft ) <= ( uint32_t ) pxIOManager->usSectorSize )
            {
                /* Bytes to write are within a block and and do not go passed the current block. */
                nBytesWritten = FF_WritePartial( pxFile, ulItemLBA, ulRelBlockPos, ulBytesLeft, pucBuffer, &xError );
                break;
            }

            /*---------- Write (memcpy) to a Sector Boundary. */
            if( ulRelBlockPos != 0 )
            {
                /* Not writing on a sector boundary, at this point the LBA is known. */
                nBytesToWrite = pxIOManager->usSectorSize - ulRelBlockPos;
                nBytesWritten = FF_WritePartial( pxFile, ulItemLBA, ulRelBlockPos, nBytesToWrite, pucBuffer, &xError );

                if( FF_isERR( xError ) )
                {
                    break;
                }

                ulBytesLeft -= nBytesWritten;
                pucBuffer += nBytesWritten;
            }

            /*---------- Write sectors, up to a Cluster Boundary. */
            ulBytesPerCluster = ( pxIOManager->xPartition.ulSectorsPerCluster * pxIOManager->usSectorSize );
            ulRelClusterPos = FF_getClusterPosition( pxIOManager, pxFile->ulFilePointer, 1 );

            if( ( ulRelClusterPos != 0 ) && ( ( ulRelClusterPos + ulBytesLeft ) >= ulBytesPerCluster ) )
            {
                /* Need to get to cluster boundary */
                ulItemLBA = FF_SetCluster( pxFile, &xError );

                if( FF_isERR( xError ) )
                {
                    break;
                }

                ulSectors = pxIOManager->xPartition.ulSectorsPerCluster - ( ulRelClusterPos / pxIOManager->usSectorSize );
                xError = FF_BlockWrite( pxIOManager, ulItemLBA, ulSectors, pucBuffer, pdFALSE );

                if( FF_isERR( xError ) )
                {
                    break;
                }

                nBytesToWrite = ulSectors * pxIOManager->usSectorSize;
                ulBytesLeft -= nBytesToWrite;
                pucBuffer += nBytesToWrite;
                nBytesWritten += nBytesToWrite;
                pxFile->ulFilePointer += nBytesToWrite;

                if( pxFile->ulFilePointer > pxFile->ulFileSize )
                {
                    pxFile->ulFileSize = pxFile->ulFilePointer;
                }
            }

            /*---------- Write entire Clusters. */
            if( ulBytesLeft >= ulBytesPerCluster )
            {
                uint32_t ulClusters;

                FF_SetCluster( pxFile, &xError );

                if( FF_isERR( xError ) )
                {
                    break;
                }

                ulClusters = ( ulBytesLeft / ulBytesPerCluster );

                xError = FF_WriteClusters( pxFile, ulClusters, pucBuffer );

                if( FF_isERR( xError ) )
                {
                    break;
                }

                nBytesToWrite = ulBytesPerCluster * ulClusters;
                ulBytesLeft -= nBytesToWrite;
                pucBuffer += nBytesToWrite;
                nBytesWritten += nBytesToWrite;
                pxFile->ulFilePointer += nBytesToWrite;

                if( pxFile->ulFilePointer > pxFile->ulFileSize )
                {
                    pxFile->ulFileSize = pxFile->ulFilePointer;
                }
            }

            /*---------- Write Remaining Blocks */
            while( ulBytesLeft >= ( uint32_t ) pxIOManager->usSectorSize )
            {
                ulSectors = ulBytesLeft / pxIOManager->usSectorSize;
                {
                    /* HT: I'd leave these pPart/ulOffset for readability... */
                    FF_Partition_t * pPart = &( pxIOManager->xPartition );
                    uint32_t ulOffset = ( pxFile->ulFilePointer / pxIOManager->usSectorSize ) % pPart->ulSectorsPerCluster;
                    uint32_t ulRemain = pPart->ulSectorsPerCluster - ulOffset;

                    if( ulSectors > ulRemain )
                    {
                        ulSectors = ulRemain;
                    }
                }

                ulItemLBA = FF_SetCluster( pxFile, &xError );

                if( FF_isERR( xError ) )
                {
                    break;
                }

                xError = FF_BlockWrite( pxIOManager, ulItemLBA, ulSectors, pucBuffer, pdFALSE );

                if( FF_isERR( xError ) )
                {
                    break;
                }

                nBytesToWrite = ulSectors * pxIOManager->usSectorSize;
                ulBytesLeft -= nBytesToWrite;
                pucBuffer += nBytesToWrite;
                nBytesWritten += nBytesToWrite;
                pxFile->ulFilePointer += nBytesToWrite;

                if( pxFile->ulFilePointer > pxFile->ulFileSize )
                {
                    pxFile->ulFileSize = pxFile->ulFilePointer;
                }
            }

            /*---------- Write (memcpy) Remaining Bytes */
            if( ulBytesLeft == 0 )
            {
                break;
            }

            ulItemLBA = FF_SetCluster( pxFile, &xError );

            if( FF_isERR( xError ) )
            {
                break;
            }

            FF_WritePartial( pxFile, ulItemLBA, 0, ulBytesLeft, pucBuffer, &xError );
            nBytesWritten += ulBytesLeft;
        }
        while( pdFALSE );
    }

    if( FF_isERR( xError ) )
    {
        lResult = xError;
    }
    else
    {
        lResult = ( int32_t ) ( nBytesWritten / ulElementSize );
    }

    return lResult;
}   /* FF_Write() */