/* * FreeRTOS+FAT V2.3.3 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * https://www.FreeRTOS.org * https://github.com/FreeRTOS * */ #include #include /* FreeRTOS includes. */ #include "FreeRTOS.h" #include "task.h" #include "portable.h" #include "ff_headers.h" #include "ff_sys.h" #ifndef ARRAY_SIZE #define ARRAY_SIZE( x ) ( int ) ( sizeof( x ) / sizeof( x )[ 0 ] ) #endif /* * Define a collection of 'file systems' as a simple array */ typedef struct xSYSTEM { FF_SubSystem_t xSystems[ ffconfigMAX_FILE_SYS ]; volatile BaseType_t xFileSystemCount; } ff_sys_t; static ff_sys_t file_systems; static const char rootDir[] = "/"; int FF_FS_Count( void ) { return ( int ) file_systems.xFileSystemCount; } /*-----------------------------------------------------------*/ void FF_FS_Init( void ) { memset( &file_systems, '\0', sizeof( file_systems ) ); /* There is always a root file system, even if it doesn't have a * IO manager. */ file_systems.xFileSystemCount = ( BaseType_t ) 1; /* Set to "/", second byte is already zero. */ file_systems.xSystems[ 0 ].pcPath[ 0 ] = ( char ) '/'; file_systems.xSystems[ 0 ].xPathlen = 1; } /*-----------------------------------------------------------*/ int FF_FS_Add( const char * pcPath, FF_Disk_t * pxDisk ) { int iReturn = pdFALSE; configASSERT( pxDisk ); if( *pcPath != ( char ) '/' ) { FF_PRINTF( "FF_FS_Add: Need a \"/\": '%s'\n", pcPath ); } else { BaseType_t xUseIndex = -1; size_t uxPathLength = strlen( pcPath ); vTaskSuspendAll(); { if( file_systems.xFileSystemCount == ( BaseType_t ) 0 ) { FF_FS_Init(); } if( uxPathLength == ( size_t ) 1u ) { /* This is the "/" path * and will always be put at index 0 */ xUseIndex = ( BaseType_t ) 0; } else { BaseType_t xIndex, xFreeIndex = -1; FF_SubSystem_t * pxSubSystem = file_systems.xSystems + 1; /* Skip the root entry */ for( xIndex = ( BaseType_t ) 1; xIndex < file_systems.xFileSystemCount; xIndex++, pxSubSystem++ ) { if( ( pxSubSystem->xPathlen == ( BaseType_t ) uxPathLength ) && ( memcmp( pxSubSystem->pcPath, pcPath, uxPathLength ) == 0 ) ) { /* A system is updated with a new handler. */ xUseIndex = xIndex; break; } if( ( pxSubSystem->pxManager == NULL ) && ( xFreeIndex < 0 ) ) { /* Remember the first free slot. */ xFreeIndex = xIndex; } } if( xUseIndex < ( BaseType_t ) 0 ) { if( xFreeIndex >= ( BaseType_t ) 0 ) { /* Use the first free slot. */ xUseIndex = xFreeIndex; } else if( file_systems.xFileSystemCount < ARRAY_SIZE( file_systems.xSystems ) ) { /* Fill a new entry. */ xUseIndex = file_systems.xFileSystemCount++; } } } /* uxPathLength != 1 */ if( xUseIndex >= ( BaseType_t ) 0 ) { iReturn = pdTRUE; strncpy( file_systems.xSystems[ xUseIndex ].pcPath, pcPath, sizeof( file_systems.xSystems[ xUseIndex ].pcPath ) ); file_systems.xSystems[ xUseIndex ].xPathlen = uxPathLength; file_systems.xSystems[ xUseIndex ].pxManager = pxDisk->pxIOManager; } } xTaskResumeAll(); if( iReturn == pdFALSE ) { FF_PRINTF( "FF_FS_Add: Table full '%s' (max = %d)\n", pcPath, ( int ) ARRAY_SIZE( file_systems.xSystems ) ); } } return iReturn; } /*-----------------------------------------------------------*/ void FF_FS_Remove( const char * pcPath ) { BaseType_t xUseIndex, xIndex; size_t uxPathLength; if( pcPath[ 0 ] == ( char ) '/' ) { xUseIndex = -1; uxPathLength = strlen( pcPath ); /* Is it the "/" path ? */ if( uxPathLength == ( size_t ) 1u ) { xUseIndex = 0; } else { FF_SubSystem_t * pxSubSystem = file_systems.xSystems + 1; for( xIndex = 1; xIndex < file_systems.xFileSystemCount; xIndex++, pxSubSystem++ ) { if( ( pxSubSystem->xPathlen == ( BaseType_t ) uxPathLength ) && ( memcmp( pxSubSystem->pcPath, pcPath, uxPathLength ) == 0 ) ) { xUseIndex = xIndex; break; } } } if( xUseIndex >= 0 ) { vTaskSuspendAll(); { file_systems.xSystems[ xUseIndex ].pxManager = NULL; file_systems.xSystems[ xUseIndex ].xPathlen = ( BaseType_t ) 0; for( xIndex = file_systems.xFileSystemCount - 1; xIndex > 0; xIndex-- ) { if( file_systems.xSystems[ xIndex ].pxManager != NULL ) { /* The slot at 'xIndex' is still in use. */ break; } } file_systems.xFileSystemCount = xIndex + 1; } xTaskResumeAll(); } } } /*-----------------------------------------------------------*/ int FF_FS_Find( const char * pcPath, FF_DirHandler_t * pxHandler ) { FF_SubSystem_t * pxSubSystem; size_t uxPathLength; BaseType_t xUseIndex; int iReturn; pxSubSystem = file_systems.xSystems + 1; uxPathLength = strlen( pcPath ); memset( pxHandler, '\0', sizeof( *pxHandler ) ); for( xUseIndex = 1; xUseIndex < file_systems.xFileSystemCount; xUseIndex++, pxSubSystem++ ) { if( ( uxPathLength >= ( size_t ) pxSubSystem->xPathlen ) && ( memcmp( pxSubSystem->pcPath, pcPath, ( size_t ) pxSubSystem->xPathlen ) == 0 ) && ( ( pcPath[ pxSubSystem->xPathlen ] == '\0' ) || ( pcPath[ pxSubSystem->xPathlen ] == '/' ) ) ) /* System "/ram" should not match with "/ramc/etc". */ { if( pcPath[ pxSubSystem->xPathlen ] == '\0' ) { pxHandler->pcPath = rootDir; } else { pxHandler->pcPath = pcPath + pxSubSystem->xPathlen; } pxHandler->pxManager = pxSubSystem->pxManager; break; } } if( xUseIndex == file_systems.xFileSystemCount ) { pxHandler->pcPath = pcPath; pxHandler->pxManager = file_systems.xSystems[ 0 ].pxManager; } if( FF_Mounted( pxHandler->pxManager ) ) { iReturn = pdTRUE; } else { iReturn = pdFALSE; } return iReturn; } /*-----------------------------------------------------------*/ int FF_FS_Get( int xIndex, FF_SubSystem_t * pxSystem ) { int iReturn; /* Get a copy of a fs info. */ if( ( xIndex < 0 ) || ( xIndex >= file_systems.xFileSystemCount ) ) { iReturn = pdFALSE; } else { /* Note: it will copy the contents of 'FF_SubSystem_t'. */ *pxSystem = file_systems.xSystems[ xIndex ]; iReturn = pdTRUE; } return iReturn; } /*-----------------------------------------------------------*/