| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174 |
- /*
- * 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
- *
- */
- /* FreeRTOS includes. */
- #include "FreeRTOS.h"
- #include "task.h"
- #include "portable.h"
- /* FreeRTOS+FAT includes. */
- #include "ff_headers.h"
- #include "ff_stdio.h"
- #if ( ffconfigTIME_SUPPORT != 0 )
- #include <time.h>
- #endif
- #ifndef SIZE_MAX
- #define SIZE_MAX ( ( size_t ) -1 )
- #endif
- /* The number of bytes to write at a time when extending the length of a file
- * in a call to ff_truncate(). */
- #define stdioTRUNCATE_WRITE_LENGTH 512
- /* Bits set to indicate whether ".." should be included as well as ".". */
- #define stdioDIR_ENTRY_DOT_1 ( 1U & 0x03U )
- #define stdioDIR_ENTRY_DOT_2 ( 2U & 0x03U )
- /* The directory entries '.' and '..' will show a file size of 1 KB. */
- #define stdioDOT_ENTRY_FILE_SIZE 1024
- /*-----------------------------------------------------------*/
- /*
- * Add the CWD to the beginning of a relative path, and copy the resultant
- * absolute path into a thread local non const buffer.
- */
- /*static*/ const char * prvABSPath( const char * pcPath );
- /*
- * Translate a +FAT error to a value compatible with errno.h
- * If the value represents an error, it is negative
- * The return value of this function will always be positive
- */
- int prvFFErrorToErrno( FF_Error_t xError );
- /*
- * Generate a time stamp for the file.
- */
- #if ( ffconfigTIME_SUPPORT == 1 )
- static uint32_t prvFileTime( FF_SystemTime_t * pxTime );
- #endif
- #if ( ffconfigHAS_CWD == 1 )
- /* FreeRTOS+FAT requires two thread local storage pointers. One for errno
- * and one for the CWD structure. */
- #if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS < 2 )
- #error FreeRTOS+FAT requires two thread local storage pointers so configNUM_THREAD_LOCAL_STORAGE_POINTERS must be at least 2 in FreeRTOSConfig.h
- #endif
- /* Each task has its own Current Working Directory (CWD). The CWD is used
- * to extend relative paths to absolute paths. */
- typedef struct WORKING_DIR
- {
- char pcCWD[ ffconfigMAX_FILENAME ]; /* The current working directory. */
- char pcFileName[ ffconfigMAX_FILENAME ]; /* The created absolute path. */
- } WorkingDirectory_t;
- /*
- * Lookup the CWD of the current task.
- */
- static WorkingDirectory_t * pxFindCWD( void );
- /*
- * Convert a string which may contain a relative path into a string that
- * will only contain an absolute path.
- */
- static const char * prvProcessRelativePaths( const char * pcPath );
- #else /* ffconfigHAS_CWD */
- /* FreeRTOS+FAT requires one thread local storage pointers for errno. */
- #if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS < 2 )
- #error FreeRTOS+FAT requires one thread local storage pointers so configNUM_THREAD_LOCAL_STORAGE_POINTERS must be at least 1 in FreeRTOSConfig.h
- #endif
- /* Only absolute paths are supported so define away the prvABSPath()
- * function. */
- /*static*/ const char * prvABSPath( const char * pcPath )
- {
- return pcPath;
- }
- #endif /* ffconfigHAS_CWD */
- #if ( ffconfigUSE_DELTREE != 0 )
- /*
- * Remove all files and directories starting from a certain path.
- * This function uses recursion - which breaches the coding standard. USE
- * WITH CARE.
- */
- static int ff_deltree_recurse( char * pcPath );
- #endif
- /*-----------------------------------------------------------*/
- FF_FILE * ff_fopen( const char * pcFile,
- const char * pcMode )
- {
- FF_FILE * pxStream = NULL;
- FF_DirHandler_t xHandler;
- FF_Error_t xError;
- uint8_t ucMode;
- /* Insert the current working directory in front of relative paths. */
- pcFile = prvABSPath( pcFile );
- /* Look-up the I/O manager for the file system. */
- if( FF_FS_Find( pcFile, &xHandler ) == pdFALSE )
- {
- stdioSET_ERRNO( pdFREERTOS_ERRNO_ENXIO ); /* No such device or address. */
- }
- else
- {
- /* Now 'xHandler.pcPath' contains an absolute path within the file system.
- * Translate a type string "r|w|a[+]" to +FAT's mode bits. */
- ucMode = FF_GetModeBits( pcMode );
- pxStream = FF_Open( xHandler.pxManager, xHandler.pcPath, ucMode, &xError );
- stdioSET_ERRNO( prvFFErrorToErrno( xError ) );
- #if ( ffconfigUSE_NOTIFY != 0 )
- {
- if( ( pxStream != NULL ) && ( ( ucMode & ( FF_MODE_WRITE | FF_MODE_APPEND ) ) != 0 ) )
- {
- /*_RB_ Function name needs updating. */
- callFileEvents( pcFile, eFileCreate );
- }
- }
- #endif /* ffconfigUSE_NOTIFY */
- #if ( ffconfigDEV_SUPPORT != 0 )
- {
- if( pxStream != NULL )
- {
- FF_Device_Open( pcFile, pxStream );
- }
- }
- #endif /* ffconfigDEV_SUPPORT */
- }
- return pxStream;
- }
- /*-----------------------------------------------------------*/
- int ff_fclose( FF_FILE * pxStream )
- {
- FF_Error_t xError;
- int iReturn, ff_errno;
- #if ( ffconfigDEV_SUPPORT != 0 )
- {
- /* Currently device support is in an experimental state. It will allow
- * to create virtual files. The I/O data to those files will be redirected
- * to their connected "drivers". */
- if( pxStream != NULL )
- {
- FF_Device_Close( pxStream );
- }
- }
- #endif
- xError = FF_Close( pxStream );
- ff_errno = prvFFErrorToErrno( xError );
- if( ff_errno == 0 )
- {
- iReturn = 0;
- }
- else
- {
- /* Return -1 for error as per normal fclose() semantics. */
- iReturn = -1;
- }
- /* Store the errno to thread local storage. */
- stdioSET_ERRNO( ff_errno );
- return iReturn;
- }
- /*-----------------------------------------------------------*/
- int ff_fseek( FF_FILE * pxStream,
- long lOffset,
- int iWhence )
- {
- FF_Error_t xError;
- int iReturn, ff_errno;
- #if ( ffconfigDEV_SUPPORT != 0 )
- if( pxStream->pxDevNode != NULL )
- {
- xError = FF_Device_Seek( pxStream, lOffset, iWhence );
- }
- else
- #endif
- {
- xError = FF_Seek( pxStream, lOffset, iWhence );
- }
- ff_errno = prvFFErrorToErrno( xError );
- if( ff_errno == 0 )
- {
- iReturn = 0;
- }
- else
- {
- if( xError == FF_ERR_FILE_SEEK_INVALID_POSITION )
- {
- /* Illegal position, outside the file's space */
- ff_errno = pdFREERTOS_ERRNO_ESPIPE;
- }
- else if( xError == FF_ERR_FILE_SEEK_INVALID_ORIGIN )
- {
- /* Illegal parameter value for iWhence: SET,CUR,END. */
- ff_errno = pdFREERTOS_ERRNO_EINVAL;
- }
- /* Return -1 for error as per normal fseek() semantics. */
- iReturn = -1;
- }
- /* Store the errno to thread local storage. */
- stdioSET_ERRNO( ff_errno );
- return iReturn;
- }
- /*-----------------------------------------------------------*/
- void ff_rewind( FF_FILE * pxStream )
- {
- ff_fseek( pxStream, 0, FF_SEEK_SET );
- /* Rewind is supposed to reset errno unconditionally. Store the errno to
- * thread local storage. */
- stdioSET_ERRNO( 0 );
- }
- /*-----------------------------------------------------------*/
- long ff_ftell( FF_FILE * pxStream )
- {
- long lResult;
- if( pxStream == NULL )
- {
- /* Store the errno to thread local storage. */
- stdioSET_ERRNO( pdFREERTOS_ERRNO_EBADF );
- /* Return -1 for error as per normal ftell() semantics. */
- lResult = -1;
- }
- else
- {
- lResult = ( long ) pxStream->ulFilePointer;
- }
- return lResult;
- }
- /*-----------------------------------------------------------*/
- int ff_feof( FF_FILE * pxStream )
- {
- int iResult;
- FF_Error_t xError;
- xError = FF_CheckValid( pxStream );
- if( FF_isERR( xError ) == pdFALSE )
- {
- /* Store the errno to thread local storage. */
- stdioSET_ERRNO( 0 );
- if( pxStream->ulFilePointer >= pxStream->ulFileSize )
- {
- iResult = pdTRUE;
- }
- else
- {
- iResult = pdFALSE;
- }
- }
- else
- {
- /* Store the errno to thread local storage. */
- stdioSET_ERRNO( prvFFErrorToErrno( xError ) );
- /* The file was invalid so a non-zero value cannot be returned. */
- iResult = pdFALSE;
- }
- return iResult;
- }
- /*-----------------------------------------------------------*/
- size_t ff_fread( void * pvBuffer,
- size_t xSize,
- size_t xItems,
- FF_FILE * pxStream )
- {
- int32_t iReturned;
- size_t xReturn;
- int ff_errno;
- #if ( ffconfigDEV_SUPPORT != 0 )
- if( pxStream->pxDevNode != NULL )
- {
- iReturned = FF_Device_Read( pvBuffer, xSize, xItems, pxStream );
- }
- else
- #endif
- {
- iReturned = FF_Read( pxStream, xSize, xItems, ( uint8_t * ) pvBuffer );
- }
- ff_errno = prvFFErrorToErrno( iReturned );
- if( ff_errno == pdFREERTOS_ERRNO_NONE )
- {
- /* As per the standard fread() semantics, the return value is the number
- * of complete items read, which will only equal the number of bytes
- * transferred when the item size is 1. */
- xReturn = ( size_t ) iReturned;
- }
- else
- {
- xReturn = 0;
- }
- /* Store the errno to thread local storage. */
- stdioSET_ERRNO( ff_errno );
- return xReturn;
- }
- /*-----------------------------------------------------------*/
- size_t ff_fwrite( const void * pvBuffer,
- size_t xSize,
- size_t xItems,
- FF_FILE * pxStream )
- {
- int32_t iReturned;
- size_t xReturn;
- int ff_errno;
- #if ( ffconfigDEV_SUPPORT != 0 )
- if( pxStream->pxDevNode != NULL )
- {
- iReturned = FF_Device_Write( pvBuffer, xSize, xItems, pxStream );
- }
- else
- #endif
- {
- iReturned = FF_Write( pxStream, xSize, xItems, ( uint8_t * ) pvBuffer );
- }
- ff_errno = prvFFErrorToErrno( iReturned );
- if( ff_errno == pdFREERTOS_ERRNO_NONE )
- {
- /* As per the standard fwrite() semantics, the return value is the
- * number of complete items read, which will only equal the number of bytes
- * transferred when the item size is 1. */
- xReturn = ( size_t ) iReturned;
- }
- else
- {
- xReturn = 0;
- }
- /* Store the errno to thread local storage. */
- stdioSET_ERRNO( ff_errno );
- return xReturn;
- }
- /*-----------------------------------------------------------*/
- int ff_fgetc( FF_FILE * pxStream )
- {
- int32_t iResult;
- int ff_errno;
- iResult = FF_GetC( pxStream );
- ff_errno = prvFFErrorToErrno( iResult );
- if( ff_errno != 0 )
- {
- iResult = FF_EOF;
- }
- /* Store the errno to thread local storage. */
- stdioSET_ERRNO( ff_errno );
- return iResult;
- }
- /*-----------------------------------------------------------*/
- int ff_fputc( int iChar,
- FF_FILE * pxStream )
- {
- int iResult, ff_errno;
- iResult = FF_PutC( pxStream, ( uint8_t ) iChar );
- ff_errno = prvFFErrorToErrno( iResult );
- if( ff_errno != 0 )
- {
- iResult = FF_EOF;
- }
- /* Store the errno to thread local storage. */
- stdioSET_ERRNO( ff_errno );
- return iResult;
- }
- /*-----------------------------------------------------------*/
- #if ( ffconfigFPRINTF_SUPPORT == 1 )
- int ff_fprintf( FF_FILE * pxStream,
- const char * pcFormat,
- ... )
- {
- int iCount;
- size_t xResult;
- char * pcBuffer;
- va_list xArgs;
- pcBuffer = ( char * ) ffconfigMALLOC( ffconfigFPRINTF_BUFFER_LENGTH );
- if( pcBuffer == NULL )
- {
- /* Store the errno to thread local storage. */
- stdioSET_ERRNO( pdFREERTOS_ERRNO_ENOMEM );
- iCount = -1;
- }
- else
- {
- va_start( xArgs, pcFormat );
- iCount = vsnprintf( pcBuffer, ffconfigFPRINTF_BUFFER_LENGTH, pcFormat, xArgs );
- va_end( xArgs );
- /* ff_fwrite() will set ff_errno. */
- if( iCount > 0 )
- {
- xResult = ff_fwrite( pcBuffer, ( size_t ) 1, ( size_t ) iCount, pxStream );
- if( xResult < ( size_t ) iCount )
- {
- iCount = -1;
- }
- }
- ffconfigFREE( pcBuffer );
- }
- return iCount;
- }
- #endif /* if ( ffconfigFPRINTF_SUPPORT == 1 ) */
- /*-----------------------------------------------------------*/
- /*_RB_ to comply with the norm, the second parameter should be an int, but size_t
- * is more appropriate. */
- char * ff_fgets( char * pcBuffer,
- size_t xCount,
- FF_FILE * pxStream )
- {
- int32_t xResult;
- int ff_errno;
- xResult = FF_GetLine( pxStream, ( char * ) pcBuffer, xCount );
- /* This call seems to result in errno being incorrectly set to
- * FF_ERR_IOMAN_NO_MOUNTABLE_PARTITION when an EOF is encountered. */
- ff_errno = prvFFErrorToErrno( xResult );
- if( ff_errno != 0 )
- {
- pcBuffer = NULL;
- }
- /* Store the errno to thread local storage. */
- stdioSET_ERRNO( ff_errno );
- return pcBuffer;
- }
- /*-----------------------------------------------------------*/
- int ff_seteof( FF_FILE * pxStream )
- {
- FF_Error_t iResult;
- int iReturn, ff_errno;
- iResult = FF_SetEof( pxStream );
- ff_errno = prvFFErrorToErrno( iResult );
- if( ff_errno == 0 )
- {
- iReturn = 0;
- }
- else
- {
- iReturn = FF_EOF;
- }
- /* Store the errno to thread local storage. */
- stdioSET_ERRNO( ff_errno );
- return iReturn;
- }
- /*-----------------------------------------------------------*/
- /*_RB_ The norm would be to return an int, but in either case it is not clear
- * what state the file is left in (open/closed). */
- FF_FILE * ff_truncate( const char * pcFileName,
- long lTruncateSize )
- {
- FF_Error_t xResult = 0;
- FF_FILE * pxStream;
- size_t xReturned;
- uint32_t ulLength, ulBytesLeftToAdd, ulBytesToWrite;
- char * pcBufferToWrite;
- pxStream = ff_fopen( pcFileName, "a+" );
- if( pxStream != NULL )
- {
- ulLength = pxStream->ulFileSize;
- }
- else
- {
- ulLength = 0;
- }
- if( pxStream == NULL )
- {
- /* Store the errno to thread local storage. */
- stdioSET_ERRNO( prvFFErrorToErrno( xResult ) );
- }
- else if( ulLength > ( uint32_t ) lTruncateSize )
- {
- /* Seek the desired position */
- xResult = FF_Seek( pxStream, lTruncateSize, FF_SEEK_SET );
- /* Make the current position equal to its length */
- if( FF_isERR( xResult ) == pdFALSE )
- {
- xResult = FF_SetEof( pxStream );
- }
- if( FF_isERR( xResult ) != pdFALSE )
- {
- ff_fclose( pxStream );
- pxStream = NULL;
- }
- /* Store the errno to thread local storage. */
- stdioSET_ERRNO( prvFFErrorToErrno( xResult ) );
- }
- else if( ulLength == ( uint32_t ) lTruncateSize )
- {
- /* Nothing to do, the file has the desired size
- * and the open handle will be returned. */
- }
- else
- {
- /* lTruncateSize > ulLength. The user wants to open this file with a
- * larger size than it currently has. Fill it with zeros. */
- pcBufferToWrite = ( char * ) ffconfigMALLOC( stdioTRUNCATE_WRITE_LENGTH );
- if( pcBufferToWrite == NULL )
- {
- ff_fclose( pxStream );
- pxStream = NULL;
- /* Store the errno to thread local storage. */
- stdioSET_ERRNO( pdFREERTOS_ERRNO_ENOMEM );
- }
- else
- {
- /* File has to grow */
- ulBytesLeftToAdd = ( ( uint32_t ) lTruncateSize ) - ulLength;
- /* Zeros must be written. */
- memset( pcBufferToWrite, '\0', stdioTRUNCATE_WRITE_LENGTH );
- while( ulBytesLeftToAdd > 0UL )
- {
- if( ( pxStream->ulFileSize % stdioTRUNCATE_WRITE_LENGTH ) != 0 )
- {
- /* Although +FAT's FF_Write() can handle any size at any
- * offset, the driver puts data more efficiently if blocks are
- * written at block boundaries. */
- ulBytesToWrite = stdioTRUNCATE_WRITE_LENGTH - ( pxStream->ulFileSize % stdioTRUNCATE_WRITE_LENGTH );
- if( ulBytesToWrite > ulBytesLeftToAdd )
- {
- ulBytesToWrite = ulBytesLeftToAdd;
- }
- }
- else
- {
- ulBytesToWrite = ulBytesLeftToAdd;
- if( ulBytesToWrite > stdioTRUNCATE_WRITE_LENGTH )
- {
- ulBytesToWrite = stdioTRUNCATE_WRITE_LENGTH;
- }
- }
- xReturned = ff_fwrite( pcBufferToWrite, sizeof( char ), ulBytesToWrite, pxStream );
- if( xReturned != ( size_t ) ulBytesToWrite )
- {
- /* Write error. Close the stream and set the proper .
- * errno. */
- ff_fclose( pxStream );
- pxStream = NULL;
- /* Not setting ff_errno because it has been set by other
- * functions from this ff_stdio. */
- break;
- }
- ulBytesLeftToAdd -= ulBytesToWrite;
- }
- ffconfigFREE( pcBufferToWrite );
- }
- }
- return pxStream;
- }
- /*-----------------------------------------------------------*/
- #if ( ffconfigMKDIR_RECURSIVE == 0 )
- /* The normal mkdir() : if assumes that the directories leading to the last
- * element of pcDirectory already exists. For instance: mkdir( "/a/b/c" ) will
- * succeed if the path "/a/b" already exists. */
- int ff_mkdir( const char * pcDirectory )
- {
- int iResult, ff_errno;
- FF_DirHandler_t xHandler;
- /* In case a CWD is used, get the absolute path. */
- pcDirectory = prvABSPath( pcDirectory );
- /* Find the i/o manager for this path */
- if( FF_FS_Find( pcDirectory, &xHandler ) == pdFALSE )
- {
- /* No such device or address. */
- stdioSET_ERRNO( pdFREERTOS_ERRNO_ENXIO );
- /* Return -1 for error as per normal mkdir() semantics. */
- iResult = -1;
- }
- else
- {
- /* A simple non-recursive make of a directory. */
- iResult = FF_MkDir( xHandler.pxManager, xHandler.pcPath );
- if( FF_GETERROR( iResult ) == FF_ERR_DIR_OBJECT_EXISTS )
- {
- /* No error if the target directory already exists. */
- iResult = FF_ERR_NONE;
- }
- ff_errno = prvFFErrorToErrno( iResult );
- /* Store the errno to thread local storage. */
- stdioSET_ERRNO( ff_errno );
- if( ff_errno == pdFREERTOS_ERRNO_NONE )
- {
- iResult = 0;
- }
- else
- {
- /* Return -1 for error as per normal mkdir() semantics. */
- iResult = -1;
- }
- }
- return iResult;
- }
- #else /* ffconfigMKDIR_RECURSIVE */
- #warning This path is not yet included in the regression tests.
- /* The 'recursive mkdir() : if the parameter 'xRecursive' is non-zero,
- * the function will try to create the complete path. */
- int ff_mkdir( const char * pcDirectory,
- int xRecursive )
- {
- int32_t lResult;
- FF_DirHandler_t xHandler;
- /* In case a CWD is used, get the absolute path. */
- pcDirectory = prvABSPath( pcDirectory );
- /* Find the i/o manager for this path */
- if( FF_FS_Find( pcDirectory, &xHandler ) == pdFALSE )
- {
- /* No such device or address. Store the errno to thread local
- * storage. */
- stdioSET_ERRNO( pdFREERTOS_ERRNO_ENXIO );
- /* Return -1 for error as per normal mkdir() semantics. */
- lResult = -1;
- }
- else
- {
- if( xRecursive == pdFALSE )
- {
- /* A simple non-recursive make of a directory. */
- lResult = FF_MkDir( xHandler.pxManager, xHandler.pcPath );
- if( FF_GETERROR( lResult ) == FF_ERR_DIR_OBJECT_EXISTS )
- {
- /* No error if the target directory already exists. */
- lResult = 0;
- }
- }
- else
- {
- /* The recursive option is used. */
- char pcTempPath[ ffconfigMAX_FILENAME ];
- FF_Error_t errCode;
- int iLength = snprintf( pcTempPath, sizeof( pcTempPath ), "%s", xHandler.pcPath );
- char * pcPtr = pcTempPath + 1, * pcPrev;
- const char * pcLast = pcTempPath + iLength;
- lResult = FF_ERR_NONE;
- for( ; ; )
- {
- for( pcPrev = pcPtr; pcPtr < pcLast; pcPtr++ )
- {
- if( *pcPtr == '/' )
- {
- *pcPtr = '\0';
- break;
- }
- }
- if( pcPrev == pcPtr )
- {
- break;
- }
- errCode = FF_MkDir( xHandler.pxManager, pcTempPath );
- if( FF_isERR( errCode ) && ( FF_GETERROR( errCode ) != FF_ERR_DIR_OBJECT_EXISTS ) )
- {
- lResult = errCode;
- break;
- }
- if( pcPtr >= ( pcLast - 1 ) )
- {
- break;
- }
- *( pcPtr++ ) = '/';
- }
- }
- /* Store the errno to thread local storage. */
- stdioSET_ERRNO( prvFFErrorToErrno( lResult ) );
- }
- return lResult;
- }
- #endif /* ffconfigMKDIR_RECURSIVE */
- /*-----------------------------------------------------------*/
- int ff_rmdir( const char * pcDirectory )
- {
- int32_t lResult;
- int iReturn, ff_errno;
- FF_DirHandler_t xHandler;
- /* In case a CWD is used, get the absolute path */
- pcDirectory = prvABSPath( pcDirectory );
- /* Find the i/o manager which can handle this path. */
- if( FF_FS_Find( pcDirectory, &xHandler ) == pdFALSE )
- {
- ff_errno = pdFREERTOS_ERRNO_ENXIO; /* No such device or address */
- /* Return -1 for error as per normal rmdir() semantics. */
- iReturn = -1;
- }
- else
- {
- lResult = FF_RmDir( xHandler.pxManager, xHandler.pcPath );
- ff_errno = prvFFErrorToErrno( lResult );
- if( ff_errno == 0 )
- {
- iReturn = 0;
- }
- else
- {
- /* Return -1 for error as per normal rmdir() semantics. */
- iReturn = -1;
- }
- }
- /* Store the errno to thread local storage. */
- stdioSET_ERRNO( ff_errno );
- return iReturn;
- }
- /*-----------------------------------------------------------*/
- int ff_remove( const char * pcPath )
- {
- FF_DirHandler_t xHandler;
- FF_Error_t xError;
- int iReturn, ff_errno;
- /* In case a CWD is used, get the absolute path */
- pcPath = prvABSPath( pcPath );
- /* Find the i/o manager which can handle this path. */
- if( FF_FS_Find( pcPath, &xHandler ) == pdFALSE )
- {
- /* No such device or address */
- ff_errno = pdFREERTOS_ERRNO_ENXIO;
- /* Return -1 for error as per normal remove() semantics. */
- iReturn = -1;
- }
- else
- {
- xError = FF_RmFile( xHandler.pxManager, xHandler.pcPath );
- ff_errno = prvFFErrorToErrno( xError );
- #if ffconfigUSE_NOTIFY
- {
- if( FF_isERR( xError ) == pdFALSE )
- {
- callFileEvents( pcPath, eFileRemove );
- }
- }
- #endif
- if( ff_errno == 0 )
- {
- iReturn = 0;
- }
- else
- {
- /* Return -1 for error as per normal remove() semantics. */
- iReturn = -1;
- }
- }
- /* Store the errno to thread local storage. */
- stdioSET_ERRNO( ff_errno );
- return iReturn;
- }
- /*-----------------------------------------------------------*/
- /*_RB_ Last parameter not documented. */
- int ff_rename( const char * pcOldName,
- const char * pcNewName,
- int bDeleteIfExists )
- {
- FF_DirHandler_t xHandlers[ 2 ];
- FF_Error_t xError = FF_ERR_NONE;
- int ff_errno = 0, iReturn;
- #if ( ffconfigHAS_CWD != 0 )
- char * pcOldCopy;
- size_t xSize;
- #endif
- /* In case a CWD is used, get the absolute path */
- pcOldName = prvABSPath( pcOldName );
- /* Find the i/o manager which can handle this path */
- if( FF_FS_Find( pcOldName, &xHandlers[ 0 ] ) == pdFALSE )
- {
- xError = ( int32_t ) ( FF_ERR_NULL_POINTER | FF_MOVE );
- ff_errno = pdFREERTOS_ERRNO_ENXIO; /* No such device or address */
- }
- else
- {
- #if ( ffconfigHAS_CWD != 0 )
- {
- xSize = strlen( xHandlers[ 0 ].pcPath ) + 1;
- pcOldCopy = ( char * ) ffconfigMALLOC( xSize );
- if( pcOldCopy == NULL )
- {
- /* Could not allocate space to store a file name. */
- ff_errno = pdFREERTOS_ERRNO_ENOMEM;
- xError = ( int32_t ) ( FF_ERR_NOT_ENOUGH_MEMORY | FF_MOVE );
- }
- else
- {
- /* The function prvABSPath() returns a pointer to the task
- * storage space. Rename needs to call it twice and therefore the
- * path must be stored before it gets overwritten. */
- memcpy( pcOldCopy, xHandlers[ 0 ].pcPath, xSize );
- xHandlers[ 0 ].pcPath = pcOldCopy;
- }
- }
- #endif /* ffconfigHAS_CWD != 0 */
- #if ( ffconfigHAS_CWD != 0 )
- if( pcOldCopy != NULL )
- #endif /* ffconfigHAS_CWD != 0 */
- {
- pcNewName = prvABSPath( pcNewName );
- /* Find the i/o manager which can handle this path */
- if( FF_FS_Find( pcNewName, &( xHandlers[ 1 ] ) ) == pdFALSE )
- {
- xError = ( int32_t ) ( FF_ERR_NULL_POINTER | FF_MOVE );
- ff_errno = pdFREERTOS_ERRNO_ENXIO; /* No such device or address */
- }
- else if( xHandlers[ 0 ].pxManager != xHandlers[ 1 ].pxManager )
- {
- xError = ( int32_t ) ( FF_ERR_NULL_POINTER | FF_MOVE );
- /* Cross-device link, which can not be done. */
- ff_errno = pdFREERTOS_ERRNO_EXDEV;
- }
- else
- {
- xError = FF_Move( xHandlers[ 0 ].pxManager, xHandlers[ 0 ].pcPath, xHandlers[ 1 ].pcPath, bDeleteIfExists );
- ff_errno = prvFFErrorToErrno( xError );
- #if ffconfigUSE_NOTIFY
- {
- if( FF_isERR( xError ) == pdFALSE )
- {
- callFileEvents( pcNewName, eFileChange );
- }
- }
- #endif
- }
- #if ( ffconfigHAS_CWD != 0 )
- {
- ffconfigFREE( pcOldCopy );
- }
- #endif
- }
- }
- /* Store the errno to thread local storage. */
- stdioSET_ERRNO( ff_errno );
- if( ff_errno == 0 )
- {
- iReturn = 0;
- }
- else
- {
- /* Return -1 for error as per normal rmdir() semantics. */
- iReturn = -1;
- }
- return iReturn;
- }
- /*-----------------------------------------------------------*/
- int ff_stat( const char * pcName,
- FF_Stat_t * pxStatBuffer )
- {
- FF_DirEnt_t xDirEntry;
- uint32_t ulFileCluster;
- FF_Error_t xError;
- int iResult;
- FF_DirHandler_t xHandler;
- BaseType_t xIndex;
- FF_FindParams_t xFindParams;
- #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
- const FF_T_WCHAR * pcFileName = NULL;
- #else
- /* Initialised to prevent MSVC incorrectly claiming the variable is used
- * without being initialised. */
- const char * pcFileName = NULL;
- #endif
- memset( &xFindParams, '\0', sizeof( xFindParams ) );
- /* Insert the current working directory in front of relative paths. */
- pcName = prvABSPath( pcName );
- /* Look-up the I/O manager for the file system. */
- if( FF_FS_Find( pcName, &xHandler ) == pdFALSE )
- {
- /* No such device or address. */
- xError = ( FF_Error_t ) ( pdFREERTOS_ERRNO_ENXIO | FF_STAT_FUNC );
- }
- else
- {
- xError = FF_ERR_NONE;
- pcName = xHandler.pcPath;
- /* Let xIndex point to the last occurrence of '/' or '\', to separate
- * the path from the file name. */
- xIndex = ( BaseType_t ) STRLEN( pcName );
- while( xIndex != 0 )
- {
- if( ( pcName[ xIndex ] == '\\' ) || ( pcName[ xIndex ] == '/' ) )
- {
- break;
- }
- xIndex--;
- }
- /* Copy the file name, i.e. the string that comes after the last
- * separator. */
- pcFileName = pcName + xIndex + 1;
- if( xIndex == 0 )
- {
- /* Only for the root, the slash is part of the directory name.
- * 'xIndex' now equals to the length of the path name. */
- xIndex = 1;
- }
- /* FF_CreateShortName() might set flags FIND_FLAG_FITS_SHORT and
- * FIND_FLAG_SIZE_OK. */
- FF_CreateShortName( &xFindParams, pcFileName );
- /* Lookup the path and find the cluster pointing to the directory: */
- xFindParams.ulDirCluster = FF_FindDir( xHandler.pxManager, pcName, xIndex, &xError );
- }
- if( FF_isERR( xError ) == pdFALSE )
- {
- /* See if the file does exist within the given directory. */
- ulFileCluster = FF_FindEntryInDir( xHandler.pxManager, &xFindParams, pcFileName, 0x00, &xDirEntry, &xError );
- if( ulFileCluster == 0ul )
- {
- /* If cluster 0 was returned, it might be because the file has no allocated cluster,
- * i.e. only a directory entry and no stored data. */
- if( STRLEN( pcFileName ) == STRLEN( xDirEntry.pcFileName ) )
- {
- if( ( xDirEntry.ulFileSize == 0 ) && ( FF_strmatch( pcFileName, xDirEntry.pcFileName, ( BaseType_t ) STRLEN( pcFileName ) ) == pdTRUE ) )
- {
- /* It is the file, give it a pseudo cluster number '1'. */
- ulFileCluster = 1;
- /* And reset any error. */
- xError = FF_ERR_NONE;
- }
- }
- }
- /* Test 'ulFileCluster' again, it might have been changed. */
- if( ulFileCluster == 0ul )
- {
- xError = FF_ERR_FILE_NOT_FOUND | FF_STAT_FUNC;
- }
- }
- if( ( pxStatBuffer != NULL ) && ( FF_isERR( xError ) == pdFALSE ) )
- {
- if( ( xDirEntry.ucAttrib & FF_FAT_ATTR_DIR ) != 0 )
- {
- pxStatBuffer->st_mode = ( unsigned short ) FF_IFDIR;
- }
- else
- {
- pxStatBuffer->st_mode = ( unsigned short ) FF_IFREG;
- }
- #if ( ffconfigDEV_SUPPORT != 0 )
- {
- BaseType_t bIsDeviceDir = xCheckDevicePath( pcFileName );
- if( bIsDeviceDir != pdFALSE )
- {
- FF_Device_GetDirEnt( xHandler.pcPath, &( xDirEntry ) );
- }
- }
- #endif
- /* Despite the warning output by MSVC - it is not possible to get here
- * if xDirEntry has not been initialised. */
- pxStatBuffer->st_size = xDirEntry.ulFileSize;
- pxStatBuffer->st_ino = xDirEntry.ulObjectCluster;
- pxStatBuffer->st_dev = ( short ) xHandler.xFSIndex;
- #if ( ffconfigTIME_SUPPORT == 1 )
- {
- pxStatBuffer->st_atime = ( unsigned long ) prvFileTime( &( xDirEntry.xAccessedTime ) );
- pxStatBuffer->st_mtime = ( unsigned long ) prvFileTime( &( xDirEntry.xModifiedTime ) );
- pxStatBuffer->st_ctime = ( unsigned long ) prvFileTime( &( xDirEntry.xCreateTime ) );
- }
- #endif
- }
- stdioSET_ERRNO( prvFFErrorToErrno( xError ) );
- if( FF_isERR( xError ) == pdFALSE )
- {
- iResult = 0;
- }
- else
- {
- iResult = -1;
- }
- return iResult;
- } /* ff_stat() */
- /*-----------------------------------------------------------*/
- #if ( ffconfigHAS_CWD == 1 )
- int ff_chdir( const char * pcDirectoryName )
- {
- int iResult, iLength, iValid = pdFALSE;
- WorkingDirectory_t * pxDir = NULL;
- /* Not all paths set an errno. */
- stdioSET_ERRNO( 0 );
- /* Is there a file system mounted? */
- if( FF_FS_Count() != 0 )
- {
- /* In case a CWD is used, get the absolute path. */
- pcDirectoryName = prvABSPath( pcDirectoryName );
- pxDir = pxFindCWD();
- if( pxDir == NULL )
- {
- /* Store the errno to thread local storage. */
- stdioSET_ERRNO( pdFREERTOS_ERRNO_ENOMEM );
- /* Return -1 for error as per normal chdir() semantics. */
- iResult = -1;
- }
- else
- {
- /* The CWD will be stored without a trailing '/'. If "/"
- * happens to be the CWD, it will be stored as an empty string. */
- iLength = strlen( pcDirectoryName );
- /* Knock off the trailing / if one exits - being careful not to
- * remove the trailing slash if this is the root directory. */
- if( ( iLength > 1 ) && ( pxDir->pcFileName[ iLength - 1 ] == '/' ) )
- {
- pxDir->pcFileName[ iLength - 1 ] = '\0';
- }
- stdioSET_ERRNO( pdFREERTOS_ERRNO_ENOENT );
- /* Does the directory exist? */
- if( strcmp( pcDirectoryName, "/" ) == 0 )
- {
- /* Moving to the root - which exists. */
- iValid = pdTRUE;
- }
- else if( ff_finddir( pxDir->pcFileName ) != pdFALSE )
- {
- iValid = pdTRUE;
- }
- }
- }
- if( iValid == pdTRUE )
- {
- /* The generated name becomes the CWD. No need to test for overflow
- * as pcPath and pcFileName are the same size. */
- strcpy( pxDir->pcCWD, pxDir->pcFileName );
- /* chdir returns 0 for success. */
- iResult = FF_ERR_NONE;
- }
- else
- {
- /* Return -1 for error as per normal chdir() semantics. */
- iResult = -1;
- }
- return iResult;
- }
- #endif /* ffconfigHAS_CWD == 1 */
- /*-----------------------------------------------------------*/
- #if ( ffconfigHAS_CWD == 1 )
- char * ff_getcwd( char * pcBuffer,
- size_t xBufferLength )
- {
- WorkingDirectory_t * pxDir = pxFindCWD();
- stdioSET_ERRNO( 0 );
- if( ( pxDir == NULL ) || ( pxDir->pcCWD[ 0 ] == '\0' ) )
- {
- if( xBufferLength > strlen( "/" ) )
- {
- strncpy( pcBuffer, "/", xBufferLength );
- }
- else
- {
- pcBuffer = NULL;
- }
- }
- else
- {
- if( strlen( pxDir->pcCWD ) < xBufferLength )
- {
- strncpy( pcBuffer, pxDir->pcCWD, xBufferLength );
- }
- else
- {
- pcBuffer = NULL;
- }
- }
- return pcBuffer;
- }
- #endif /* ffconfigHAS_CWD */
- /*-----------------------------------------------------------*/
- int ff_findfirst( const char * pcPath,
- FF_FindData_t * pxFindData )
- {
- int iIsRootDir, iReturn;
- const char * pcDirectory;
- iReturn = 0;
- memset( pxFindData, '\0', sizeof( *pxFindData ) );
- pxFindData->pcFileName = pxFindData->xDirectoryEntry.pcFileName;
- /* In case a CWD is used, get the absolute path. */
- pcDirectory = prvABSPath( pcPath );
- if( ( pcDirectory[ 0 ] == '/' ) && ( pcDirectory[ 1 ] == 0x00 ) )
- {
- iIsRootDir = pdTRUE;
- }
- else
- {
- iIsRootDir = pdFALSE;
- }
- /* Find the i/o manager that can handle this path. */
- if( FF_FS_Find( pcDirectory, &( pxFindData->xDirectoryHandler ) ) == pdFALSE )
- {
- if( ( iIsRootDir == pdFALSE ) || ( FF_FS_Count() == 0 ) )
- {
- stdioSET_ERRNO( prvFFErrorToErrno( ( FF_Error_t ) ( FF_ERR_NULL_POINTER | FF_FINDFIRST ) ) );
- iReturn = -1;
- }
- }
- /* Check no errors before continuing. */
- if( iReturn == 0 )
- {
- #if ( ffconfigDEV_SUPPORT != 0 )
- {
- pxFindData->bIsDeviceDir = xCheckDevicePath( pcDirectory );
- }
- #endif
- if( iIsRootDir != pdFALSE )
- {
- /* A listing of the root directory will include pseudo entries
- * such as /ram /nand. */
- pxFindData->xDirectoryHandler.xFSIndex = FF_FS_Count();
- /* Only add '.' */
- pxFindData->xDirectoryHandler.u.bits.bAddDotEntries = stdioDIR_ENTRY_DOT_1;
- }
- else
- {
- /* This is the root of a sub file system, add "." and ".." */
- pxFindData->xDirectoryHandler.u.bits.bAddDotEntries = stdioDIR_ENTRY_DOT_1 | stdioDIR_ENTRY_DOT_2;
- }
- pxFindData->xDirectoryHandler.u.bits.bIsValid = pdTRUE;
- iReturn = ff_findnext( pxFindData );
- }
- else
- {
- /* errno has already been set. */
- }
- return iReturn;
- }
- /*-----------------------------------------------------------*/
- int ff_findnext( FF_FindData_t * pxFindData )
- {
- FF_Error_t xError;
- #if ( ffconfigTIME_SUPPORT != 0 )
- BaseType_t xSetTime = 0;
- #endif /* ffconfigTIME_SUPPORT */
- if( pxFindData->xDirectoryHandler.u.bits.bIsValid == pdFALSE )
- {
- xError = ( FF_Error_t ) ( FF_ERR_DIR_INVALID_PARAMETER | FF_FINDNEXT );
- FF_PRINTF( "ff_findnext: xDirectoryHandler not valid\n" );
- }
- else
- {
- xError = ( FF_Error_t ) ( FF_ERR_DIR_END_OF_DIR | FF_FINDNEXT );
- if( pxFindData->xDirectoryHandler.pxManager != NULL )
- {
- if( pxFindData->xDirectoryHandler.u.bits.bFirstCalled == pdFALSE )
- {
- pxFindData->xDirectoryHandler.u.bits.bFirstCalled = pdTRUE;
- xError = FF_FindFirst( pxFindData->xDirectoryHandler.pxManager, &( pxFindData->xDirectoryEntry ),
- pxFindData->xDirectoryHandler.pcPath );
- }
- else if( pxFindData->xDirectoryHandler.u.bits.bEndOfDir == pdFALSE )
- {
- xError = FF_FindNext( pxFindData->xDirectoryHandler.pxManager, &( pxFindData->xDirectoryEntry ) );
- }
- if( FF_GETERROR( xError ) == FF_ERR_DIR_END_OF_DIR )
- {
- /* Stop further calls to FF_FindNext(). */
- pxFindData->xDirectoryHandler.u.bits.bEndOfDir = pdTRUE;
- }
- #if ( ffconfigDEV_SUPPORT != 0 )
- {
- if( pxFindData->bIsDeviceDir != pdFALSE )
- {
- FF_Device_GetDirEnt( pxFindData->xDirectoryHandler.pcPath, &( pxFindData->xDirectoryEntry ) );
- }
- }
- #endif
- }
- if( FF_isERR( xError ) == pdFALSE )
- {
- /* If an entry is found, see if it is a dot-entry. Dot-entries
- * ("." and "..") need a time-stamp. */
- if( pxFindData->xDirectoryEntry.pcFileName[ 0 ] == '.' )
- {
- if( ( pxFindData->xDirectoryEntry.pcFileName[ 1 ] == '.' ) &&
- ( pxFindData->xDirectoryEntry.pcFileName[ 2 ] == '\0' ) )
- {
- /* This is a directory "..". Clear the flag for DOT_2. */
- pxFindData->xDirectoryHandler.u.bits.bAddDotEntries &= stdioDIR_ENTRY_DOT_1;
- #if ( ffconfigTIME_SUPPORT != 0 )
- {
- /* The dot-entries do not have a proper time stamp, add
- * it here. */
- xSetTime = pdTRUE;
- }
- #endif /* ffconfigTIME_SUPPORT */
- }
- else if( pxFindData->xDirectoryEntry.pcFileName[ 1 ] == '\0' )
- {
- /* This is a directory ".". Clear the flag for DOT_1. */
- pxFindData->xDirectoryHandler.u.bits.bAddDotEntries &= stdioDIR_ENTRY_DOT_2;
- #if ( ffconfigTIME_SUPPORT != 0 )
- {
- xSetTime = pdTRUE;
- }
- #endif /* ffconfigTIME_SUPPORT */
- }
- }
- }
- if( FF_GETERROR( xError ) == FF_ERR_DIR_END_OF_DIR )
- {
- /* No more physical entries were found. Now see if there are FS
- * entries or dot-entries to be added: */
- while( ( pxFindData->xDirectoryHandler.xFSIndex > 0 ) ||
- ( pxFindData->xDirectoryHandler.u.bits.bAddDotEntries != 0 ) )
- {
- if( pxFindData->xDirectoryHandler.xFSIndex > 0 )
- {
- FF_SubSystem_t xSubSystem;
- int found;
- pxFindData->xDirectoryHandler.xFSIndex--;
- found = FF_FS_Get( pxFindData->xDirectoryHandler.xFSIndex, &xSubSystem );
- if( ( found == pdFALSE ) || ( xSubSystem.pcPath[ 1 ] == '\0' ) )
- {
- continue;
- }
- snprintf( pxFindData->xDirectoryEntry.pcFileName, sizeof( pxFindData->xDirectoryEntry.pcFileName ), "%s", xSubSystem.pcPath + 1 );
- if( xSubSystem.pxManager != NULL )
- {
- pxFindData->xDirectoryEntry.ulObjectCluster = xSubSystem.pxManager->xPartition.ulRootDirCluster;
- }
- else
- {
- pxFindData->xDirectoryEntry.ulObjectCluster = 0;
- }
- }
- else if( ( pxFindData->xDirectoryHandler.u.bits.bAddDotEntries & stdioDIR_ENTRY_DOT_2 ) != 0 )
- {
- strcpy( pxFindData->xDirectoryEntry.pcFileName, ".." );
- /* Clear DOT_2 (keep DOT_1). */
- pxFindData->xDirectoryHandler.u.bits.bAddDotEntries &= stdioDIR_ENTRY_DOT_1;
- }
- else
- {
- strcpy( pxFindData->xDirectoryEntry.pcFileName, "." );
- pxFindData->xDirectoryHandler.u.bits.bAddDotEntries = 0;
- }
- pxFindData->xDirectoryEntry.ucAttrib = FF_FAT_ATTR_READONLY | FF_FAT_ATTR_DIR;
- pxFindData->xDirectoryEntry.ulFileSize = stdioDOT_ENTRY_FILE_SIZE;
- #if ( ffconfigTIME_SUPPORT != 0 )
- {
- xSetTime = pdTRUE;
- }
- #endif /* ffconfigTIME_SUPPORT */
- xError = FF_ERR_NONE;
- break;
- }
- }
- #if ( ffconfigTIME_SUPPORT != 0 )
- {
- if( xSetTime != pdFALSE )
- {
- FF_TimeStruct_t xTimeStruct;
- time_t xSeconds;
- xSeconds = FreeRTOS_time( NULL );
- FreeRTOS_gmtime_r( &xSeconds, &xTimeStruct );
- pxFindData->xDirectoryEntry.xCreateTime.Year = ( uint16_t ) ( xTimeStruct.tm_year + 1900 ); /* Year (e.g. 2009). */
- pxFindData->xDirectoryEntry.xCreateTime.Month = ( uint16_t ) ( xTimeStruct.tm_mon + 1 ); /* Month (e.g. 1 = Jan, 12 = Dec). */
- pxFindData->xDirectoryEntry.xCreateTime.Day = ( uint16_t ) xTimeStruct.tm_mday; /* Day (1 - 31). */
- pxFindData->xDirectoryEntry.xCreateTime.Hour = ( uint16_t ) xTimeStruct.tm_hour; /* Hour (0 - 23). */
- pxFindData->xDirectoryEntry.xCreateTime.Minute = ( uint16_t ) xTimeStruct.tm_min; /* Min (0 - 59). */
- pxFindData->xDirectoryEntry.xCreateTime.Second = ( uint16_t ) xTimeStruct.tm_sec; /* Second (0 - 59). */
- pxFindData->xDirectoryEntry.xModifiedTime = pxFindData->xDirectoryEntry.xCreateTime; /* Date and Time Modified. */
- pxFindData->xDirectoryEntry.xAccessedTime = pxFindData->xDirectoryEntry.xCreateTime; /* Date of Last Access. */
- }
- }
- #endif /* ffconfigTIME_SUPPORT */
- if( FF_GETERROR( xError ) == FF_ERR_DIR_END_OF_DIR )
- {
- /* FF_ERR_DIR_END_OF_DIR will be returned. */
- pxFindData->xDirectoryHandler.u.bits.bIsValid = 0;
- }
- pxFindData->ucAttributes = pxFindData->xDirectoryEntry.ucAttrib;
- pxFindData->ulFileSize = pxFindData->xDirectoryEntry.ulFileSize;
- }
- stdioSET_ERRNO( prvFFErrorToErrno( xError ) );
- return xError;
- }
- /*-----------------------------------------------------------*/
- /*-----------------------------------------------------------
- * ff_isdirempty() returns 1 if a given directory is empty
- * (has no entries)
- *-----------------------------------------------------------*/
- int ff_isdirempty( const char * pcPath )
- {
- FF_DirHandler_t xHandler;
- int iResult;
- /* In case a CWD is used, get the absolute path */
- pcPath = prvABSPath( pcPath );
- /* Find the i/o manager which can handle this path */
- if( FF_FS_Find( pcPath, &xHandler ) == pdFALSE )
- {
- iResult = ( int ) ( FF_ERR_NULL_POINTER | FF_ISDIREMPTY );
- }
- else
- {
- iResult = FF_isDirEmpty( xHandler.pxManager, xHandler.pcPath );
- }
- /* Store the errno to thread local storage. */
- stdioSET_ERRNO( prvFFErrorToErrno( iResult ) );
- return iResult;
- }
- /*-----------------------------------------------------------*/
- #if ( ffconfig64_NUM_SUPPORT != 0 )
- int64_t ff_diskfree( const char * pcPath,
- uint32_t * pxSectorCount )
- #else
- int32_t ff_diskfree( const char * pcPath,
- uint32_t * pxSectorCount )
- #endif
- {
- FF_DirHandler_t xHandler;
- FF_Error_t xError;
- #if ( ffconfig64_NUM_SUPPORT != 0 )
- #define DISKFREE_RETURN_TYPE int64_t
- int64_t lReturn;
- #else
- #define DISKFREE_RETURN_TYPE int32_t
- int32_t lReturn;
- #endif
- if( FF_FS_Find( pcPath, &xHandler ) == pdFALSE )
- {
- /* Return cluster 0 for error. */
- lReturn = 0ul;
- /* Store the errno to thread local storage. */
- stdioSET_ERRNO( pdFREERTOS_ERRNO_ENXIO ); /* No such device or address */
- }
- else
- {
- if( pxSectorCount != NULL )
- {
- *pxSectorCount = xHandler.pxManager->xPartition.ulDataSectors;
- }
- lReturn = ( DISKFREE_RETURN_TYPE ) FF_GetFreeSize( xHandler.pxManager, &xError ) / 512;
- /* Store the errno to thread local storage. */
- stdioSET_ERRNO( prvFFErrorToErrno( xError ) );
- }
- return lReturn;
- }
- /*-----------------------------------------------------------*/
- int ff_finddir( const char * pcPath )
- {
- int iResult;
- FF_DirHandler_t xHandler;
- FF_Error_t errCode;
- if( FF_FS_Find( pcPath, &xHandler ) == pdFALSE )
- {
- /* Return cluster 0 for error. */
- iResult = 0;
- }
- else
- {
- iResult = ( int ) FF_FindDir( xHandler.pxManager, xHandler.pcPath, ( uint16_t ) strlen( xHandler.pcPath ), &errCode );
- }
- return iResult;
- }
- /*-----------------------------------------------------------*/
- size_t ff_filelength( FF_FILE * pxStream )
- {
- FF_Error_t xReturned;
- uint32_t ulLength;
- xReturned = FF_GetFileSize( pxStream, &( ulLength ) );
- if( FF_isERR( xReturned ) != pdFALSE )
- {
- /* An error. */
- ulLength = ( uint32_t ) 0u;
- stdioSET_ERRNO( prvFFErrorToErrno( xReturned ) );
- }
- else
- {
- stdioSET_ERRNO( pdFREERTOS_ERRNO_NONE );
- }
- return ( size_t ) ulLength;
- }
- /*-----------------------------------------------------------*/
- /*-----------------------------------------------------------
- * Delete a directory and, recursively, all of its contents
- *-----------------------------------------------------------*/
- #if ( ffconfigUSE_DELTREE != 0 )
- int ff_deltree( const char * pcDirectory )
- {
- int iResult;
- char * pcPath;
- pcPath = ( char * ) ffconfigMALLOC( ffconfigMAX_FILENAME );
- if( pcPath != NULL )
- {
- /* In case a CWD is used, get the absolute path */
- pcDirectory = prvABSPath( pcDirectory );
- snprintf( pcPath, ffconfigMAX_FILENAME, "%s", pcDirectory );
- /* This recursive function will do all the work */
- iResult = ff_deltree_recurse( pcPath );
- if( iResult >= 0 )
- {
- iResult = ff_rmdir( pcPath );
- if( iResult )
- {
- FF_PRINTF( "ff_deltree(%s): %s\n", pcPath, strerror( stdioGET_ERRNO() ) );
- }
- }
- ffconfigFREE( pcPath );
- }
- else
- {
- iResult = -1;
- stdioSET_ERRNO( pdFREERTOS_ERRNO_ENOMEM );
- }
- return iResult;
- }
- #endif /* ffconfigUSE_DELTREE */
- /*-----------------------------------------------------------*/
- #if ( ffconfigUSE_DELTREE != 0 )
- static int ff_deltree_recurse( char * pcPath )
- {
- FF_FindData_t * pxFindData;
- BaseType_t xIsDir, xIsDotDir;
- FF_Error_t xError;
- int iResult, iNext, iNameLength, pass, iCount = 0;
- pxFindData = ( FF_FindData_t * ) ffconfigMALLOC( sizeof( *pxFindData ) );
- if( pxFindData != NULL )
- {
- iNameLength = ( int ) strlen( pcPath );
- /* The directory will be scanned 2 times. First the sub-directories will be
- * entered and their contents deleted. In the second pass the files in the
- * current directory will be removed. In this way 'pcPath' can be constantly
- * used and reused recursively which is cheaper than allocating 'ffconfigMAX_FILENAME'
- * bytes within each recursion. */
- for( pass = 0; pass < 2; pass++ )
- {
- for( iResult = ff_findfirst( pcPath, pxFindData );
- iResult == 0;
- iResult = iNext )
- {
- xIsDir = ( pxFindData->xDirectoryEntry.ucAttrib & FF_FAT_ATTR_DIR ) != 0;
- if( ( pass == 0 ) && ( xIsDir != pdFALSE ) )
- {
- /* This entry is a directory. Don't traverse '.' or '..' */
- xIsDotDir = 0;
- if( pxFindData->pcFileName[ 0 ] == '.' )
- {
- if( ( pxFindData->pcFileName[ 1 ] == '.' ) &&
- ( pxFindData->pcFileName[ 2 ] == '\0' ) )
- {
- xIsDotDir = 2;
- }
- else if( pxFindData->pcFileName[ 1 ] == '\0' )
- {
- xIsDotDir = 1;
- }
- }
- if( xIsDotDir == 0 )
- {
- snprintf( pcPath + iNameLength, ( size_t ) ( ffconfigMAX_FILENAME - iNameLength ), "%s%s",
- pcPath[ iNameLength - 1 ] == '/' ? "" : "/", pxFindData->pcFileName );
- /* Let pxFindData point to the next element before
- * the current will get removed. */
- iNext = ff_findnext( pxFindData );
- /* Remove the contents of this directory. */
- iResult = ff_deltree_recurse( pcPath );
- if( iResult < 0 )
- {
- iCount = -1;
- break;
- }
- iCount += iResult;
- /* remove the directory itself */
- xError = ff_rmdir( pcPath );
- if( xError != 0 )
- {
- FF_PRINTF( "ff_rmdir( %s ): errno %d\n", pcPath, stdioGET_ERRNO() );
- }
- else
- {
- iCount++;
- }
- }
- else
- {
- iNext = ff_findnext( pxFindData );
- }
- }
- else if( ( pass == 1 ) && ( xIsDir == pdFALSE ) )
- {
- snprintf( pcPath + iNameLength, ( size_t ) ( ffconfigMAX_FILENAME - iNameLength ), "%s%s",
- pcPath[ iNameLength - 1 ] == '/' ? "" : "/", pxFindData->pcFileName );
- /* Let pxFindData point to the next element before
- * the current will get removed. */
- iNext = ff_findnext( pxFindData );
- /* Remove a plain file. */
- xError = ff_remove( pcPath );
- if( xError != 0 )
- {
- FF_PRINTF( "ff_remove( %s ): errno %d\n", pcPath, stdioGET_ERRNO() );
- }
- else
- {
- iCount++;
- }
- }
- else
- {
- iNext = ff_findnext( pxFindData );
- }
- pcPath[ iNameLength ] = '\0';
- }
- if( FF_GETERROR( iResult ) == FF_ERR_DIR_INVALID_PATH )
- {
- break;
- }
- if( ( FF_GETERROR( iResult ) != FF_ERR_DIR_END_OF_DIR ) && ( FF_GETERROR( iResult ) != FF_ERR_FILE_INVALID_PATH ) )
- {
- FF_PRINTF( "ff_deltree_recurse[%s]: %s\n", pcPath, ( const char * ) FF_GetErrMessage( iResult ) );
- }
- }
- ffconfigFREE( pxFindData );
- }
- else
- {
- iCount = -1;
- stdioSET_ERRNO( pdFREERTOS_ERRNO_ENOMEM );
- }
- return iCount;
- }
- #endif /* ffconfigUSE_DELTREE */
- /*-----------------------------------------------------------*/
- int prvFFErrorToErrno( FF_Error_t xError )
- {
- if( FF_isERR( xError ) == pdFALSE )
- {
- return 0;
- }
- /* Store the last +FAT error code received. */
- stdioSET_FF_ERROR( xError );
- switch( FF_GETERROR( xError ) )
- {
- /* Global Error Codes. */
- case FF_ERR_NONE:
- return 0; /* No Error. */
- case FF_ERR_NULL_POINTER:
- return pdFREERTOS_ERRNO_EBADF; /* pxIOManager was NULL. */
- case FF_ERR_NOT_ENOUGH_MEMORY:
- return pdFREERTOS_ERRNO_ENOMEM; /* malloc() failed! - Could not allocate handle memory. */
- case FF_ERR_DEVICE_DRIVER_FAILED:
- return pdFREERTOS_ERRNO_EIO; /* The Block Device driver reported a FATAL error, cannot continue. */
- /* User return codes for Rd/Wr functions:. */
- case FF_ERR_IOMAN_DRIVER_BUSY:
- return pdFREERTOS_ERRNO_EBUSY; /* 10. */
- case FF_ERR_IOMAN_DRIVER_FATAL_ERROR:
- return pdFREERTOS_ERRNO_EUNATCH; /* Protocol driver not attached. */
- /* IOMAN Error Codes. */
- case FF_ERR_IOMAN_BAD_BLKSIZE:
- return pdFREERTOS_ERRNO_EINVAL; /* The provided blocksize was not a multiple of 512. */
- case FF_ERR_IOMAN_BAD_MEMSIZE:
- return pdFREERTOS_ERRNO_EINVAL; /* The memory size was not a multiple of the blocksize. */
- case FF_ERR_IOMAN_DEV_ALREADY_REGD:
- return pdFREERTOS_ERRNO_EADDRINUSE; /* Device was already registered. Use FF_UnRegister() to re-use this IOMAN with another device. */
- case FF_ERR_IOMAN_NO_MOUNTABLE_PARTITION:
- return pdFREERTOS_ERRNO_ENOMEDIUM; /* A mountable partition could not be found on the device. */
- case FF_ERR_IOMAN_INVALID_FORMAT:
- return pdFREERTOS_ERRNO_EFTYPE; /* The. */
- case FF_ERR_IOMAN_INVALID_PARTITION_NUM:
- return pdFREERTOS_ERRNO_EINVAL; /* The partition number provided was out of range. */
- case FF_ERR_IOMAN_NOT_FAT_FORMATTED:
- return pdFREERTOS_ERRNO_EFTYPE; /* The partition did not look like a FAT partition. */
- case FF_ERR_IOMAN_DEV_INVALID_BLKSIZE:
- return pdFREERTOS_ERRNO_EINVAL; /* IOMAN object BlkSize is not compatible with the blocksize of this device driver. */
- case FF_ERR_IOMAN_PARTITION_MOUNTED:
- return pdFREERTOS_ERRNO_EADDRINUSE; /* Device is in use by an actively mounted partition. Unmount the partition first. */
- case FF_ERR_IOMAN_ACTIVE_HANDLES:
- return pdFREERTOS_ERRNO_EBUSY; /* The partition cannot be unmounted until all active file handles are closed. (There may also be active handles on the cache). */
- case FF_ERR_IOMAN_GPT_HEADER_CORRUPT:
- return pdFREERTOS_ERRNO_EBADE; /* The GPT partition table appears to be corrupt, refusing to mount. */
- case FF_ERR_IOMAN_NOT_ENOUGH_FREE_SPACE:
- return pdFREERTOS_ERRNO_ENOSPC; /* 22. */
- case FF_ERR_IOMAN_OUT_OF_BOUNDS_READ:
- return pdFREERTOS_ERRNO_ESPIPE; /* 23, return 'Illegal seek'. */
- case FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE:
- return pdFREERTOS_ERRNO_ESPIPE; /* 24. */
- case FF_ERR_IOMAN_DRIVER_NOMEDIUM:
- return pdFREERTOS_ERRNO_ENOMEDIUM; /* The medium (e.g. SD-card) has been extracted. */
- /* File Error Codes 30 +. */
- case FF_ERR_FILE_ALREADY_OPEN:
- return pdFREERTOS_ERRNO_EALREADY; /* File is in use. */
- case FF_ERR_FILE_NOT_FOUND:
- return pdFREERTOS_ERRNO_ENOENT; /* File was not found. */
- case FF_ERR_FILE_OBJECT_IS_A_DIR:
- return pdFREERTOS_ERRNO_EISDIR; /* Tried to FF_Open() a Directory. */
- case FF_ERR_FILE_IS_READ_ONLY:
- return pdFREERTOS_ERRNO_EROFS; /* Tried to FF_Open() a file marked read only. */
- case FF_ERR_FILE_INVALID_PATH:
- return pdFREERTOS_ERRNO_ENOTDIR; /* The path of the file was not found. */
- case FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE:
- return pdFREERTOS_ERRNO_EACCES; /* 35. */
- case FF_ERR_FILE_NOT_OPENED_IN_READ_MODE:
- return pdFREERTOS_ERRNO_EACCES; /* 36. */
- case FF_ERR_FILE_EXTEND_FAILED:
- return pdFREERTOS_ERRNO_ENOSPC; /* Could not extend the file. */
- case FF_ERR_FILE_DESTINATION_EXISTS:
- return pdFREERTOS_ERRNO_EEXIST; /* 38. */
- case FF_ERR_FILE_SOURCE_NOT_FOUND:
- return pdFREERTOS_ERRNO_ENOENT; /* 39. */
- case FF_ERR_FILE_DIR_NOT_FOUND:
- return pdFREERTOS_ERRNO_ENOENT; /* 40. */
- case FF_ERR_FILE_COULD_NOT_CREATE_DIRENT:
- return pdFREERTOS_ERRNO_EIO; /* 41. */
- case FF_ERR_FILE_BAD_HANDLE:
- return pdFREERTOS_ERRNO_EBADF; /* A file handle was invalid. */
- case FF_ERR_FILE_MEDIA_REMOVED:
- return pdFREERTOS_ERRNO_ENODEV; /* File handle got invalid because media was removed. */
- case FF_ERR_FILE_SEEK_INVALID_POSITION:
- return pdFREERTOS_ERRNO_ESPIPE; /* Illegal position, outside the file's space */
- case FF_ERR_FILE_SEEK_INVALID_ORIGIN:
- return pdFREERTOS_ERRNO_EINVAL; /* Seeking beyond end of file. */
- /* Directory Error Codes 50 +. */
- case FF_ERR_DIR_OBJECT_EXISTS:
- return pdFREERTOS_ERRNO_EEXIST; /* A file or folder of the same name already exists in the current directory. */
- case FF_ERR_DIR_DIRECTORY_FULL:
- return pdFREERTOS_ERRNO_ENOSPC; /* No more items could be added to the directory. */
- case FF_ERR_DIR_END_OF_DIR:
- return pdFREERTOS_ERRNO_ENMFILE; /*/. */
- case FF_ERR_DIR_NOT_EMPTY:
- return pdFREERTOS_ERRNO_ENOTEMPTY; /* Cannot delete a directory that contains files or folders. */
- case FF_ERR_DIR_INVALID_PATH:
- return pdFREERTOS_ERRNO_EINVAL; /* Could not find the directory specified by the path. */
- case FF_ERR_DIR_CANT_EXTEND_ROOT_DIR:
- return pdFREERTOS_ERRNO_ENOSPC; /* Can't extend the root dir. */
- case FF_ERR_DIR_EXTEND_FAILED:
- return pdFREERTOS_ERRNO_ENOSPC; /* Not enough space to extend the directory. */
- case FF_ERR_DIR_NAME_TOO_LONG:
- return pdFREERTOS_ERRNO_ENAMETOOLONG; /* Name exceeds the number of allowed characters for a filename. */
- /* Fat Error Codes 70 +. */
- case FF_ERR_FAT_NO_FREE_CLUSTERS:
- return pdFREERTOS_ERRNO_ENOSPC; /* No more free space is available on the disk. */
- /* UNICODE Error Codes 100 +. */
- case FF_ERR_UNICODE_INVALID_CODE:
- return pdFREERTOS_ERRNO_EBADE; /* An invalid Unicode character was provided!. */
- case FF_ERR_UNICODE_DEST_TOO_SMALL:
- return pdFREERTOS_ERRNO_ENOBUFS; /* Not enough space in the UTF-16 buffer to encode the entire sequence as UTF-16. */
- case FF_ERR_UNICODE_INVALID_SEQUENCE:
- return pdFREERTOS_ERRNO_EILSEQ; /* An invalid UTF-16 sequence was encountered. */
- case FF_ERR_UNICODE_CONVERSION_EXCEEDED:
- return pdFREERTOS_ERRNO_ENAMETOOLONG; /* Filename exceeds MAX long-filename length when converted to UTF-16. */
- }
- return pdFREERTOS_ERRNO_EFAULT;
- }
- /*-----------------------------------------------------------*/
- #if ( ffconfigHAS_CWD == 1 )
- void ff_free_CWD_space( void )
- {
- WorkingDirectory_t * pxSpace;
- /* Obtain the CWD used by the current task. */
- pxSpace = ( WorkingDirectory_t * ) pvTaskGetThreadLocalStoragePointer( NULL, stdioCWD_THREAD_LOCAL_OFFSET );
- if( pxSpace != NULL )
- {
- vTaskSetThreadLocalStoragePointer( NULL, stdioCWD_THREAD_LOCAL_OFFSET, ( void * ) NULL );
- ffconfigFREE( pxSpace );
- }
- }
- #endif /* ffconfigHAS_CWD */
- /*-----------------------------------------------------------*/
- #if ( ffconfigHAS_CWD == 1 )
- static WorkingDirectory_t * pxFindCWD( void )
- {
- WorkingDirectory_t * pxReturn;
- /* Obtain the CWD used by the current task. */
- pxReturn = ( WorkingDirectory_t * ) pvTaskGetThreadLocalStoragePointer( NULL, stdioCWD_THREAD_LOCAL_OFFSET );
- if( pxReturn == NULL )
- {
- /* This task does not yet have a WorkingDirectory_t structure - create and
- * initialise one now. */
- pxReturn = ( WorkingDirectory_t * ) ffconfigMALLOC( sizeof( WorkingDirectory_t ) );
- if( pxReturn != NULL )
- {
- pxReturn->pcCWD[ 0 ] = '\0';
- vTaskSetThreadLocalStoragePointer( NULL, stdioCWD_THREAD_LOCAL_OFFSET, ( void * ) pxReturn );
- }
- }
- return pxReturn;
- }
- #endif /* ffconfigHAS_CWD */
- /*-----------------------------------------------------------*/
- #if ( ffconfigHAS_CWD == 1 )
- static const char * prvProcessRelativePaths( const char * pcPath )
- {
- const char * pcReturn;
- char * pcChar, * pcTokenStart = NULL, * pcFollowingToken, cPreviousChar = 0x00;
- BaseType_t xByte;
- /* Scan the string looking for a relative path. */
- pcReturn = pcPath;
- pcChar = ( char * ) pcReturn;
- configASSERT( pcPath );
- while( *pcChar != 0x00 )
- {
- if( *pcChar == '.' )
- {
- /* A potential relative path was found. Is this a "." or a "..". */
- if( *( pcChar + 1 ) == '.' )
- {
- /* Nothing can be done if this is at the start of the string. */
- if( pcTokenStart != NULL )
- {
- /* A ".." was found. Where does the next token start? */
- pcFollowingToken = pcChar + 2;
- if( *pcFollowingToken == '/' )
- {
- /* The next token starts after the "../" */
- pcFollowingToken += sizeof( char );
- }
- /* Remove the ".." and the previous token. */
- xByte = 0;
- while( pcFollowingToken[ xByte ] != 0x00 )
- {
- pcTokenStart[ xByte ] = pcFollowingToken[ xByte ];
- xByte++;
- }
- /* Terminate. */
- pcTokenStart[ xByte ] = 0x00;
- /* The pointer to the previous token will now be wrong if
- * there are multiple if "../.." appears in the string. So
- * reset the variables to continue scanning. */
- pcChar = ( char * ) pcReturn;
- cPreviousChar = 0x00;
- pcTokenStart = NULL;
- continue;
- }
- }
- else
- {
- /* A "." was found. Remove it. */
- }
- }
- if( cPreviousChar == '/' )
- {
- /* This is the start of a new token. */
- pcTokenStart = pcChar;
- }
- cPreviousChar = *pcChar;
- pcChar++;
- }
- /* Make sure there is no / on the end of the string, being careful not to
- * remove the / at the beginning of the string. */
- if( *( pcChar - 1 ) == '/' )
- {
- if( ( pcChar - 1 ) != pcReturn )
- {
- *( pcChar - 1 ) = 0x00;
- }
- }
- return pcReturn;
- }
- #endif /* ffconfigHAS_CWD */
- /*-----------------------------------------------------------*/
- #if ( ffconfigHAS_CWD == 1 )
- /*static*/ const char * prvABSPath( const char * pcPath )
- {
- char * pcReturn;
- WorkingDirectory_t * pxWorkingDirectory = pxFindCWD();
- configASSERT( pxWorkingDirectory );
- if( ( pcPath[ 0 ] ) == '/' )
- {
- /* If the path starts with a slash it does not start with a relative
- * path. Copy the string into a thread local buffer so it can be
- * manipulated without risk of attempting to write to read only
- * memory. */
- snprintf( pxWorkingDirectory->pcFileName, sizeof( pxWorkingDirectory->pcFileName ), "%s", pcPath );
- pcReturn = pxWorkingDirectory->pcFileName;
- }
- else
- {
- /* Insert the working directory into the front of the path. */
- if( pxWorkingDirectory->pcCWD[ 1 ] == 0x00 )
- {
- /* In the root, so don't add a '/' between the CWD and the
- * file name. */
- snprintf( pxWorkingDirectory->pcFileName, sizeof( pxWorkingDirectory->pcFileName ), "/%s", pcPath );
- }
- else
- {
- snprintf( pxWorkingDirectory->pcFileName, sizeof( pxWorkingDirectory->pcFileName ), "%s/%s", pxWorkingDirectory->pcCWD, pcPath );
- }
- pcReturn = pxWorkingDirectory->pcFileName;
- }
- /* Make any adjustments necessitated by relative paths. */
- prvProcessRelativePaths( pcReturn );
- return pcReturn;
- }
- #endif /* ffconfigHAS_CWD */
- #if ( ffconfigTIME_SUPPORT == 1 )
- static uint32_t prvFileTime( FF_SystemTime_t * pxTime )
- {
- FF_TimeStruct_t xTime;
- time_t xReturn;
- xTime.tm_sec = pxTime->Second;
- xTime.tm_min = pxTime->Minute;
- xTime.tm_hour = pxTime->Hour;
- xTime.tm_mday = pxTime->Day;
- xTime.tm_mon = pxTime->Month - 1;
- xTime.tm_year = pxTime->Year - 1900;
- xReturn = FreeRTOS_mktime( &xTime );
- return xReturn;
- }
- #endif /* if ( ffconfigTIME_SUPPORT == 1 ) */
- /*-----------------------------------------------------------*/
|