| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318 |
- /*
- * 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
- *
- */
- /**
- * @file ff_file.c
- * @ingroup FILEIO
- *
- * @defgroup FILEIO FILE I/O Access
- * @brief Provides an interface to allow File I/O on a mounted IOMAN.
- *
- * Provides file-system interfaces for the FAT file-system.
- **/
- #include "ff_headers.h"
- #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
- #include <wchar.h>
- #endif
- static FF_Error_t FF_Truncate( FF_FILE * pxFile,
- BaseType_t bClosing );
- static int32_t FF_ReadPartial( FF_FILE * pxFile,
- uint32_t ulItemLBA,
- uint32_t ulRelBlockPos,
- uint32_t ulCount,
- uint8_t * pucBuffer,
- FF_Error_t * pxError );
- static int32_t FF_WritePartial( FF_FILE * pxFile,
- uint32_t ulItemLBA,
- uint32_t ulRelBlockPos,
- uint32_t ulCount,
- const uint8_t * pucBuffer,
- FF_Error_t * pxError );
- static uint32_t FF_SetCluster( FF_FILE * pxFile,
- FF_Error_t * pxError );
- static uint32_t FF_FileLBA( FF_FILE * pxFile );
- static FF_Error_t FF_ExtendFile( FF_FILE * pxFile,
- uint32_t ulSize );
- /*-----------------------------------------------------------*/
- /**
- * @public
- * @brief Converts STDIO mode strings into the equivalent FreeRTOS+FAT mode.
- *
- * @param Mode The mode string e.g. "rb" "rb+" "w" "a" "r" "w+" "a+" etc
- *
- * @return Returns the mode bits that should be passed to the FF_Open function.
- **/
- uint8_t FF_GetModeBits( const char * pcMode )
- {
- uint8_t ucModeBits = 0x00;
- while( *pcMode != '\0' )
- {
- switch( *pcMode )
- {
- case 'r': /* Allow Read. */
- case 'R':
- ucModeBits |= FF_MODE_READ;
- break;
- case 'w': /* Allow Write. */
- case 'W':
- ucModeBits |= FF_MODE_WRITE;
- ucModeBits |= FF_MODE_CREATE; /* Create if not exist. */
- ucModeBits |= FF_MODE_TRUNCATE;
- break;
- case 'a': /* Append new writes to the end of the file. */
- case 'A':
- ucModeBits |= FF_MODE_WRITE;
- ucModeBits |= FF_MODE_APPEND;
- ucModeBits |= FF_MODE_CREATE; /* Create if not exist. */
- break;
- case '+': /* Update the file, don't Append! */
- ucModeBits |= FF_MODE_READ;
- ucModeBits |= FF_MODE_WRITE; /* RW Mode. */
- break;
- case 'D':
- /* Internal use only! */
- ucModeBits |= FF_MODE_DIR;
- break;
- case 'b':
- case 'B':
- /* b|B flags not supported (Binary mode is native anyway). */
- break;
- default:
- break;
- }
- pcMode++;
- }
- return ucModeBits;
- } /* FF_GetModeBits() */
- /*-----------------------------------------------------------*/
- static FF_FILE * prvAllocFileHandle( FF_IOManager_t * pxIOManager,
- FF_Error_t * pxError )
- {
- FF_FILE * pxFile;
- pxFile = ffconfigMALLOC( sizeof( FF_FILE ) );
- if( pxFile == NULL )
- {
- *pxError = ( FF_Error_t ) ( FF_ERR_NOT_ENOUGH_MEMORY | FF_OPEN );
- }
- else
- {
- memset( pxFile, 0, sizeof( *pxFile ) );
- #if ( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 )
- {
- pxFile->pucBuffer = ( uint8_t * ) ffconfigMALLOC( pxIOManager->usSectorSize );
- if( pxFile->pucBuffer != NULL )
- {
- memset( pxFile->pucBuffer, 0, pxIOManager->usSectorSize );
- }
- else
- {
- *pxError = ( FF_Error_t ) ( FF_ERR_NOT_ENOUGH_MEMORY | FF_OPEN );
- ffconfigFREE( pxFile );
- /* Make sure that NULL will be returned. */
- pxFile = NULL;
- }
- }
- #else /* if ( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 ) */
- {
- /* Remove compiler warnings. */
- ( void ) pxIOManager;
- }
- #endif /* if ( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 ) */
- }
- return pxFile;
- } /* prvAllocFileHandle() */
- /*-----------------------------------------------------------*/
- /**
- * FF_Open() Mode Information
- * - FF_MODE_WRITE
- * - Allows WRITE access to the file.
- * .
- * - FF_MODE_READ
- * - Allows READ access to the file.
- * .
- * - FF_MODE_CREATE
- * - Create file if it doesn't exist.
- * .
- * - FF_MODE_TRUNCATE
- * - Erase the file if it already exists and overwrite.
- * *
- * - FF_MODE_APPEND
- * - Causes all writes to occur at the end of the file. (Its impossible to overwrite other data in a file with this flag set).
- * .
- * .
- *
- * Some sample modes:
- * - (FF_MODE_WRITE | FF_MODE_CREATE | FF_MODE_TRUNCATE)
- * - Write access to the file. (Equivalent to "w").
- * .
- * - (FF_MODE_WRITE | FF_MODE_READ)
- * - Read and Write access to the file. (Equivalent to "rb+").
- * .
- * - (FF_MODE_WRITE | FF_MODE_READ | FF_MODE_APPEND | FF_MODE_CREATE)
- * - Read and Write append mode access to the file. (Equivalent to "a+").
- * .
- * .
- * Be careful when choosing modes. For those using FF_Open() at the application layer
- * its best to use the provided FF_GetModeBits() function, as this complies to the same
- * behaviour as the stdio.h fopen() function.
- *
- **/
- /**
- * @public
- * @brief Opens a File for Access
- *
- * @param pxIOManager FF_IOManager_t object that was created by FF_CreateIOManger().
- * @param pcPath Path to the File or object.
- * @param ucMode Access Mode required. Modes are a little complicated, the function FF_GetModeBits()
- * @param ucMode will convert a stdio Mode string into the equivalent Mode bits for this parameter.
- * @param pxError Pointer to a signed byte for error checking. Can be NULL if not required.
- * @param pxError To be checked when a NULL pointer is returned.
- *
- * @return NULL pointer on error, in which case pxError should be checked for more information.
- * @return pxError can be:
- **/
- #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
- FF_FILE * FF_Open( FF_IOManager_t * pxIOManager,
- const FF_T_WCHAR * pcPath,
- uint8_t ucMode,
- FF_Error_t * pxError )
- #else
- FF_FILE * FF_Open( FF_IOManager_t * pxIOManager, const char * pcPath, uint8_t ucMode, FF_Error_t * pxError )
- #endif
- {
- FF_FILE * pxFile = NULL;
- FF_FILE * pxFileChain;
- FF_DirEnt_t xDirEntry;
- uint32_t ulFileCluster;
- FF_Error_t xError;
- BaseType_t xIndex;
- FF_FindParams_t xFindParams;
- #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
- FF_T_WCHAR pcFileName[ ffconfigMAX_FILENAME ];
- #else
- char pcFileName[ ffconfigMAX_FILENAME ];
- #endif
- memset( &xFindParams, '\0', sizeof( xFindParams ) );
- /* Inform the functions that the entry will be created if not found. */
- if( ( ucMode & FF_MODE_CREATE ) != 0 )
- {
- xFindParams.ulFlags |= FIND_FLAG_CREATE_FLAG;
- }
- if( pxIOManager == NULL )
- {
- /* Use the error function code 'FF_OPEN' as this static
- * function is only called from that function. */
- xError = ( FF_Error_t ) ( FF_ERR_NULL_POINTER | FF_OPEN );
- }
- #if ( ffconfigREMOVABLE_MEDIA != 0 )
- else if( ( pxIOManager->ucFlags & FF_IOMAN_DEVICE_IS_EXTRACTED ) != 0 )
- {
- xError = ( FF_Error_t ) ( FF_ERR_IOMAN_DRIVER_NOMEDIUM | FF_OPEN );
- }
- #endif /* ffconfigREMOVABLE_MEDIA */
- else
- {
- xError = FF_ERR_NONE;
- /* Let xIndex point to the last occurrence of '/' or '\',
- * to separate the path from the file name. */
- xIndex = ( BaseType_t ) STRLEN( pcPath );
- while( xIndex != 0 )
- {
- if( ( pcPath[ xIndex ] == '\\' ) || ( pcPath[ xIndex ] == '/' ) )
- {
- break;
- }
- xIndex--;
- }
- /* Copy the file name, i.e. the string that comes after the last separator. */
- STRNCPY( pcFileName, pcPath + xIndex + 1, ffconfigMAX_FILENAME );
- 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( pxIOManager, pcPath, xIndex, &xError );
- if( xFindParams.ulDirCluster == 0ul )
- {
- if( ( ucMode & FF_MODE_WRITE ) != 0 )
- {
- FF_PRINTF( "FF_Open[%s]: Path not found\n", pcPath );
- }
- /* The user tries to open a file but the path leading to the file does not exist. */
- }
- else if( FF_isERR( xError ) == pdFALSE )
- {
- /* Allocate an empty file handle and buffer space for 'unaligned access'. */
- pxFile = prvAllocFileHandle( pxIOManager, &xError );
- }
- }
- if( FF_isERR( xError ) == pdFALSE )
- {
- /* Copy the Mode Bits. */
- pxFile->ucMode = ucMode;
- /* See if the file does exist within the given directory. */
- ulFileCluster = FF_FindEntryInDir( pxIOManager, &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 )
- {
- /* The path is found, but it does not contain the file name yet.
- * Maybe the user wants to create it? */
- if( ( ucMode & FF_MODE_CREATE ) == 0 )
- {
- xError = ( FF_Error_t ) ( FF_ERR_FILE_NOT_FOUND | FF_OPEN );
- }
- else
- {
- ulFileCluster = FF_CreateFile( pxIOManager, &xFindParams, pcFileName, &xDirEntry, &xError );
- if( FF_isERR( xError ) == pdFALSE )
- {
- xDirEntry.usCurrentItem += 1;
- }
- }
- }
- }
- if( FF_isERR( xError ) == pdFALSE )
- {
- /* Now the file exists, or it has been created.
- * Check if the Mode flags are allowed: */
- if( ( xDirEntry.ucAttrib == FF_FAT_ATTR_DIR ) && ( ( ucMode & FF_MODE_DIR ) == 0 ) )
- {
- /* Not the object, File Not Found! */
- xError = ( FF_Error_t ) ( FF_ERR_FILE_OBJECT_IS_A_DIR | FF_OPEN );
- }
- /*---------- Ensure Read-Only files don't get opened for Writing. */
- else if( ( ( ucMode & ( FF_MODE_WRITE | FF_MODE_APPEND ) ) != 0 ) && ( ( xDirEntry.ucAttrib & FF_FAT_ATTR_READONLY ) != 0 ) )
- {
- xError = ( FF_Error_t ) ( FF_ERR_FILE_IS_READ_ONLY | FF_OPEN );
- }
- }
- if( FF_isERR( xError ) == pdFALSE )
- {
- pxFile->pxIOManager = pxIOManager;
- pxFile->ulFilePointer = 0;
- /* Despite the warning output by MSVC - it is not possible to get here
- * if xDirEntry has not been initialised. */
- pxFile->ulObjectCluster = xDirEntry.ulObjectCluster;
- pxFile->ulFileSize = xDirEntry.ulFileSize;
- pxFile->ulCurrentCluster = 0;
- pxFile->ulAddrCurrentCluster = pxFile->ulObjectCluster;
- pxFile->pxNext = NULL;
- pxFile->ulDirCluster = xFindParams.ulDirCluster;
- pxFile->usDirEntry = xDirEntry.usCurrentItem - 1;
- pxFile->ulChainLength = 0;
- pxFile->ulEndOfChain = 0;
- pxFile->ulValidFlags &= ~( FF_VALID_FLAG_DELETED );
- /* Add pxFile onto the end of our linked list of FF_FILE objects.
- * But first make sure that there are not 2 handles with write access
- * to the same object. */
- FF_PendSemaphore( pxIOManager->pvSemaphore );
- {
- pxFileChain = ( FF_FILE * ) pxIOManager->FirstFile;
- if( pxFileChain == NULL )
- {
- pxIOManager->FirstFile = pxFile;
- }
- else
- {
- for( ; ; )
- {
- /* See if two file handles point to the same object. */
- if( ( pxFileChain->ulObjectCluster == pxFile->ulObjectCluster ) &&
- ( pxFileChain->ulDirCluster == pxFile->ulDirCluster ) &&
- ( pxFileChain->usDirEntry == pxFile->usDirEntry ) )
- {
- /* Fail if any of the two has write access to the object. */
- if( ( ( pxFileChain->ucMode | pxFile->ucMode ) & ( FF_MODE_WRITE | FF_MODE_APPEND ) ) != 0 )
- {
- /* File is already open! DON'T ALLOW IT! */
- xError = ( FF_Error_t ) ( FF_ERR_FILE_ALREADY_OPEN | FF_OPEN );
- break;
- }
- }
- if( pxFileChain->pxNext == NULL )
- {
- pxFileChain->pxNext = pxFile;
- break;
- }
- pxFileChain = ( FF_FILE * ) pxFileChain->pxNext;
- }
- }
- }
- FF_ReleaseSemaphore( pxIOManager->pvSemaphore );
- }
- if( FF_isERR( xError ) == pdFALSE )
- {
- /* If the file is opened with the truncate flag, truncate its contents. */
- if( ( ucMode & FF_MODE_TRUNCATE ) != 0 )
- {
- /* Set the current size and position to zero. */
- pxFile->ulFileSize = 0;
- pxFile->ulFilePointer = 0;
- }
- }
- if( FF_isERR( xError ) != pdFALSE )
- {
- if( pxFile != NULL )
- {
- #if ( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 )
- {
- ffconfigFREE( pxFile->pucBuffer );
- }
- #endif
- ffconfigFREE( pxFile );
- }
- pxFile = NULL;
- }
- if( pxError != NULL )
- {
- *pxError = xError;
- }
- return pxFile;
- } /* FF_Open() */
- /*-----------------------------------------------------------*/
- /**
- * @public
- * @brief Tests if a Directory contains any other files or folders.
- *
- * @param pxIOManager FF_IOManager_t object returned from the FF_CreateIOManger() function.
- *
- **/
- #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
- BaseType_t FF_isDirEmpty( FF_IOManager_t * pxIOManager,
- const FF_T_WCHAR * pcPath )
- #else
- BaseType_t FF_isDirEmpty( FF_IOManager_t * pxIOManager,
- const char * pcPath )
- #endif
- {
- FF_DirEnt_t xDirEntry;
- FF_Error_t xError = FF_ERR_NONE;
- BaseType_t xReturn;
- if( pxIOManager == NULL )
- {
- xReturn = pdFALSE;
- }
- else
- {
- xError = FF_FindFirst( pxIOManager, &xDirEntry, pcPath );
- /* Assume the directory is empty until a file is
- * encountered with a name other than ".." or "." */
- xReturn = pdTRUE;
- while( xError == 0 )
- {
- /* As we can't be sure the first 2 entries contain
- * "." and "..", check it, not just count them
- */
- #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
- if( ( wcscmp( xDirEntry.pcFileName, L".." ) != 0 ) && ( wcscmp( xDirEntry.pcFileName, L"." ) != 0 ) )
- #else
- if( ( strcmp( xDirEntry.pcFileName, ".." ) != 0 ) && ( strcmp( xDirEntry.pcFileName, "." ) != 0 ) )
- #endif
- {
- xReturn = pdFALSE;
- break;
- }
- xError = FF_FindNext( pxIOManager, &xDirEntry );
- }
- }
- return xReturn;
- } /* FF_isDirEmpty() */
- /*-----------------------------------------------------------*/
- #if ( ffconfigPATH_CACHE != 0 )
- /* _HT_ After a directory has been renamed, the path cache becomes out-of-date */
- #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
- static void FF_RmPathCache( FF_IOManager_t * pxIOManager,
- const FF_T_WCHAR * pcPath )
- #else
- static void FF_RmPathCache( FF_IOManager_t * pxIOManager,
- const char * pcPath )
- #endif
- {
- /*
- * The directory 'path' will be removed or renamed
- * now clear all entries starting with 'path' in the path cache
- */
- BaseType_t xIndex;
- BaseType_t pathLen = STRLEN( pcPath );
- FF_PendSemaphore( pxIOManager->pvSemaphore );
- {
- for( xIndex = 0; xIndex < ffconfigPATH_CACHE_DEPTH; xIndex++ )
- {
- BaseType_t len2 = STRLEN( pxIOManager->xPartition.pxPathCache[ xIndex ].pcPath );
- if( ( len2 >= pathLen ) && FF_strmatch( pxIOManager->xPartition.pxPathCache[ xIndex ].pcPath, pcPath, pathLen ) )
- {
- pxIOManager->xPartition.pxPathCache[ xIndex ].pcPath[ 0 ] = '\0';
- pxIOManager->xPartition.pxPathCache[ xIndex ].ulDirCluster = 0;
- }
- }
- }
- FF_ReleaseSemaphore( pxIOManager->pvSemaphore );
- }
- #endif /* ffconfigPATH_CACHE */
- /*-----------------------------------------------------------*/
- #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
- FF_Error_t FF_RmDir( FF_IOManager_t * pxIOManager,
- const FF_T_WCHAR * pcPath )
- #else
- FF_Error_t FF_RmDir( FF_IOManager_t * pxIOManager,
- const char * pcPath )
- #endif
- {
- FF_FILE * pxFile;
- uint8_t ucEntryBuffer[ 32 ];
- FF_FetchContext_t xFetchContext;
- FF_Error_t xError = FF_ERR_NONE;
- if( pxIOManager == NULL )
- {
- xError = ( FF_Error_t ) ( FF_ERR_NULL_POINTER | FF_RMDIR );
- }
- #if ( ffconfigREMOVABLE_MEDIA != 0 )
- else if( ( pxIOManager->ucFlags & FF_IOMAN_DEVICE_IS_EXTRACTED ) != 0 )
- {
- xError = ( FF_Error_t ) ( FF_ERR_IOMAN_DRIVER_NOMEDIUM | FF_RMDIR );
- }
- #endif /* ffconfigREMOVABLE_MEDIA */
- else
- {
- pxFile = FF_Open( pxIOManager, pcPath, FF_MODE_DIR, &xError );
- if( pxFile != NULL )
- {
- pxFile->ulValidFlags |= FF_VALID_FLAG_DELETED;
- /* Clear the struct to allow a call to FF_CleanupEntryFetch() in any
- * state. */
- memset( &xFetchContext, '\0', sizeof( xFetchContext ) );
- /* This task will get the unique right to change directories. */
- FF_LockDirectory( pxIOManager );
- do /* while( pdFALSE ) */
- {
- /* This while loop is only introduced to be able to use break
- * statements. */
- if( FF_isDirEmpty( pxIOManager, pcPath ) == pdFALSE )
- {
- xError = ( FF_ERR_DIR_NOT_EMPTY | FF_RMDIR );
- break;
- }
- FF_LockFAT( pxIOManager );
- #if ( ffconfigHASH_CACHE != 0 )
- {
- /* A directory is removed so invalidate any hash table
- * referring to this directory. */
- FF_UnHashDir( pxIOManager, pxFile->ulObjectCluster );
- }
- #endif /* ffconfigHASH_CACHE */
- {
- /* Add parameter 0 to delete the entire chain!
- * The actual directory entries on disk will be freed. */
- xError = FF_UnlinkClusterChain( pxIOManager, pxFile->ulObjectCluster, 0 );
- }
- FF_UnlockFAT( pxIOManager );
- if( FF_isERR( xError ) )
- {
- break;
- }
- /* Now remove this directory from its parent directory.
- * Initialise the dirent Fetch Context object for faster removal of
- * dirents. */
- xError = FF_InitEntryFetch( pxIOManager, pxFile->ulDirCluster, &xFetchContext );
- if( FF_isERR( xError ) )
- {
- break;
- }
- #if ( ffconfigHASH_CACHE != 0 )
- {
- /* Invalidate any hash table of the parent directory
- * as well. */
- FF_UnHashDir( pxIOManager, pxFile->ulDirCluster );
- }
- #endif /* ffconfigHASH_CACHE */
- /* Edit the Directory Entry, so it will show as deleted.
- * First remove the LFN entries: */
- xError = FF_RmLFNs( pxIOManager, pxFile->usDirEntry, &xFetchContext );
- if( FF_isERR( xError ) )
- {
- break;
- }
- /* And remove the Short file name entry: */
- xError = FF_FetchEntryWithContext( pxIOManager, pxFile->usDirEntry, &xFetchContext, ucEntryBuffer );
- if( FF_isERR( xError ) == pdFALSE )
- {
- ucEntryBuffer[ 0 ] = FF_FAT_DELETED;
- FF_putShort( ucEntryBuffer, FF_FAT_DIRENT_CLUS_HIGH, ( uint32_t ) 0ul );
- FF_putShort( ucEntryBuffer, FF_FAT_DIRENT_CLUS_LOW, ( uint32_t ) 0ul );
- xError = FF_PushEntryWithContext( pxIOManager, pxFile->usDirEntry, &xFetchContext, ucEntryBuffer );
- }
- if( FF_isERR( xError ) )
- {
- break;
- }
- #if ( ffconfigPATH_CACHE != 0 )
- {
- /* We're removing a directory which might contain
- * subdirectories. Instead of iterating through all
- * subdirectories, just clear the path cache. */
- FF_RmPathCache( pxIOManager, pcPath );
- }
- #endif
- } while( pdFALSE );
- {
- FF_Error_t xTempError;
- xTempError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext );
- if( FF_isERR( xError ) == pdFALSE )
- {
- xError = xTempError;
- }
- FF_UnlockDirectory( pxIOManager );
- /* Free the file pointer resources. */
- xTempError = FF_Close( pxFile );
- if( FF_isERR( xError ) == pdFALSE )
- {
- xError = xTempError;
- }
- xTempError = FF_FlushCache( pxIOManager );
- if( FF_isERR( xError ) == pdFALSE )
- {
- xError = xTempError;
- }
- }
- } /* if( pxFile != NULL ) */
- } /* else if( pxIOManager != NULL ) */
- return xError;
- } /* FF_RmDir() */
- /*-----------------------------------------------------------*/
- #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
- FF_Error_t FF_RmFile( FF_IOManager_t * pxIOManager,
- const FF_T_WCHAR * pcPath )
- #else
- FF_Error_t FF_RmFile( FF_IOManager_t * pxIOManager,
- const char * pcPath )
- #endif
- {
- FF_FILE * pxFile;
- FF_Error_t xError = FF_ERR_NONE;
- uint8_t ucEntryBuffer[ 32 ];
- FF_FetchContext_t xFetchContext;
- /* Opening the file-to-be-deleted in WR mode has two advantages:
- * 1. The file handle gives all necessary information to delete it such
- * as the data clusters and directory entries.
- * 2. The file is now locked, it can not be opened by another task. */
- pxFile = FF_Open( pxIOManager, pcPath, FF_MODE_WRITE, &xError );
- if( pxFile != NULL )
- {
- /* FF_Close() will see this flag and won't do any disc access. */
- pxFile->ulValidFlags |= FF_VALID_FLAG_DELETED;
- /* Ensure there is actually a cluster chain to delete! */
- if( pxFile->ulObjectCluster != 0 )
- {
- /* Lock the FAT so its thread-safe. */
- FF_LockFAT( pxIOManager );
- {
- /* 0 to delete the entire chain! */
- xError = FF_UnlinkClusterChain( pxIOManager, pxFile->ulObjectCluster, 0 );
- }
- FF_UnlockFAT( pxIOManager );
- }
- if( FF_isERR( xError ) == pdFALSE )
- {
- /* Clear the struct to allow a call to FF_CleanupEntryFetch() in any
- * state. */
- memset( &xFetchContext, '\0', sizeof( xFetchContext ) );
- /* Get sole access to "directory changes" */
- FF_LockDirectory( pxIOManager );
- /* Edit the Directory Entry! (So it appears as deleted); */
- do
- {
- xError = FF_InitEntryFetch( pxIOManager, pxFile->ulDirCluster, &xFetchContext );
- if( FF_isERR( xError ) )
- {
- break;
- }
- #if ( ffconfigHASH_CACHE != 0 )
- {
- FF_UnHashDir( pxIOManager, pxFile->ulDirCluster );
- }
- #endif /* ffconfigHASH_CACHE */
- /* Remove LFN entries, if any. */
- xError = FF_RmLFNs( pxIOManager, ( uint16_t ) pxFile->usDirEntry, &xFetchContext );
- if( FF_isERR( xError ) )
- {
- break;
- }
- /* Remove the Short file name entry. */
- xError = FF_FetchEntryWithContext( pxIOManager, pxFile->usDirEntry, &xFetchContext, ucEntryBuffer );
- if( FF_isERR( xError ) == pdFALSE )
- {
- ucEntryBuffer[ 0 ] = FF_FAT_DELETED;
- FF_putShort( ucEntryBuffer, FF_FAT_DIRENT_CLUS_HIGH, ( uint32_t ) 0ul );
- FF_putShort( ucEntryBuffer, FF_FAT_DIRENT_CLUS_LOW, ( uint32_t ) 0ul );
- xError = FF_PushEntryWithContext( pxIOManager, pxFile->usDirEntry, &xFetchContext, ucEntryBuffer );
- }
- } while( pdFALSE );
- {
- FF_Error_t xTempError;
- xTempError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext );
- if( FF_isERR( xError ) == pdFALSE )
- {
- xError = xTempError;
- }
- FF_UnlockDirectory( pxIOManager );
- /* Free the file pointer resources. */
- xTempError = FF_Close( pxFile );
- if( FF_isERR( xError ) == pdFALSE )
- {
- xError = xTempError;
- }
- xTempError = FF_FlushCache( pxIOManager );
- if( FF_isERR( xError ) == pdFALSE )
- {
- xError = xTempError;
- }
- }
- }
- } /* if( pxFile != NULL ) */
- return xError;
- } /* FF_RmFile() */
- /*-----------------------------------------------------------*/
- /**
- * @public
- * @brief Moves a file or directory from source to destination.
- *
- * @param pxIOManager The FF_IOManager_t object pointer.
- * @param szSourceFile String of the source file to be moved or renamed.
- * @param szDestinationFile String of the destination file to where the source should be moved or renamed.
- *
- * @return FF_ERR_NONE on success.
- * @return FF_ERR_FILE_DESTINATION_EXISTS if the destination file exists.
- * @return FF_ERR_FILE_COULD_NOT_CREATE_DIRENT if dirent creation failed (fatal error!).
- * @return FF_ERR_FILE_DIR_NOT_FOUND if destination directory was not found.
- * @return FF_ERR_FILE_SOURCE_NOT_FOUND if the source file was not found.
- *
- **/
- #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
- FF_Error_t FF_Move( FF_IOManager_t * pxIOManager,
- const FF_T_WCHAR * szSourceFile,
- const FF_T_WCHAR * szDestinationFile,
- BaseType_t xDeleteIfExists )
- #else
- FF_Error_t FF_Move( FF_IOManager_t * pxIOManager,
- const char * szSourceFile,
- const char * szDestinationFile,
- BaseType_t xDeleteIfExists )
- #endif
- {
- FF_Error_t xError;
- FF_FILE * pSrcFile, * pxDestFile;
- FF_DirEnt_t xMyFile;
- uint8_t ucEntryBuffer[ 32 ];
- BaseType_t xIndex;
- uint32_t ulDirCluster = 0ul;
- FF_FetchContext_t xFetchContext;
- #if ( ffconfigPATH_CACHE != 0 )
- BaseType_t xIsDirectory = pdFALSE;
- #endif
- memset( &xFetchContext, '\0', sizeof( xFetchContext ) );
- if( pxIOManager == NULL )
- {
- xError = ( FF_Error_t ) ( FF_ERR_NULL_POINTER | FF_MOVE );
- }
- #if ( ffconfigREMOVABLE_MEDIA != 0 )
- else if( ( pxIOManager->ucFlags & FF_IOMAN_DEVICE_IS_EXTRACTED ) != 0 )
- {
- xError = ( FF_Error_t ) ( FF_ERR_IOMAN_DRIVER_NOMEDIUM | FF_MOVE );
- }
- #endif /* ffconfigREMOVABLE_MEDIA */
- else
- {
- /* Check destination file doesn't exist! */
- pxDestFile = FF_Open( pxIOManager, szDestinationFile, FF_MODE_READ, &xError );
- if( ( pxDestFile != NULL ) || ( FF_GETERROR( xError ) == FF_ERR_FILE_OBJECT_IS_A_DIR ) )
- {
- xError = ( FF_Error_t ) ( FF_ERR_FILE_DESTINATION_EXISTS | FF_MOVE );
- if( pxDestFile != NULL )
- {
- FF_Close( pxDestFile );
- if( xDeleteIfExists != pdFALSE )
- {
- xError = FF_RmFile( pxIOManager, szDestinationFile );
- }
- }
- }
- else
- {
- /* Discard the error set by FF_Open().
- * The target file (or directory) is not found: continue renaming. */
- xError = FF_ERR_NONE;
- }
- }
- if( FF_isERR( xError ) == pdFALSE )
- {
- /* About to move/rename 'szSourceFile'. When opening it with 'FF_MODE_WRITE'
- * only succeeds if it has no other open handle to it. */
- pSrcFile = FF_Open( pxIOManager, szSourceFile, FF_MODE_WRITE, &xError );
- if( FF_GETERROR( xError ) == FF_ERR_FILE_OBJECT_IS_A_DIR )
- {
- /* Open a directory for moving! */
- pSrcFile = FF_Open( pxIOManager, szSourceFile, FF_MODE_DIR, &xError );
- #if ( ffconfigPATH_CACHE != 0 )
- xIsDirectory = pdTRUE;
- #endif
- }
- if( pSrcFile != NULL )
- {
- /* Collect information about the current directory entry. */
- xError = FF_InitEntryFetch( pxIOManager, pSrcFile->ulDirCluster, &xFetchContext );
- if( FF_isERR( xError ) == pdFALSE )
- {
- xError = FF_FetchEntryWithContext( pxIOManager, pSrcFile->usDirEntry, &xFetchContext, ucEntryBuffer );
- if( FF_isERR( xError ) == pdFALSE )
- {
- xMyFile.ucAttrib = FF_getChar( ucEntryBuffer, ( uint16_t ) ( FF_FAT_DIRENT_ATTRIB ) );
- xMyFile.ulFileSize = pSrcFile->ulFileSize;
- xMyFile.ulObjectCluster = pSrcFile->ulObjectCluster;
- xMyFile.usCurrentItem = 0;
- xIndex = ( BaseType_t ) STRLEN( szDestinationFile );
- while( xIndex != 0 )
- {
- if( ( szDestinationFile[ xIndex ] == '\\' ) || ( szDestinationFile[ xIndex ] == '/' ) )
- {
- break;
- }
- xIndex--;
- }
- /* Copy the base name of the destination file. */
- STRNCPY( xMyFile.pcFileName, ( szDestinationFile + xIndex + 1 ), ffconfigMAX_FILENAME );
- if( xIndex == 0 )
- {
- xIndex = 1;
- }
- /* Find the (cluster of the) directory in which the target file will be located.
- * It must exist before calling FF_Move(). */
- ulDirCluster = FF_FindDir( pxIOManager, szDestinationFile, xIndex, &xError );
- }
- }
- }
- if( FF_isERR( xError ) == pdFALSE )
- {
- if( ulDirCluster != 0ul )
- {
- FF_FindParams_t xFindParams;
- memset( &xFindParams, '\0', sizeof( xFindParams ) );
- /* Clean up because FF_CreateDirent might want to write to the same sector. */
- xError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext );
- if( FF_isERR( xError ) == pdFALSE )
- {
- /* Destination directory was found, we can now create the new entry. */
- xFindParams.ulDirCluster = ulDirCluster;
- xError = FF_CreateDirent( pxIOManager, &xFindParams, &xMyFile );
- }
- if( FF_isERR( xError ) == pdFALSE )
- {
- /* Edit the Directory Entry! (So it appears as deleted); */
- FF_LockDirectory( pxIOManager );
- {
- xError = FF_RmLFNs( pxIOManager, pSrcFile->usDirEntry, &xFetchContext );
- if( FF_isERR( xError ) == pdFALSE )
- {
- xError = FF_FetchEntryWithContext( pxIOManager, pSrcFile->usDirEntry, &xFetchContext, ucEntryBuffer );
- if( FF_isERR( xError ) == pdFALSE )
- {
- FF_Error_t xTempError;
- ucEntryBuffer[ 0 ] = FF_FAT_DELETED;
- FF_putShort( ucEntryBuffer, FF_FAT_DIRENT_CLUS_HIGH, ( uint32_t ) 0ul );
- FF_putShort( ucEntryBuffer, FF_FAT_DIRENT_CLUS_LOW, ( uint32_t ) 0ul );
- xError = FF_PushEntryWithContext( pxIOManager, pSrcFile->usDirEntry, &xFetchContext, ucEntryBuffer );
- /* The contents of 'xFetchContext' has changed, flush it to disk now. */
- xTempError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext );
- if( FF_isERR( xError ) == pdFALSE )
- {
- xError = xTempError;
- }
- }
- }
- }
- FF_UnlockDirectory( pxIOManager );
- }
- #if ( ffconfigPATH_CACHE != 0 )
- {
- if( xIsDirectory != 0 )
- {
- /* We've renamed a directory which might contain
- * subdirectories. To avoid having false entries, clear
- * the path cache. */
- FF_RmPathCache( pxIOManager, szSourceFile );
- }
- }
- #endif
- }
- else /* ulDirCluster == 0ul */
- {
- xError = ( FF_Error_t ) ( FF_ERR_FILE_DIR_NOT_FOUND | FF_MOVE );
- }
- }
- if( pSrcFile != NULL )
- {
- /* The source file was opened in WRITE mode just to lock it.
- * Now clear the write flags to avoid writing back any changes. */
- pSrcFile->ucMode &= ~( FF_MODE_WRITE | FF_MODE_APPEND | FF_MODE_CREATE );
- FF_Close( pSrcFile );
- }
- }
- {
- FF_Error_t xTempError;
- xTempError = FF_FlushCache( pxIOManager );
- if( FF_isERR( xError ) == pdFALSE )
- {
- xError = xTempError;
- }
- xTempError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext );
- if( FF_isERR( xError ) == pdFALSE )
- {
- xError = xTempError;
- }
- }
- return xError;
- } /* FF_Move() */
- /*-----------------------------------------------------------*/
- /**
- * @public
- * @brief Get's the next Entry based on the data recorded in the FF_DirEnt_t object.
- *
- * @param pxFile FF_FILE object that was created by FF_Open().
- *
- * @return pdTRUE if End of File was reached. pdFALSE if not.
- * @return pdFALSE if a null pointer was provided.
- *
- **/
- BaseType_t FF_isEOF( FF_FILE * pxFile )
- {
- BaseType_t xReturn;
- if( ( pxFile != NULL ) && ( pxFile->ulFilePointer >= pxFile->ulFileSize ) )
- {
- xReturn = pdTRUE;
- }
- else
- {
- xReturn = pdFALSE;
- }
- return xReturn;
- } /* FF_isEOF() */
- /*-----------------------------------------------------------*/
- /**
- * @public
- * @brief Checks the number of bytes left on a read handle
- *
- * @param pxFile An open file handle
- *
- * @return Less than zero: an error code
- * @return Number of bytes left to read from handle
- **/
- int32_t FF_BytesLeft( FF_FILE * pxFile )
- {
- BaseType_t xReturn;
- if( pxFile == NULL )
- {
- xReturn = FF_ERR_NULL_POINTER | FF_BYTESLEFT;
- }
- else if( ( pxFile->ucMode & FF_MODE_READ ) == 0 )
- {
- xReturn = FF_ERR_FILE_NOT_OPENED_IN_READ_MODE | FF_BYTESLEFT;
- }
- else if( pxFile->ulFilePointer >= pxFile->ulFileSize )
- {
- xReturn = 0;
- }
- else
- {
- xReturn = pxFile->ulFileSize - pxFile->ulFilePointer;
- }
- return xReturn;
- } /* FF_BytesLeft() */
- /*-----------------------------------------------------------*/
- /**
- * @public
- * @brief Returns the file size of a read handle
- *
- * @param pxFile An open file handle
- *
- * @return Less than zero: an error code
- * @return Number of bytes left to read from handle
- **/
- FF_Error_t FF_GetFileSize( FF_FILE * pxFile,
- uint32_t * pulSize ) /* Writes # of bytes in a file to the parameter. */
- {
- BaseType_t xReturn;
- if( pxFile == NULL )
- {
- xReturn = ( FF_Error_t ) ( FF_ERR_NULL_POINTER | FF_BYTESLEFT );
- *( pulSize ) = ( uint32_t ) 0u;
- }
- else if( FF_isERR( FF_CheckValid( pxFile ) ) )
- {
- xReturn = ( FF_Error_t ) ( FF_ERR_FILE_BAD_HANDLE | FF_BYTESLEFT );
- *( pulSize ) = ( uint32_t ) 0u;
- }
- else
- {
- xReturn = 0;
- *( pulSize ) = pxFile->ulFileSize;
- }
- return xReturn;
- } /* FF_GetFileSize */
- int32_t FF_FileSize( FF_FILE * pxFile )
- {
- uint32_t ulLength;
- FF_Error_t xResult;
- /* Function is deprecated. Please use FF_GetFileSize(). */
- xResult = FF_GetFileSize( pxFile, &( ulLength ) );
- if( FF_isERR( xResult ) == 0 )
- {
- xResult = ( int32_t ) ulLength;
- }
- return ( int32_t ) xResult;
- } /* FF_FileSize() */
- /*-----------------------------------------------------------*/
- static uint32_t FF_GetSequentialClusters( FF_IOManager_t * pxIOManager,
- uint32_t ulStartCluster,
- uint32_t ulLimit,
- FF_Error_t * pxError )
- {
- uint32_t ulCurrentCluster;
- uint32_t ulNextCluster = ulStartCluster;
- uint32_t ulIndex = 0;
- FF_FATBuffers_t xFATBuffers;
- FF_InitFATBuffers( &xFATBuffers, FF_MODE_READ );
- *pxError = FF_ERR_NONE;
- FF_LockFAT( pxIOManager );
- do
- {
- ulCurrentCluster = ulNextCluster;
- ulNextCluster = FF_getFATEntry( pxIOManager, ulCurrentCluster, pxError, &xFATBuffers );
- if( FF_isERR( *pxError ) )
- {
- ulIndex = 0;
- break;
- }
- if( ulNextCluster == ( ulCurrentCluster + 1 ) )
- {
- ulIndex++;
- }
- else
- {
- break;
- }
- if( ( ulLimit != 0 ) && ( ulIndex == ulLimit ) )
- {
- break;
- }
- }
- while( ulNextCluster == ( ulCurrentCluster + 1 ) );
- FF_UnlockFAT( pxIOManager );
- *pxError = FF_ReleaseFATBuffers( pxIOManager, &xFATBuffers );
- return ulIndex;
- } /* FF_GetSequentialClusters() */
- /*-----------------------------------------------------------*/
- static FF_Error_t FF_ReadClusters( FF_FILE * pxFile,
- uint32_t ulCount,
- uint8_t * buffer )
- {
- uint32_t ulSectors;
- uint32_t ulSequentialClusters = 0;
- uint32_t ulItemLBA;
- FF_Error_t xError = FF_ERR_NONE;
- while( ulCount != 0 )
- {
- if( ( ulCount - 1 ) > 0 )
- {
- ulSequentialClusters =
- FF_GetSequentialClusters( pxFile->pxIOManager, pxFile->ulAddrCurrentCluster, ulCount - 1, &xError );
- if( FF_isERR( xError ) )
- {
- break;
- }
- }
- ulSectors = ( ulSequentialClusters + 1 ) * pxFile->pxIOManager->xPartition.ulSectorsPerCluster;
- ulItemLBA = FF_Cluster2LBA( pxFile->pxIOManager, pxFile->ulAddrCurrentCluster );
- ulItemLBA = FF_getRealLBA( pxFile->pxIOManager, ulItemLBA );
- xError = FF_BlockRead( pxFile->pxIOManager, ulItemLBA, ulSectors, buffer, pdFALSE );
- if( FF_isERR( xError ) )
- {
- break;
- }
- ulCount -= ( ulSequentialClusters + 1 );
- FF_LockFAT( pxFile->pxIOManager );
- {
- pxFile->ulAddrCurrentCluster =
- FF_TraverseFAT( pxFile->pxIOManager, pxFile->ulAddrCurrentCluster, ulSequentialClusters + 1, &xError );
- }
- FF_UnlockFAT( pxFile->pxIOManager );
- if( FF_isERR( xError ) )
- {
- break;
- }
- pxFile->ulCurrentCluster += ( ulSequentialClusters + 1 );
- buffer += ulSectors * pxFile->pxIOManager->usSectorSize;
- ulSequentialClusters = 0;
- }
- return xError;
- } /* FF_ReadClusters ()*/
- /*-----------------------------------------------------------*/
- 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.
- */
- 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() */
- /*-----------------------------------------------------------*/
- static FF_Error_t FF_WriteClusters( FF_FILE * pxFile,
- uint32_t ulCount,
- uint8_t * buffer )
- {
- uint32_t ulSectors;
- uint32_t ulSequentialClusters = 0;
- uint32_t ulItemLBA;
- FF_Error_t xError = FF_ERR_NONE;
- while( ulCount != 0 )
- {
- if( ulCount > 1U )
- {
- ulSequentialClusters =
- FF_GetSequentialClusters( pxFile->pxIOManager, pxFile->ulAddrCurrentCluster, ulCount - 1, &xError );
- if( FF_isERR( xError ) )
- {
- break;
- }
- }
- else
- {
- /* Handling the last cluster which is a single one. */
- }
- ulSectors = ( ulSequentialClusters + 1 ) * pxFile->pxIOManager->xPartition.ulSectorsPerCluster;
- ulItemLBA = FF_Cluster2LBA( pxFile->pxIOManager, pxFile->ulAddrCurrentCluster );
- ulItemLBA = FF_getRealLBA( pxFile->pxIOManager, ulItemLBA );
- xError = FF_BlockWrite( pxFile->pxIOManager, ulItemLBA, ulSectors, buffer, pdFALSE );
- if( FF_isERR( xError ) )
- {
- break;
- }
- ulCount -= ulSequentialClusters + 1;
- FF_LockFAT( pxFile->pxIOManager );
- {
- pxFile->ulAddrCurrentCluster =
- FF_TraverseFAT( pxFile->pxIOManager, pxFile->ulAddrCurrentCluster, ulSequentialClusters + 1, &xError );
- }
- FF_UnlockFAT( pxFile->pxIOManager );
- if( FF_isERR( xError ) )
- {
- break;
- }
- pxFile->ulCurrentCluster += ( ulSequentialClusters + 1 );
- buffer += ulSectors * pxFile->pxIOManager->usSectorSize;
- ulSequentialClusters = 0;
- }
- return xError;
- } /* FF_WriteClusters */
- /*-----------------------------------------------------------*/
- /**
- * @private
- * @brief Calculate the Logical Block Address (LBA)
- *
- * @param pxFile The file handle
- *
- * @return LBA
- *
- * Must be set:
- * - pxFile->ulFilePointer : byte offset in file
- * - pxFile->ulAddrCurrentCluster : physical cluster on the partition
- **/
- static uint32_t FF_FileLBA( FF_FILE * pxFile )
- {
- uint32_t ulItemLBA;
- ulItemLBA = FF_Cluster2LBA( pxFile->pxIOManager, pxFile->ulAddrCurrentCluster );
- ulItemLBA += FF_getMajorBlockNumber( pxFile->pxIOManager, pxFile->ulFilePointer, 1 );
- ulItemLBA = FF_getRealLBA( pxFile->pxIOManager, ulItemLBA );
- ulItemLBA += FF_getMinorBlockNumber( pxFile->pxIOManager, pxFile->ulFilePointer, 1 );
- return ulItemLBA;
- } /* FF_FileLBA() */
- /*-----------------------------------------------------------*/
- /**
- * @private
- * @brief Depending on FilePointer, calculate CurrentCluster
- * @brief and traverse the FAT to find the right ulAddrCurrentCluster
- *
- * @param pxFile The file handle
- *
- * @return FF_ERR_NONE on success
- * @return Possible error returned by FF_TraverseFAT() or END_OF_DIR
- *
- * Side effects:
- * - pxFile->ulCurrentCluster : relative cluster number (0 <= Num < ulChainLength)
- * - pxFile->ulAddrCurrentCluster : fysical cluster on the partition
- **/
- static uint32_t FF_SetCluster( FF_FILE * pxFile,
- FF_Error_t * pxError )
- {
- FF_IOManager_t * pxIOManager = pxFile->pxIOManager;
- uint32_t ulNewCluster = FF_getClusterChainNumber( pxIOManager, pxFile->ulFilePointer, 1 );
- FF_Error_t xResult = FF_ERR_NONE;
- uint32_t ulReturn;
- if( ulNewCluster > pxFile->ulCurrentCluster )
- {
- FF_LockFAT( pxIOManager );
- {
- pxFile->ulAddrCurrentCluster = FF_TraverseFAT( pxIOManager, pxFile->ulAddrCurrentCluster,
- ulNewCluster - pxFile->ulCurrentCluster, &xResult );
- }
- FF_UnlockFAT( pxIOManager );
- }
- else if( ulNewCluster < pxFile->ulCurrentCluster )
- {
- FF_LockFAT( pxIOManager );
- {
- pxFile->ulAddrCurrentCluster = FF_TraverseFAT( pxIOManager, pxFile->ulObjectCluster, ulNewCluster, &xResult );
- }
- FF_UnlockFAT( pxIOManager );
- }
- else
- {
- /* Well positioned. */
- }
- if( FF_isERR( xResult ) == pdFALSE )
- {
- pxFile->ulCurrentCluster = ulNewCluster;
- ulReturn = FF_FileLBA( pxFile );
- }
- else
- {
- ulReturn = 0;
- }
- *pxError = xResult;
- return ulReturn;
- } /* FF_SetCluster() */
- /*-----------------------------------------------------------*/
- static int32_t FF_ReadPartial( FF_FILE * pxFile,
- uint32_t ulItemLBA,
- uint32_t ulRelBlockPos,
- uint32_t ulCount,
- uint8_t * pucBuffer,
- FF_Error_t * pxError )
- {
- FF_Error_t xError = FF_ERR_NONE;
- uint32_t ulBytesRead;
- /* Bytes to read are within a block and less than a block size. */
- #if ( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 )
- {
- BaseType_t xLastRead;
- /* Optimised method: each file handle holds one data block
- * in cache: 'pxFile->pucBuffer'. */
- /* See if the current block will be accessed after this read: */
- if( ( ulRelBlockPos + ulCount ) >= ( uint32_t ) pxFile->pxIOManager->usSectorSize )
- {
- /* After this read, ulFilePointer will point to the next block/sector. */
- xLastRead = pdTRUE;
- }
- else
- {
- /* It is not the last read within this block/sector. */
- xLastRead = pdFALSE;
- }
- if( ( pxFile->ucState & FF_BUFSTATE_VALID ) == 0 )
- {
- xError = FF_BlockRead( pxFile->pxIOManager, ulItemLBA, 1, pxFile->pucBuffer, pdFALSE );
- if( FF_isERR( xError ) == pdFALSE )
- {
- pxFile->ucState = FF_BUFSTATE_VALID;
- }
- }
- if( ( pxFile->ucState & FF_BUFSTATE_VALID ) != 0 )
- {
- memcpy( pucBuffer, pxFile->pucBuffer + ulRelBlockPos, ulCount );
- pxFile->ulFilePointer += ulCount;
- ulBytesRead = ulCount;
- if( ( xLastRead == pdTRUE ) && ( ( pxFile->ucState & FF_BUFSTATE_WRITTEN ) != 0 ) )
- {
- /* If the data was changed (file in 'update' mode), store the changes: */
- xError = FF_BlockWrite( pxFile->pxIOManager, ulItemLBA, 1, pxFile->pucBuffer, pdFALSE );
- }
- }
- else
- {
- ulBytesRead = 0ul;
- }
- if( xLastRead == pdTRUE )
- {
- /* As the next FF_Read() will go passed the current block, invalidate the buffer now. */
- pxFile->ucState = FF_BUFSTATE_INVALID;
- }
- }
- #else /* if ( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 ) */
- {
- FF_Buffer_t * pxBuffer;
- /* Reading in the standard way, using FF_Buffer_t. */
- pxBuffer = FF_GetBuffer( pxFile->pxIOManager, ulItemLBA, FF_MODE_READ );
- if( pxBuffer == NULL )
- {
- xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_READ );
- ulBytesRead = 0ul;
- }
- else
- {
- memcpy( pucBuffer, pxBuffer->pucBuffer + ulRelBlockPos, ulCount );
- /* Releasing a buffer in FF_MODE_READ mode will not lead to an error,
- * because no disk access is needed. */
- xError = FF_ReleaseBuffer( pxFile->pxIOManager, pxBuffer );
- pxFile->ulFilePointer += ulCount;
- ulBytesRead = ulCount;
- }
- }
- #endif /* if ( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 ) */
- *pxError = xError;
- return ulBytesRead;
- } /* FF_ReadPartial() */
- /*-----------------------------------------------------------*/
- /**
- * @public
- * @brief Equivalent to fread()
- *
- * @param pxFile FF_FILE object that was created by FF_Open().
- * @param ulElementSize The size of an element to read.
- * @param ulCount The number of elements to read.
- * @param buffer A pointer to a buffer of adequate size to be filled with the requested data.
- *
- * @return Number of bytes read.
- *
- * FF_Read() and FF_Write() work very similar. They both complete their task in 5 steps:
- * 1. Read bytes up to a sector border: FF_ReadPartial()
- * 2. Read sectors up to cluster border: FF_BlockRead()
- * 3. Read complete clusters: FF_ReadClusters()
- * 4. Read remaining sectors: FF_BlockRead()
- * 5. Read remaining bytes: FF_ReadPartial()
- **/
- int32_t FF_Read( FF_FILE * pxFile,
- uint32_t ulElementSize,
- uint32_t ulCount,
- uint8_t * pucBuffer )
- {
- uint32_t ulBytesLeft = ulElementSize * ulCount;
- uint32_t ulBytesRead = 0;
- uint32_t ulBytesToRead;
- 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_READ ) == 0 )
- {
- /* File was not opened with READ mode access. */
- xError = ( FF_Error_t ) ( FF_ERR_FILE_NOT_OPENED_IN_READ_MODE | FF_READ );
- }
- else if( pxFile->ulFilePointer >= pxFile->ulFileSize )
- {
- /* The end-of-file is reached. The error READ_ZERO will not be
- * returned, it is just used to avoid further processing. */
- xError = ( FF_Error_t ) ( FF_ERR_FILE_READ_ZERO | FF_READ );
- }
- else if( ( pxFile->ulFilePointer + ulBytesLeft ) > pxFile->ulFileSize )
- {
- /* Note that many bytes can be read. */
- ulBytesLeft = pxFile->ulFileSize - pxFile->ulFilePointer;
- }
- }
- else
- {
- /* The file handle is not valid. */
- }
- } /* else pxFile != NULL */
- if( FF_isERR( xError ) == pdFALSE )
- {
- pxIOManager = pxFile->pxIOManager;
- /* And calculate the Logical Block Address. */
- ulItemLBA = FF_SetCluster( pxFile, &xError );
- /* Get the position within a block. */
- ulRelBlockPos = FF_getMinorBlockEntry( pxIOManager, pxFile->ulFilePointer, 1 );
- /* Open a do {} while( 0 ) loop to allow easy breaks: */
- do
- {
- if( ( ulRelBlockPos + ulBytesLeft ) <= ( uint32_t ) pxIOManager->usSectorSize )
- {
- /*---------- A small read within the current block only. */
- ulBytesRead = FF_ReadPartial( pxFile, ulItemLBA, ulRelBlockPos, ulBytesLeft, pucBuffer, &xError );
- break;
- }
- /*---------- Read (memcpy) to a Sector Boundary. */
- if( ulRelBlockPos != 0 )
- {
- /* Not on a sector boundary, at this point the LBA is known. */
- ulBytesToRead = pxIOManager->usSectorSize - ulRelBlockPos;
- ulBytesRead = FF_ReadPartial( pxFile, ulItemLBA, ulRelBlockPos, ulBytesToRead, pucBuffer, &xError );
- if( FF_isERR( xError ) )
- {
- break;
- }
- ulBytesLeft -= ulBytesRead;
- pucBuffer += ulBytesRead;
- }
- /*---------- Read sectors, up to a Cluster Boundary. */
- ulBytesPerCluster = ( pxIOManager->xPartition.ulSectorsPerCluster * pxIOManager->usSectorSize );
- ulRelClusterPos = pxFile->ulFilePointer % ( ulBytesPerCluster * pxIOManager->xPartition.ucBlkFactor );
- 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_BlockRead( pxIOManager, ulItemLBA, ulSectors, pucBuffer, pdFALSE );
- if( FF_isERR( xError ) )
- {
- break;
- }
- ulBytesToRead = ulSectors * pxIOManager->usSectorSize;
- ulBytesLeft -= ulBytesToRead;
- pucBuffer += ulBytesToRead;
- ulBytesRead += ulBytesToRead;
- pxFile->ulFilePointer += ulBytesToRead;
- }
- /*---------- Read entire clusters. */
- if( ulBytesLeft >= ulBytesPerCluster )
- {
- uint32_t ulClusters;
- FF_SetCluster( pxFile, &xError );
- if( FF_isERR( xError ) )
- {
- break;
- }
- ulClusters = ulBytesLeft / ulBytesPerCluster;
- xError = FF_ReadClusters( pxFile, ulClusters, pucBuffer );
- if( FF_isERR( xError ) )
- {
- break;
- }
- ulBytesToRead = ulBytesPerCluster * ulClusters;
- pxFile->ulFilePointer += ulBytesToRead;
- ulBytesLeft -= ulBytesToRead;
- pucBuffer += ulBytesToRead;
- ulBytesRead += ulBytesToRead;
- }
- /*---------- Read Remaining Blocks. */
- while( ulBytesLeft >= ( uint32_t ) pxIOManager->usSectorSize )
- {
- ulSectors = ulBytesLeft / pxIOManager->usSectorSize;
- {
- /* HT: I'd leave these pPart/ulOffset for readability */
- /* and shorter code lines */
- 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_BlockRead( pxIOManager, ulItemLBA, ulSectors, pucBuffer, pdFALSE );
- if( FF_isERR( xError ) )
- {
- break;
- }
- ulBytesToRead = ulSectors * pxIOManager->usSectorSize;
- pxFile->ulFilePointer += ulBytesToRead;
- ulBytesLeft -= ulBytesToRead;
- pucBuffer += ulBytesToRead;
- ulBytesRead += ulBytesToRead;
- }
- /*---------- Read (memcpy) Remaining Bytes */
- if( ulBytesLeft == 0 )
- {
- break;
- }
- ulItemLBA = FF_SetCluster( pxFile, &xError );
- if( FF_isERR( xError ) )
- {
- break;
- }
- /* Bytes to read are within a block and less than a block size. */
- FF_ReadPartial( pxFile, ulItemLBA, 0, ulBytesLeft, pucBuffer, &xError );
- if( FF_isERR( xError ) == pdFALSE )
- {
- ulBytesRead += ulBytesLeft;
- }
- }
- while( pdFALSE );
- } /* if( FF_isERR( xError ) == pdFALSE ) */
- if( FF_GETERROR( xError ) == FF_ERR_FILE_READ_ZERO )
- {
- lResult = 0;
- }
- else if( FF_isERR( xError ) )
- {
- lResult = xError;
- }
- else
- {
- lResult = ( int32_t ) ( ulBytesRead / ulElementSize );
- }
- return lResult;
- } /* FF_Read() */
- /*-----------------------------------------------------------*/
- /**
- * @public
- * @brief Equivalent to fgetc()
- *
- * @param pxFile FF_FILE object that was created by FF_Open().
- *
- * @return The character that was read (cast as a 32-bit interger). -1 on EOF.
- * @return FF_Error_t code. (Check with if(FF_isERR(xRetVal)) {}).
- * @return -1 EOF (end of file).
- *
- **/
- int32_t FF_GetC( FF_FILE * pxFile )
- {
- uint32_t ulItemLBA;
- uint8_t ucReturnedChar;
- uint32_t ulRelBlockPos;
- FF_Error_t xResult;
- if( pxFile == NULL )
- {
- xResult = FF_ERR_NULL_POINTER | FF_GETC; /* Ensure this is a signed error. */
- }
- else if( ( pxFile->ucMode & FF_MODE_READ ) == 0 )
- {
- xResult = FF_ERR_FILE_NOT_OPENED_IN_READ_MODE | FF_GETC;
- }
- else if( pxFile->ulFilePointer >= pxFile->ulFileSize )
- {
- /* The end-of-file is reached. The error READ_ZERO will not be
- * returned, it is just used to avoid further processing. */
- xResult = FF_ERR_FILE_READ_ZERO | FF_READ;
- }
- else
- {
- ulRelBlockPos = FF_getMinorBlockEntry( pxFile->pxIOManager, pxFile->ulFilePointer, 1 );
- ulItemLBA = FF_SetCluster( pxFile, &xResult );
- if( FF_isERR( xResult ) == pdFALSE )
- {
- FF_ReadPartial( pxFile, ulItemLBA, ulRelBlockPos, 1, &ucReturnedChar, &xResult );
- if( FF_isERR( xResult ) == pdFALSE )
- {
- xResult = ( int32_t ) ( ( uint32_t ) ucReturnedChar );
- }
- }
- }
- return ( int32_t ) xResult;
- } /* FF_GetC() */
- /*-----------------------------------------------------------*/
- /**
- * @public
- * @brief Gets a Line from a Text File, but no more than ulLimit characters. The line will be NULL terminated.
- *
- * The behaviour of this function is undefined when called on a binary file.
- * It should just read in ulLimit bytes of binary, and ZERO terminate the line.
- *
- * This function works for both UNIX line feeds, and Windows CRLF type files.
- *
- * @param pxFile The FF_FILE object pointer.
- * @param szLine The character buffer where the line should be stored.
- * @param ulLimit This should be the max number of characters that szLine can hold.
- *
- * @return The number of characters read from the line, on success.
- * @return 0 when no more lines are available, or when ulLimit is 0.
- * @return FF_ERR_NULL_POINTER if pxFile or szLine are NULL;
- *
- **/
- int32_t FF_GetLine( FF_FILE * pxFile,
- char * pcLine,
- uint32_t ulLimit )
- {
- int32_t iChar = 0;
- BaseType_t xIndex;
- FF_Error_t xResult = FF_ERR_NONE;
- if( ( pxFile == NULL ) || ( pcLine == NULL ) )
- {
- xResult = FF_ERR_NULL_POINTER | FF_GETLINE;
- }
- else
- {
- for( xIndex = 0; xIndex < ( BaseType_t ) ( ulLimit - 1 ); ++xIndex )
- {
- iChar = FF_GetC( pxFile );
- if( FF_isERR( iChar ) == pdFALSE )
- {
- pcLine[ xIndex ] = ( char ) iChar;
- if( iChar == '\n' )
- {
- /* Read until the first linefeed. Move xIndex forward so the
- * null terminator does not overwrite the \n. xIndex must be less
- * thank ( ulLimit - 1 ), so incrementing it here cannot make it
- * greater than ulLimit - 1, so the NULL can be inserted without
- * overflowing the buffer. */
- xIndex++;
- break;
- }
- }
- else
- {
- if( ( FF_GETERROR( iChar ) == FF_ERR_FILE_READ_ZERO ) && ( xIndex > 0 ) )
- {
- /* Although FF_GetC() returns an End Of File,
- * the last few characters will be returned first. */
- iChar = xIndex;
- }
- break;
- }
- }
- /* Make sure that the resulting string always ends with a zero: */
- pcLine[ xIndex ] = '\0';
- /*_RB_ In some paths this will be the second time FF_isERR() is called
- * on the same value. */
- if( FF_isERR( iChar ) == pdFALSE )
- {
- /* Return the number of bytes read. */
- xResult = xIndex;
- }
- else
- {
- /* Return iChar as an error code (see FF_GetC()). */
- xResult = iChar;
- }
- }
- return xResult;
- } /* FF_GetLine() */
- /*-----------------------------------------------------------*/
- static int32_t FF_WritePartial( FF_FILE * pxFile,
- uint32_t ulItemLBA,
- uint32_t ulRelBlockPos,
- uint32_t ulCount,
- const uint8_t * pucBuffer,
- FF_Error_t * pxError )
- {
- FF_Error_t xError;
- uint32_t ulBytesWritten;
- #if ( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 )
- {
- BaseType_t xLastRead;
- if( ( ulRelBlockPos + ulCount ) >= ( uint32_t ) pxFile->pxIOManager->usSectorSize )
- {
- /* After this read, ulFilePointer will point to the next block/sector. */
- xLastRead = pdTRUE;
- }
- else
- {
- /* It is not the last read within this block/sector. */
- xLastRead = pdFALSE;
- }
- if( ( ( pxFile->ucState & FF_BUFSTATE_VALID ) == 0 ) &&
- ( ( ulRelBlockPos != 0 ) || ( pxFile->ulFilePointer < pxFile->ulFileSize ) ) )
- {
- xError = FF_BlockRead( pxFile->pxIOManager, ulItemLBA, 1, pxFile->pucBuffer, pdFALSE );
- /* pxFile->ucState will be set later on. */
- }
- else
- {
- xError = FF_ERR_NONE;
- /* the buffer is valid or a whole block/sector will be written, so it is
- * not necessary to read the contents first. */
- }
- if( FF_isERR( xError ) == pdFALSE )
- {
- memcpy( pxFile->pucBuffer + ulRelBlockPos, pucBuffer, ulCount );
- if( xLastRead == pdTRUE )
- {
- xError = FF_BlockWrite( pxFile->pxIOManager, ulItemLBA, 1, pxFile->pucBuffer, pdFALSE );
- pxFile->ucState = FF_BUFSTATE_INVALID;
- }
- else
- {
- pxFile->ucState |= FF_BUFSTATE_WRITTEN | FF_BUFSTATE_VALID;
- }
- }
- else
- {
- pxFile->ucState = FF_BUFSTATE_INVALID;
- }
- }
- #else /* if ( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 ) */
- {
- FF_Buffer_t * pxBuffer;
- if( ( ulRelBlockPos == 0 ) && ( pxFile->ulFilePointer >= pxFile->ulFileSize ) )
- {
- /* An entire sector will be written. */
- pxBuffer = FF_GetBuffer( pxFile->pxIOManager, ulItemLBA, FF_MODE_WR_ONLY );
- }
- else
- {
- /* A partial write will be done, make sure to read the contents before
- * changing anything. */
- pxBuffer = FF_GetBuffer( pxFile->pxIOManager, ulItemLBA, FF_MODE_WRITE );
- }
- if( pxBuffer == NULL )
- {
- xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_WRITE );
- }
- else
- {
- /* Here we copy to the sector boundary. */
- memcpy( ( pxBuffer->pucBuffer + ulRelBlockPos ), pucBuffer, ulCount );
- xError = FF_ReleaseBuffer( pxFile->pxIOManager, pxBuffer );
- }
- }
- #endif /* if ( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 ) */
- if( FF_isERR( xError ) == pdFALSE )
- {
- pxFile->ulFilePointer += ulCount;
- ulBytesWritten = ulCount;
- if( pxFile->ulFilePointer > pxFile->ulFileSize )
- {
- pxFile->ulFileSize = pxFile->ulFilePointer;
- }
- }
- else
- {
- ulBytesWritten = 0ul;
- }
- *pxError = xError;
- return ulBytesWritten;
- } /* FF_WritePartial() */
- /*-----------------------------------------------------------*/
- /**
- * @public
- * @brief Writes data to a File.
- *
- * @param pxFile FILE Pointer.
- * @param ulElementSize Size of an Element of Data to be copied. (in bytes).
- * @param ulCount Number of Elements of Data to be copied. (ulElementSize * ulCount must not exceed ((2^31)-1) bytes. (2GB). For best performance, multiples of 512 bytes or Cluster sizes are best.
- * @param pucBuffer Byte-wise pucBuffer containing the data to be written.
- *
- * FF_Read() and FF_Write() work very similar. They both complete their task in 5 steps:
- * 1. Write bytes up to a sector border: FF_WritePartial()
- * 2. Write sectors up to cluster border: FF_BlockWrite()
- * 3. Write complete clusters: FF_WriteClusters()
- * 4. Write remaining sectors: FF_BlockWrite()
- * 5. Write remaining bytes: FF_WritePartial()
- * @return
- **/
- 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() */
- /*-----------------------------------------------------------*/
- /**
- * @public
- * @brief Writes a char to a FILE.
- *
- * @param pxFile FILE Pointer.
- * @param ucValue Char to be placed in the file.
- *
- * @return Returns the value written to the file, or a value less than 0.
- *
- **/
- int32_t FF_PutC( FF_FILE * pxFile,
- uint8_t ucValue )
- {
- uint32_t ulItemLBA;
- uint32_t ulRelBlockPos;
- FF_Error_t xResult;
- if( pxFile == NULL )
- { /* Ensure we don't have a Null file pointer on a Public interface. */
- xResult = FF_ERR_NULL_POINTER | FF_PUTC;
- }
- else if( ( pxFile->ucMode & FF_MODE_WRITE ) == 0 )
- {
- xResult = FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE | FF_PUTC;
- }
- else
- {
- xResult = FF_ERR_NONE;
- do
- {
- /* Make sure a write is after the append point. */
- if( ( pxFile->ucMode & FF_MODE_APPEND ) != 0 )
- {
- if( pxFile->ulFilePointer < pxFile->ulFileSize )
- {
- xResult = FF_Seek( pxFile, 0, FF_SEEK_END );
- if( FF_isERR( xResult ) )
- {
- break;
- }
- }
- }
- ulRelBlockPos = FF_getMinorBlockEntry( pxFile->pxIOManager, pxFile->ulFilePointer, 1 );
- /* Handle File Space Allocation. */
- /* We'll write 1 byte and always have a next cluster reserved. */
- xResult = FF_ExtendFile( pxFile, pxFile->ulFilePointer + 2 );
- if( FF_isERR( xResult ) )
- {
- break;
- }
- ulItemLBA = FF_SetCluster( pxFile, &xResult );
- if( FF_isERR( xResult ) )
- {
- break;
- }
- FF_WritePartial( pxFile, ulItemLBA, ulRelBlockPos, 1, &ucValue, &xResult );
- if( FF_isERR( xResult ) == pdFALSE )
- {
- xResult = ( FF_Error_t ) ucValue;
- }
- } while( pdFALSE );
- }
- return xResult;
- } /* FF_PutC() */
- /*-----------------------------------------------------------*/
- /**
- * @public
- * @brief Equivalent to fseek()
- *
- * @param pxFile FF_FILE object that was created by FF_Open().
- * @param ulOffset An integer (+/-) to seek to, from the specified origin.
- * @param xOrigin Where to seek from. (FF_SEEK_SET seek from start, FF_SEEK_CUR seek from current position, or FF_SEEK_END seek from end of file).
- *
- * @return 0 on Sucess,
- * @return -2 if offset results in an invalid position in the file.
- * @return FF_ERR_NULL_POINTER if a FF_FILE pointer was not received.
- * @return -3 if an invalid origin was provided.
- *
- **/
- FF_Error_t FF_Seek( FF_FILE * pxFile,
- int32_t lOffset,
- BaseType_t xOrigin )
- {
- FF_Error_t xError;
- uint32_t ulPosition = 0ul;
- xError = FF_CheckValid( pxFile );
- if( FF_isERR( xError ) == pdFALSE )
- {
- xError = FF_FlushCache( pxFile->pxIOManager );
- #if ( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 )
- {
- if( FF_isERR( xError ) == pdFALSE )
- {
- /* Here we must ensure that if the user tries to seek, and we had data in the file's
- * write buffer that this is written to disk. */
- if( ( pxFile->ucState & FF_BUFSTATE_WRITTEN ) != 0 )
- {
- xError = FF_BlockWrite( pxFile->pxIOManager, FF_FileLBA( pxFile ), 1, pxFile->pucBuffer, pdFALSE );
- }
- pxFile->ucState = FF_BUFSTATE_INVALID;
- }
- }
- #endif /* ffconfigOPTIMISE_UNALIGNED_ACCESS */
- if( FF_isERR( xError ) == pdFALSE )
- {
- if( xOrigin == FF_SEEK_SET )
- {
- ulPosition = ( uint32_t ) lOffset;
- }
- else if( xOrigin == FF_SEEK_CUR )
- {
- if( lOffset >= ( int32_t ) 0 )
- {
- ulPosition = pxFile->ulFilePointer + ( ( uint32_t ) lOffset );
- }
- else
- {
- ulPosition = pxFile->ulFilePointer - ( ( uint32_t ) ( -lOffset ) );
- }
- }
- else if( xOrigin == FF_SEEK_END )
- {
- /* 'FF_SEEK_END' only allows zero or negative values. */
- if( lOffset <= ( int32_t ) 0 )
- {
- ulPosition = pxFile->ulFileSize - ( ( uint32_t ) ( -lOffset ) );
- }
- }
- else
- {
- xError = ( FF_Error_t ) ( FF_SEEK | FF_ERR_FILE_SEEK_INVALID_ORIGIN );
- /* To supress a compiler warning. */
- ulPosition = ( uint32_t ) 0u;
- }
- if( FF_isERR( xError ) == pdFALSE )
- {
- if( ulPosition <= ( uint32_t ) pxFile->ulFileSize )
- {
- if( ulPosition != ( uint32_t ) pxFile->ulFilePointer )
- {
- pxFile->ulFilePointer = ulPosition;
- FF_SetCluster( pxFile, &xError );
- }
- }
- else
- {
- xError = ( FF_Error_t ) ( FF_SEEK | FF_ERR_FILE_SEEK_INVALID_POSITION );
- }
- }
- }
- }
- return xError;
- } /* FF_Seek() */
- /*-----------------------------------------------------------*/
- #if ( ffconfigREMOVABLE_MEDIA != 0 )
- /**
- * @public
- * @brief Invalidate all file handles belonging to pxIOManager
- *
- * @param pIoMan FF_IOManager_t object that was created by FF_CreateIOManger().
- *
- * @return 0 if no handles were open
- * @return >0 the amount of handles that were invalidated
- * @return <0 probably an invalid FF_IOManager_t pointer
- *
- **/
- int32_t FF_Invalidate( FF_IOManager_t * pxIOManager )
- {
- int32_t xResult;
- FF_FILE * pxFileChain;
- if( pxIOManager == NULL )
- {
- xResult = FF_ERR_NULL_POINTER | FF_INVALIDATE;
- }
- else
- {
- xResult = 0;
- FF_PendSemaphore( pxIOManager->pvSemaphore );
- {
- pxIOManager->ucFlags |= FF_IOMAN_DEVICE_IS_EXTRACTED;
- /* Semaphore is required, or linked list might change */
- pxFileChain = ( FF_FILE * ) pxIOManager->FirstFile;
- if( pxFileChain != NULL )
- {
- /* Count elements in FirstFile */
- do
- {
- pxFileChain->ulValidFlags |= FF_VALID_FLAG_INVALID;
- xResult++;
- pxFileChain = pxFileChain->pxNext;
- }
- while( pxFileChain != NULL );
- }
- }
- FF_ReleaseSemaphore( pxIOManager->pvSemaphore );
- }
- return xResult;
- } /* FF_Invalidate() */
- #endif /* ffconfigREMOVABLE_MEDIA */
- /*-----------------------------------------------------------*/
- /**
- * @public
- * @brief Check validity of file handle
- *
- * @param pxFile FF_FILE object that was created by FF_Open().
- *
- * @return 0 on sucess.
- * @return FF_ERR_NULL_POINTER if a null pointer was provided.
- * @return FF_ERR_FILE_BAD_HANDLE if handle is not recognized
- * @return FF_ERR_FILE_MEDIA_REMOVED please call FF_Close
- *
- **/
- FF_Error_t FF_CheckValid( FF_FILE * pxFile )
- {
- FF_FILE * pxFileChain;
- FF_Error_t xError;
- if( ( pxFile == NULL ) || ( pxFile->pxIOManager == NULL ) )
- {
- xError = ( FF_Error_t ) ( FF_ERR_NULL_POINTER | FF_CHECKVALID );
- }
- else
- {
- FF_PendSemaphore( pxFile->pxIOManager->pvSemaphore );
- {
- pxFileChain = ( FF_FILE * ) pxFile->pxIOManager->FirstFile;
- xError = ( FF_Error_t ) ( FF_ERR_FILE_BAD_HANDLE | FF_CHECKVALID );
- while( pxFileChain != NULL )
- {
- if( pxFileChain == pxFile )
- {
- #if ( ffconfigREMOVABLE_MEDIA != 0 )
- if( ( pxFileChain->ulValidFlags & FF_VALID_FLAG_INVALID ) != 0 )
- {
- /* The medium has been removed while this file handle was open. */
- xError = ( FF_Error_t ) ( FF_ERR_FILE_MEDIA_REMOVED | FF_CHECKVALID );
- }
- else
- #endif
- {
- /* Found the handle, so it is a valid / existing handle. */
- xError = FF_ERR_NONE;
- }
- break;
- }
- pxFileChain = pxFileChain->pxNext;
- }
- }
- FF_ReleaseSemaphore( pxFile->pxIOManager->pvSemaphore );
- }
- return xError;
- } /* FF_CheckValid() */
- /*-----------------------------------------------------------*/
- #if ( ffconfigTIME_SUPPORT != 0 )
- /**
- * @public
- * @brief Set the time-stamp(s) of a file entry
- *
- * @param pxFile FF_FILE object that was created by FF_Open().
- * @param pxTime FF_SystemTime_t the time stamp
- * @param uxWhat UBaseType_t a combination of enum ETimeMask
- *
- * @return 0 or FF_Error_t
- *
- **/
- FF_Error_t FF_SetFileTime( FF_FILE * pxFile,
- FF_SystemTime_t * pxTime,
- UBaseType_t uxWhat )
- {
- FF_DirEnt_t xOriginalEntry;
- FF_Error_t xError;
- xError = FF_CheckValid( pxFile );
- if( FF_isERR( xError ) == pdFALSE )
- {
- if( pxFile->ulValidFlags & FF_VALID_FLAG_DELETED )
- { /*if (pxFile->FileDeleted) */
- xError = ( FF_Error_t ) ( FF_ERR_FILE_NOT_FOUND | FF_SETFILETIME );
- }
- else if( ( pxFile->ucMode & ( FF_MODE_WRITE | FF_MODE_APPEND ) ) == 0 )
- {
- xError = ( FF_Error_t ) ( FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE | FF_SETFILETIME );
- }
- else
- {
- /* Update the Dirent! */
- xError = FF_GetEntry( pxFile->pxIOManager, pxFile->usDirEntry, pxFile->ulDirCluster, &xOriginalEntry );
- if( FF_isERR( xError ) == pdFALSE )
- {
- if( uxWhat & ETimeCreate )
- {
- xOriginalEntry.xCreateTime = *pxTime; /*/< Date and Time Created. */
- }
- if( uxWhat & ETimeMod )
- {
- xOriginalEntry.xModifiedTime = *pxTime; /*/< Date and Time Modified. */
- }
- if( uxWhat & ETimeAccess )
- {
- xOriginalEntry.xAccessedTime = *pxTime; /*/< Date of Last Access. */
- }
- xError = FF_PutEntry( pxFile->pxIOManager, pxFile->usDirEntry, pxFile->ulDirCluster, &xOriginalEntry, NULL );
- }
- if( FF_isERR( xError ) == pdFALSE )
- {
- xError = FF_FlushCache( pxFile->pxIOManager ); /* Ensure all modfied blocks are flushed to disk! */
- }
- }
- }
- return xError;
- } /* FF_SetFileTime() */
- #endif /* ffconfigTIME_SUPPORT */
- /*-----------------------------------------------------------*/
- #if ( ffconfigTIME_SUPPORT != 0 )
- /**
- * @public
- * @brief Set the time-stamp(s) of a file entry (by name)
- *
- * @param pxIOManager FF_IOManager_t device handle
- * @param pcPath int8_t/FF_T_WCHAR name of the file
- * @param pxTime FF_SystemTime_t the time stamp
- * @param uxWhat UBaseType_t a combination of enum ETimeMask
- *
- * @return 0 or FF_Error_t
- *
- **/
- #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
- FF_Error_t FF_SetTime( FF_IOManager_t * pxIOManager,
- const FF_T_WCHAR * pcPath,
- FF_SystemTime_t * pxTime,
- UBaseType_t uxWhat )
- #else
- FF_Error_t FF_SetTime( FF_IOManager_t * pxIOManager,
- const char * pcPath,
- FF_SystemTime_t * pxTime,
- UBaseType_t uxWhat )
- #endif /* ffconfigUNICODE_UTF16_SUPPORT */
- {
- FF_DirEnt_t xOriginalEntry;
- FF_Error_t xError;
- uint32_t ulFileCluster;
- BaseType_t xIndex;
- FF_FindParams_t xFindParams;
- #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
- FF_T_WCHAR pcFileName[ ffconfigMAX_FILENAME ];
- #else
- char pcFileName[ ffconfigMAX_FILENAME ];
- #endif /* ffconfigUNICODE_UTF16_SUPPORT */
- xIndex = ( BaseType_t ) STRLEN( pcPath );
- memset( &xFindParams, '\0', sizeof( xFindParams ) );
- while( xIndex != 0 )
- {
- if( ( pcPath[ xIndex ] == '\\' ) || ( pcPath[ xIndex ] == '/' ) )
- {
- break;
- }
- xIndex--;
- }
- STRNCPY( pcFileName, ( pcPath + xIndex + 1 ), ffconfigMAX_FILENAME );
- if( xIndex == 0 )
- {
- xIndex = 1;
- }
- xFindParams.ulDirCluster = FF_FindDir( pxIOManager, pcPath, ( uint16_t ) xIndex, &xError );
- if( FF_isERR( xError ) == pdFALSE )
- {
- if( xFindParams.ulDirCluster == 0 )
- {
- xError = ( FF_Error_t ) ( FF_ERR_FILE_NOT_FOUND | FF_SETTIME );
- }
- else
- {
- ulFileCluster = FF_FindEntryInDir( pxIOManager, &xFindParams, pcFileName, 0, &xOriginalEntry, &xError );
- if( ( FF_isERR( xError ) == pdFALSE ) || ( FF_GETERROR( xError ) == FF_ERR_DIR_END_OF_DIR ) )
- {
- if( ulFileCluster == 0ul )
- {
- /*FF_PRINTF ("FF_SetTime: Can not find '%s'\n", pcFileName); */
- xError = ( FF_Error_t ) ( FF_ERR_FILE_NOT_FOUND | FF_SETTIME );
- }
- }
- }
- }
- if( FF_isERR( xError ) == pdFALSE )
- {
- /* Update the Dirent! */
- if( uxWhat & ETimeCreate )
- {
- xOriginalEntry.xCreateTime = *pxTime; /*/< Date and Time Created. */
- }
- if( uxWhat & ETimeMod )
- {
- xOriginalEntry.xModifiedTime = *pxTime; /*/< Date and Time Modified. */
- }
- if( uxWhat & ETimeAccess )
- {
- xOriginalEntry.xAccessedTime = *pxTime; /*/< Date of Last Access. */
- }
- xError = FF_PutEntry( pxIOManager, xOriginalEntry.usCurrentItem - 1, xFindParams.ulDirCluster, &xOriginalEntry, NULL );
- if( FF_isERR( xError ) == pdFALSE )
- {
- xError = FF_FlushCache( pxIOManager ); /* Ensure all modified blocks are flushed to disk! */
- }
- }
- return xError;
- } /* FF_SetTime() */
- #endif /* ffconfigTIME_SUPPORT */
- /*-----------------------------------------------------------*/
- #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
- FF_Error_t FF_SetPerm( FF_IOManager_t * pxIOManager,
- const FF_T_WCHAR * pcPath,
- UBaseType_t aPerm )
- #else
- FF_Error_t FF_SetPerm( FF_IOManager_t * pxIOManager,
- const char * pcPath,
- UBaseType_t aPerm )
- #endif
- {
- FF_DirEnt_t xOriginalEntry;
- FF_Error_t xError;
- uint32_t ulFileCluster;
- BaseType_t xIndex;
- #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
- FF_T_WCHAR pcFileName[ ffconfigMAX_FILENAME ];
- #else
- char pcFileName[ ffconfigMAX_FILENAME ];
- #endif
- FF_FindParams_t xFindParams;
- xIndex = ( BaseType_t ) STRLEN( pcPath );
- memset( &xFindParams, '\0', sizeof( xFindParams ) );
- while( xIndex != 0 )
- {
- if( ( pcPath[ xIndex ] == '\\' ) || ( pcPath[ xIndex ] == '/' ) )
- {
- break;
- }
- xIndex--;
- }
- STRNCPY( pcFileName, ( pcPath + xIndex + 1 ), ffconfigMAX_FILENAME );
- if( xIndex == 0 )
- {
- xIndex = 1;
- }
- /* Open a do {} while( pdFALSE ) loop to allow the use of break statements. */
- do
- {
- xFindParams.ulDirCluster = FF_FindDir( pxIOManager, pcPath, ( uint16_t ) xIndex, &xError );
- if( xError )
- {
- break;
- }
- if( !xFindParams.ulDirCluster )
- {
- xError = ( FF_Error_t ) ( FF_ERR_FILE_NOT_FOUND | FF_SETTIME );
- break;
- }
- ulFileCluster = FF_FindEntryInDir( pxIOManager, &xFindParams, pcFileName, 0, &xOriginalEntry, &xError );
- if( FF_isERR( xError ) )
- {
- break;
- }
- if( ulFileCluster == 0ul )
- {
- /*FF_PRINTF ("FF_SetTime: Can not find '%s'\n", pcFileName); */
- xError = ( FF_Error_t ) ( FF_ERR_FILE_NOT_FOUND | FF_SETTIME );
- break;
- }
- /* #define FF_FAT_ATTR_READONLY 0x01 */
- /* #define FF_FAT_ATTR_HIDDEN 0x02 */
- /* #define FF_FAT_ATTR_SYSTEM 0x04 */
- /* #define FF_FAT_ATTR_VOLID 0x08 */
- /* #define FF_FAT_ATTR_DIR 0x10 */
- /* #define FF_FAT_ATTR_ARCHIVE 0x20 */
- /* #define FF_FAT_ATTR_LFN 0x0F */
- #define FF_FAT_ATTR_USER ( ( uint8_t ) FF_FAT_ATTR_READONLY | FF_FAT_ATTR_HIDDEN | FF_FAT_ATTR_SYSTEM | FF_FAT_ATTR_ARCHIVE )
- /* Update the Dirent! */
- xOriginalEntry.ucAttrib &= ~FF_FAT_ATTR_USER;
- xOriginalEntry.ucAttrib |= ( aPerm & FF_FAT_ATTR_USER );
- xError = FF_PutEntry( pxIOManager, xOriginalEntry.usCurrentItem - 1, xFindParams.ulDirCluster, &xOriginalEntry, NULL );
- if( FF_isERR( xError ) == pdFALSE )
- {
- xError = FF_FlushCache( pxIOManager ); /* Ensure all modfied blocks are flushed to disk! */
- }
- }
- while( pdFALSE );
- return xError;
- } /* FF_SetPerm() */
- /*-----------------------------------------------------------*/
- /**
- * @public
- * @brief Equivalent to fclose()
- *
- * @param pxFile FF_FILE object that was created by FF_Open().
- *
- * @return 0 on sucess.
- * @return -1 if a null pointer was provided.
- *
- **/
- FF_Error_t FF_Close( FF_FILE * pxFile )
- {
- FF_FILE * pxFileChain;
- FF_DirEnt_t xOriginalEntry;
- FF_Error_t xError;
- /* Opening a do {} while( 0 ) loop to allow the use of the break statement. */
- do
- {
- if( pxFile == NULL )
- {
- xError = ( FF_Error_t ) ( FF_ERR_NULL_POINTER | FF_CLOSE );
- break;
- }
- /* It is important to check that user doesn't supply invalid
- * handle or a handle invalid because of "media removed" */
- xError = FF_CheckValid( pxFile );
- #if ( ffconfigREMOVABLE_MEDIA != 0 )
- {
- if( FF_GETERROR( xError ) == FF_ERR_FILE_MEDIA_REMOVED )
- {
- FF_PendSemaphore( pxFile->pxIOManager->pvSemaphore );
- {
- pxFileChain = ( FF_FILE * ) pxFile->pxIOManager->FirstFile;
- if( pxFileChain == pxFile )
- {
- pxFile->pxIOManager->FirstFile = pxFile->pxNext;
- }
- else
- {
- while( pxFileChain )
- {
- if( pxFileChain->pxNext == pxFile )
- {
- pxFileChain->pxNext = pxFile->pxNext;
- break;
- }
- pxFileChain = pxFileChain->pxNext; /* Forgot this one */
- }
- }
- } /* Semaphore released, linked list was shortened! */
- FF_ReleaseSemaphore( pxFile->pxIOManager->pvSemaphore );
- #if ( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 )
- {
- ffconfigFREE( pxFile->pucBuffer );
- }
- #endif /* ffconfigOPTIMISE_UNALIGNED_ACCESS */
- ffconfigFREE( pxFile ); /* So at least we have freed the pointer. */
- xError = FF_ERR_NONE;
- break;
- }
- }
- #endif /* ffconfigREMOVABLE_MEDIA */
- if( FF_isERR( xError ) )
- {
- /* FF_ERR_FILE_BAD_HANDLE or FF_ERR_NULL_POINTER */
- break;
- }
- /* So here we have a normal valid file handle. */
- /* Sometimes FreeRTOS+FAT will leave a trailing cluster on the end of a cluster chain.
- * To ensure we're compliant we shall now check for this condition and truncate it. */
- if( ( ( pxFile->ulValidFlags & FF_VALID_FLAG_DELETED ) == 0 ) &&
- ( ( pxFile->ucMode & ( FF_MODE_WRITE | FF_MODE_APPEND | FF_MODE_CREATE ) ) != 0 ) )
- {
- uint32_t ulClusterSize;
- /* File is not deleted and it was opened for writing or updating */
- ulClusterSize = pxFile->pxIOManager->xPartition.usBlkSize * pxFile->pxIOManager->xPartition.ulSectorsPerCluster;
- if( ( ( pxFile->ulFileSize % ulClusterSize ) == 0 ) && ( pxFile->ulObjectCluster != 0ul ) )
- {
- /* The file's length is a multiple of cluster size. This means
- * that an extra cluster has been reserved, which wasn't necessary. */
- xError = FF_Truncate( pxFile, pdTRUE );
- }
- /* Get the directory entry and update it to show the new file size */
- if( FF_isERR( xError ) == pdFALSE )
- {
- xError = FF_GetEntry( pxFile->pxIOManager, pxFile->usDirEntry, pxFile->ulDirCluster, &xOriginalEntry );
- /* Now update the directory entry */
- if( ( FF_isERR( xError ) == pdFALSE ) &&
- ( ( pxFile->ulFileSize != xOriginalEntry.ulFileSize ) || ( pxFile->ulFileSize == 0UL ) ) )
- {
- if( pxFile->ulFileSize == 0UL )
- {
- xOriginalEntry.ulObjectCluster = 0;
- }
- xOriginalEntry.ulFileSize = pxFile->ulFileSize;
- xError = FF_PutEntry( pxFile->pxIOManager, pxFile->usDirEntry, pxFile->ulDirCluster, &xOriginalEntry, NULL );
- }
- }
- }
- /* Handle Linked list! */
- FF_PendSemaphore( pxFile->pxIOManager->pvSemaphore );
- { /* Semaphore is required, or linked list could become corrupted. */
- pxFileChain = ( FF_FILE * ) pxFile->pxIOManager->FirstFile;
- if( pxFileChain == pxFile )
- {
- pxFile->pxIOManager->FirstFile = pxFile->pxNext;
- }
- else
- {
- while( pxFileChain )
- {
- if( pxFileChain->pxNext == pxFile )
- {
- /* Found it, remove it from the list. */
- pxFileChain->pxNext = pxFile->pxNext;
- break;
- }
- pxFileChain = pxFileChain->pxNext;
- }
- }
- } /* Semaphore released, linked list was shortened! */
- FF_ReleaseSemaphore( pxFile->pxIOManager->pvSemaphore );
- #if ( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 )
- {
- if( pxFile->pucBuffer != NULL )
- {
- /* Ensure any unaligned points are pushed to the disk! */
- if( pxFile->ucState & FF_BUFSTATE_WRITTEN )
- {
- FF_Error_t xTempError;
- xTempError = FF_BlockWrite( pxFile->pxIOManager, FF_FileLBA( pxFile ), 1, pxFile->pucBuffer, pdFALSE );
- if( FF_isERR( xError ) == pdFALSE )
- {
- xError = xTempError;
- }
- }
- ffconfigFREE( pxFile->pucBuffer );
- }
- }
- #endif /* if ( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 ) */
- if( FF_isERR( xError ) == pdFALSE )
- {
- xError = FF_FlushCache( pxFile->pxIOManager ); /* Ensure all modified blocks are flushed to disk! */
- }
- ffconfigFREE( pxFile );
- }
- while( pdFALSE );
- return xError;
- } /* FF_Close() */
- /*-----------------------------------------------------------*/
- /**
- * @public
- * @brief Make Filesize equal to the FilePointer and truncates the file to this position
- *
- * @param pxFile FF_FILE object that was created by FF_Open().
- *
- * @return 0 on sucess.
- * @return negative if some error occurred
- *
- **/
- FF_Error_t FF_SetEof( FF_FILE * pxFile )
- {
- FF_Error_t xError;
- /* Check if the file was not deleted and if it was opened with write permissions: */
- if( ( ( pxFile->ulValidFlags & FF_VALID_FLAG_DELETED ) == 0 ) &&
- ( ( pxFile->ucMode & ( FF_MODE_WRITE | FF_MODE_APPEND | FF_MODE_CREATE ) ) != 0 ) )
- {
- pxFile->ulFileSize = pxFile->ulFilePointer;
- if( pxFile->ulObjectCluster != 0ul )
- {
- xError = FF_Truncate( pxFile, pdFALSE );
- }
- else
- {
- xError = FF_ERR_NONE;
- }
- }
- else
- {
- xError = ( FF_Error_t ) ( FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE | FF_SETEOF );
- }
- return xError;
- } /* FF_SetEof() */
- /*-----------------------------------------------------------*/
- /**
- * @public
- * @brief Truncate a file to 'pxFile->ulFileSize'
- *
- * @param pxFile FF_FILE object that was created by FF_Open().
- *
- * @return 0 on sucess.
- * @return negative if some error occurred
- *
- **/
- static FF_Error_t FF_Truncate( FF_FILE * pxFile,
- BaseType_t bClosing )
- {
- FF_Error_t xError;
- FF_IOManager_t * pxIOManager = pxFile->pxIOManager;
- uint32_t ulClusterSize;
- uint32_t ulClusterCount;
- uint32_t ulClustersNeeded;
- /* The number of bytes contained in a cluster. */
- ulClusterSize = pxIOManager->xPartition.usBlkSize * pxIOManager->xPartition.ulSectorsPerCluster;
- /* See how many clusters have been allocated. */
- ulClusterCount = FF_GetChainLength( pxIOManager, pxFile->ulObjectCluster, NULL, &xError );
- /* Calculate the actual number of clusters needed, rounding up */
- ulClustersNeeded = ( pxFile->ulFileSize + ulClusterSize - 1 ) / ulClusterSize;
- if( bClosing != pdFALSE )
- {
- /* The handle will be closed after truncating. This function is called
- * because Filesize is an exact multiple of ulClusterSize. */
- ulClustersNeeded = pxFile->ulFileSize / ulClusterSize;
- }
- else
- {
- /* This function is called to make the file size equal to the current
- * position within the file. Always keep an extra cluster to write to. */
- ulClustersNeeded = ( pxFile->ulFileSize + ulClusterSize ) / ulClusterSize;
- }
- /* First change the FAT chain. */
- if( ( FF_isERR( xError ) == pdFALSE ) && ( ulClusterCount > ulClustersNeeded ) )
- {
- if( ulClustersNeeded == 0ul )
- {
- FF_LockFAT( pxIOManager );
- {
- /* In FF_Truncate() */
- xError = FF_UnlinkClusterChain( pxIOManager, pxFile->ulObjectCluster, 0 );
- }
- FF_UnlockFAT( pxIOManager );
- if( FF_isERR( xError ) == pdFALSE )
- {
- FF_DirEnt_t xOriginalEntry;
- /* 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 = 0ul;
- xError = FF_PutEntry( pxIOManager, pxFile->usDirEntry, pxFile->ulDirCluster, &xOriginalEntry, NULL );
- if( FF_isERR( xError ) == pdFALSE )
- {
- pxFile->ulObjectCluster = 0ul;
- pxFile->ulChainLength = 0ul;
- pxFile->ulCurrentCluster = 0ul;
- pxFile->ulEndOfChain = 0ul;
- }
- }
- }
- }
- else
- {
- FF_LockFAT( pxIOManager );
- {
- uint32_t ulTruncateCluster = FF_TraverseFAT( pxIOManager, pxFile->ulObjectCluster, ulClustersNeeded - 1, &xError );
- if( FF_isERR( xError ) == pdFALSE )
- {
- xError = FF_UnlinkClusterChain( pxIOManager, ulTruncateCluster, 1 );
- }
- }
- FF_UnlockFAT( pxIOManager );
- }
- }
- return xError;
- } /* FF_Truncate() */
- /*-----------------------------------------------------------*/
|