ff_file.c 110 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318
  1. /*
  2. * FreeRTOS+FAT V2.3.3
  3. * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
  4. *
  5. * Permission is hereby granted, free of charge, to any person obtaining a copy of
  6. * this software and associated documentation files (the "Software"), to deal in
  7. * the Software without restriction, including without limitation the rights to
  8. * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  9. * the Software, and to permit persons to whom the Software is furnished to do so,
  10. * subject to the following conditions:
  11. *
  12. * The above copyright notice and this permission notice shall be included in all
  13. * copies or substantial portions of the Software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  17. * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  18. * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  19. * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  20. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  21. *
  22. * https://www.FreeRTOS.org
  23. * https://github.com/FreeRTOS
  24. *
  25. */
  26. /**
  27. * @file ff_file.c
  28. * @ingroup FILEIO
  29. *
  30. * @defgroup FILEIO FILE I/O Access
  31. * @brief Provides an interface to allow File I/O on a mounted IOMAN.
  32. *
  33. * Provides file-system interfaces for the FAT file-system.
  34. **/
  35. #include "ff_headers.h"
  36. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  37. #include <wchar.h>
  38. #endif
  39. static FF_Error_t FF_Truncate( FF_FILE * pxFile,
  40. BaseType_t bClosing );
  41. static int32_t FF_ReadPartial( FF_FILE * pxFile,
  42. uint32_t ulItemLBA,
  43. uint32_t ulRelBlockPos,
  44. uint32_t ulCount,
  45. uint8_t * pucBuffer,
  46. FF_Error_t * pxError );
  47. static int32_t FF_WritePartial( FF_FILE * pxFile,
  48. uint32_t ulItemLBA,
  49. uint32_t ulRelBlockPos,
  50. uint32_t ulCount,
  51. const uint8_t * pucBuffer,
  52. FF_Error_t * pxError );
  53. static uint32_t FF_SetCluster( FF_FILE * pxFile,
  54. FF_Error_t * pxError );
  55. static uint32_t FF_FileLBA( FF_FILE * pxFile );
  56. static FF_Error_t FF_ExtendFile( FF_FILE * pxFile,
  57. uint32_t ulSize );
  58. /*-----------------------------------------------------------*/
  59. /**
  60. * @public
  61. * @brief Converts STDIO mode strings into the equivalent FreeRTOS+FAT mode.
  62. *
  63. * @param Mode The mode string e.g. "rb" "rb+" "w" "a" "r" "w+" "a+" etc
  64. *
  65. * @return Returns the mode bits that should be passed to the FF_Open function.
  66. **/
  67. uint8_t FF_GetModeBits( const char * pcMode )
  68. {
  69. uint8_t ucModeBits = 0x00;
  70. while( *pcMode != '\0' )
  71. {
  72. switch( *pcMode )
  73. {
  74. case 'r': /* Allow Read. */
  75. case 'R':
  76. ucModeBits |= FF_MODE_READ;
  77. break;
  78. case 'w': /* Allow Write. */
  79. case 'W':
  80. ucModeBits |= FF_MODE_WRITE;
  81. ucModeBits |= FF_MODE_CREATE; /* Create if not exist. */
  82. ucModeBits |= FF_MODE_TRUNCATE;
  83. break;
  84. case 'a': /* Append new writes to the end of the file. */
  85. case 'A':
  86. ucModeBits |= FF_MODE_WRITE;
  87. ucModeBits |= FF_MODE_APPEND;
  88. ucModeBits |= FF_MODE_CREATE; /* Create if not exist. */
  89. break;
  90. case '+': /* Update the file, don't Append! */
  91. ucModeBits |= FF_MODE_READ;
  92. ucModeBits |= FF_MODE_WRITE; /* RW Mode. */
  93. break;
  94. case 'D':
  95. /* Internal use only! */
  96. ucModeBits |= FF_MODE_DIR;
  97. break;
  98. case 'b':
  99. case 'B':
  100. /* b|B flags not supported (Binary mode is native anyway). */
  101. break;
  102. default:
  103. break;
  104. }
  105. pcMode++;
  106. }
  107. return ucModeBits;
  108. } /* FF_GetModeBits() */
  109. /*-----------------------------------------------------------*/
  110. static FF_FILE * prvAllocFileHandle( FF_IOManager_t * pxIOManager,
  111. FF_Error_t * pxError )
  112. {
  113. FF_FILE * pxFile;
  114. pxFile = ffconfigMALLOC( sizeof( FF_FILE ) );
  115. if( pxFile == NULL )
  116. {
  117. *pxError = ( FF_Error_t ) ( FF_ERR_NOT_ENOUGH_MEMORY | FF_OPEN );
  118. }
  119. else
  120. {
  121. memset( pxFile, 0, sizeof( *pxFile ) );
  122. #if ( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 )
  123. {
  124. pxFile->pucBuffer = ( uint8_t * ) ffconfigMALLOC( pxIOManager->usSectorSize );
  125. if( pxFile->pucBuffer != NULL )
  126. {
  127. memset( pxFile->pucBuffer, 0, pxIOManager->usSectorSize );
  128. }
  129. else
  130. {
  131. *pxError = ( FF_Error_t ) ( FF_ERR_NOT_ENOUGH_MEMORY | FF_OPEN );
  132. ffconfigFREE( pxFile );
  133. /* Make sure that NULL will be returned. */
  134. pxFile = NULL;
  135. }
  136. }
  137. #else /* if ( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 ) */
  138. {
  139. /* Remove compiler warnings. */
  140. ( void ) pxIOManager;
  141. }
  142. #endif /* if ( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 ) */
  143. }
  144. return pxFile;
  145. } /* prvAllocFileHandle() */
  146. /*-----------------------------------------------------------*/
  147. /**
  148. * FF_Open() Mode Information
  149. * - FF_MODE_WRITE
  150. * - Allows WRITE access to the file.
  151. * .
  152. * - FF_MODE_READ
  153. * - Allows READ access to the file.
  154. * .
  155. * - FF_MODE_CREATE
  156. * - Create file if it doesn't exist.
  157. * .
  158. * - FF_MODE_TRUNCATE
  159. * - Erase the file if it already exists and overwrite.
  160. * *
  161. * - FF_MODE_APPEND
  162. * - Causes all writes to occur at the end of the file. (Its impossible to overwrite other data in a file with this flag set).
  163. * .
  164. * .
  165. *
  166. * Some sample modes:
  167. * - (FF_MODE_WRITE | FF_MODE_CREATE | FF_MODE_TRUNCATE)
  168. * - Write access to the file. (Equivalent to "w").
  169. * .
  170. * - (FF_MODE_WRITE | FF_MODE_READ)
  171. * - Read and Write access to the file. (Equivalent to "rb+").
  172. * .
  173. * - (FF_MODE_WRITE | FF_MODE_READ | FF_MODE_APPEND | FF_MODE_CREATE)
  174. * - Read and Write append mode access to the file. (Equivalent to "a+").
  175. * .
  176. * .
  177. * Be careful when choosing modes. For those using FF_Open() at the application layer
  178. * its best to use the provided FF_GetModeBits() function, as this complies to the same
  179. * behaviour as the stdio.h fopen() function.
  180. *
  181. **/
  182. /**
  183. * @public
  184. * @brief Opens a File for Access
  185. *
  186. * @param pxIOManager FF_IOManager_t object that was created by FF_CreateIOManger().
  187. * @param pcPath Path to the File or object.
  188. * @param ucMode Access Mode required. Modes are a little complicated, the function FF_GetModeBits()
  189. * @param ucMode will convert a stdio Mode string into the equivalent Mode bits for this parameter.
  190. * @param pxError Pointer to a signed byte for error checking. Can be NULL if not required.
  191. * @param pxError To be checked when a NULL pointer is returned.
  192. *
  193. * @return NULL pointer on error, in which case pxError should be checked for more information.
  194. * @return pxError can be:
  195. **/
  196. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  197. FF_FILE * FF_Open( FF_IOManager_t * pxIOManager,
  198. const FF_T_WCHAR * pcPath,
  199. uint8_t ucMode,
  200. FF_Error_t * pxError )
  201. #else
  202. FF_FILE * FF_Open( FF_IOManager_t * pxIOManager, const char * pcPath, uint8_t ucMode, FF_Error_t * pxError )
  203. #endif
  204. {
  205. FF_FILE * pxFile = NULL;
  206. FF_FILE * pxFileChain;
  207. FF_DirEnt_t xDirEntry;
  208. uint32_t ulFileCluster;
  209. FF_Error_t xError;
  210. BaseType_t xIndex;
  211. FF_FindParams_t xFindParams;
  212. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  213. FF_T_WCHAR pcFileName[ ffconfigMAX_FILENAME ];
  214. #else
  215. char pcFileName[ ffconfigMAX_FILENAME ];
  216. #endif
  217. memset( &xFindParams, '\0', sizeof( xFindParams ) );
  218. /* Inform the functions that the entry will be created if not found. */
  219. if( ( ucMode & FF_MODE_CREATE ) != 0 )
  220. {
  221. xFindParams.ulFlags |= FIND_FLAG_CREATE_FLAG;
  222. }
  223. if( pxIOManager == NULL )
  224. {
  225. /* Use the error function code 'FF_OPEN' as this static
  226. * function is only called from that function. */
  227. xError = ( FF_Error_t ) ( FF_ERR_NULL_POINTER | FF_OPEN );
  228. }
  229. #if ( ffconfigREMOVABLE_MEDIA != 0 )
  230. else if( ( pxIOManager->ucFlags & FF_IOMAN_DEVICE_IS_EXTRACTED ) != 0 )
  231. {
  232. xError = ( FF_Error_t ) ( FF_ERR_IOMAN_DRIVER_NOMEDIUM | FF_OPEN );
  233. }
  234. #endif /* ffconfigREMOVABLE_MEDIA */
  235. else
  236. {
  237. xError = FF_ERR_NONE;
  238. /* Let xIndex point to the last occurrence of '/' or '\',
  239. * to separate the path from the file name. */
  240. xIndex = ( BaseType_t ) STRLEN( pcPath );
  241. while( xIndex != 0 )
  242. {
  243. if( ( pcPath[ xIndex ] == '\\' ) || ( pcPath[ xIndex ] == '/' ) )
  244. {
  245. break;
  246. }
  247. xIndex--;
  248. }
  249. /* Copy the file name, i.e. the string that comes after the last separator. */
  250. STRNCPY( pcFileName, pcPath + xIndex + 1, ffconfigMAX_FILENAME );
  251. if( xIndex == 0 )
  252. {
  253. /* Only for the root, the slash is part of the directory name.
  254. * 'xIndex' now equals to the length of the path name. */
  255. xIndex = 1;
  256. }
  257. /* FF_CreateShortName() might set flags FIND_FLAG_FITS_SHORT and FIND_FLAG_SIZE_OK. */
  258. FF_CreateShortName( &xFindParams, pcFileName );
  259. /* Lookup the path and find the cluster pointing to the directory: */
  260. xFindParams.ulDirCluster = FF_FindDir( pxIOManager, pcPath, xIndex, &xError );
  261. if( xFindParams.ulDirCluster == 0ul )
  262. {
  263. if( ( ucMode & FF_MODE_WRITE ) != 0 )
  264. {
  265. FF_PRINTF( "FF_Open[%s]: Path not found\n", pcPath );
  266. }
  267. /* The user tries to open a file but the path leading to the file does not exist. */
  268. }
  269. else if( FF_isERR( xError ) == pdFALSE )
  270. {
  271. /* Allocate an empty file handle and buffer space for 'unaligned access'. */
  272. pxFile = prvAllocFileHandle( pxIOManager, &xError );
  273. }
  274. }
  275. if( FF_isERR( xError ) == pdFALSE )
  276. {
  277. /* Copy the Mode Bits. */
  278. pxFile->ucMode = ucMode;
  279. /* See if the file does exist within the given directory. */
  280. ulFileCluster = FF_FindEntryInDir( pxIOManager, &xFindParams, pcFileName, 0x00, &xDirEntry, &xError );
  281. if( ulFileCluster == 0ul )
  282. {
  283. /* If cluster 0 was returned, it might be because the file has no allocated cluster,
  284. * i.e. only a directory entry and no stored data. */
  285. if( STRLEN( pcFileName ) == STRLEN( xDirEntry.pcFileName ) )
  286. {
  287. if( ( xDirEntry.ulFileSize == 0 ) && ( FF_strmatch( pcFileName, xDirEntry.pcFileName, ( BaseType_t ) STRLEN( pcFileName ) ) == pdTRUE ) )
  288. {
  289. /* It is the file, give it a pseudo cluster number '1'. */
  290. ulFileCluster = 1;
  291. /* And reset any error. */
  292. xError = FF_ERR_NONE;
  293. }
  294. }
  295. }
  296. /* Test 'ulFileCluster' again, it might have been changed. */
  297. if( ulFileCluster == 0ul )
  298. {
  299. /* The path is found, but it does not contain the file name yet.
  300. * Maybe the user wants to create it? */
  301. if( ( ucMode & FF_MODE_CREATE ) == 0 )
  302. {
  303. xError = ( FF_Error_t ) ( FF_ERR_FILE_NOT_FOUND | FF_OPEN );
  304. }
  305. else
  306. {
  307. ulFileCluster = FF_CreateFile( pxIOManager, &xFindParams, pcFileName, &xDirEntry, &xError );
  308. if( FF_isERR( xError ) == pdFALSE )
  309. {
  310. xDirEntry.usCurrentItem += 1;
  311. }
  312. }
  313. }
  314. }
  315. if( FF_isERR( xError ) == pdFALSE )
  316. {
  317. /* Now the file exists, or it has been created.
  318. * Check if the Mode flags are allowed: */
  319. if( ( xDirEntry.ucAttrib == FF_FAT_ATTR_DIR ) && ( ( ucMode & FF_MODE_DIR ) == 0 ) )
  320. {
  321. /* Not the object, File Not Found! */
  322. xError = ( FF_Error_t ) ( FF_ERR_FILE_OBJECT_IS_A_DIR | FF_OPEN );
  323. }
  324. /*---------- Ensure Read-Only files don't get opened for Writing. */
  325. else if( ( ( ucMode & ( FF_MODE_WRITE | FF_MODE_APPEND ) ) != 0 ) && ( ( xDirEntry.ucAttrib & FF_FAT_ATTR_READONLY ) != 0 ) )
  326. {
  327. xError = ( FF_Error_t ) ( FF_ERR_FILE_IS_READ_ONLY | FF_OPEN );
  328. }
  329. }
  330. if( FF_isERR( xError ) == pdFALSE )
  331. {
  332. pxFile->pxIOManager = pxIOManager;
  333. pxFile->ulFilePointer = 0;
  334. /* Despite the warning output by MSVC - it is not possible to get here
  335. * if xDirEntry has not been initialised. */
  336. pxFile->ulObjectCluster = xDirEntry.ulObjectCluster;
  337. pxFile->ulFileSize = xDirEntry.ulFileSize;
  338. pxFile->ulCurrentCluster = 0;
  339. pxFile->ulAddrCurrentCluster = pxFile->ulObjectCluster;
  340. pxFile->pxNext = NULL;
  341. pxFile->ulDirCluster = xFindParams.ulDirCluster;
  342. pxFile->usDirEntry = xDirEntry.usCurrentItem - 1;
  343. pxFile->ulChainLength = 0;
  344. pxFile->ulEndOfChain = 0;
  345. pxFile->ulValidFlags &= ~( FF_VALID_FLAG_DELETED );
  346. /* Add pxFile onto the end of our linked list of FF_FILE objects.
  347. * But first make sure that there are not 2 handles with write access
  348. * to the same object. */
  349. FF_PendSemaphore( pxIOManager->pvSemaphore );
  350. {
  351. pxFileChain = ( FF_FILE * ) pxIOManager->FirstFile;
  352. if( pxFileChain == NULL )
  353. {
  354. pxIOManager->FirstFile = pxFile;
  355. }
  356. else
  357. {
  358. for( ; ; )
  359. {
  360. /* See if two file handles point to the same object. */
  361. if( ( pxFileChain->ulObjectCluster == pxFile->ulObjectCluster ) &&
  362. ( pxFileChain->ulDirCluster == pxFile->ulDirCluster ) &&
  363. ( pxFileChain->usDirEntry == pxFile->usDirEntry ) )
  364. {
  365. /* Fail if any of the two has write access to the object. */
  366. if( ( ( pxFileChain->ucMode | pxFile->ucMode ) & ( FF_MODE_WRITE | FF_MODE_APPEND ) ) != 0 )
  367. {
  368. /* File is already open! DON'T ALLOW IT! */
  369. xError = ( FF_Error_t ) ( FF_ERR_FILE_ALREADY_OPEN | FF_OPEN );
  370. break;
  371. }
  372. }
  373. if( pxFileChain->pxNext == NULL )
  374. {
  375. pxFileChain->pxNext = pxFile;
  376. break;
  377. }
  378. pxFileChain = ( FF_FILE * ) pxFileChain->pxNext;
  379. }
  380. }
  381. }
  382. FF_ReleaseSemaphore( pxIOManager->pvSemaphore );
  383. }
  384. if( FF_isERR( xError ) == pdFALSE )
  385. {
  386. /* If the file is opened with the truncate flag, truncate its contents. */
  387. if( ( ucMode & FF_MODE_TRUNCATE ) != 0 )
  388. {
  389. /* Set the current size and position to zero. */
  390. pxFile->ulFileSize = 0;
  391. pxFile->ulFilePointer = 0;
  392. }
  393. }
  394. if( FF_isERR( xError ) != pdFALSE )
  395. {
  396. if( pxFile != NULL )
  397. {
  398. #if ( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 )
  399. {
  400. ffconfigFREE( pxFile->pucBuffer );
  401. }
  402. #endif
  403. ffconfigFREE( pxFile );
  404. }
  405. pxFile = NULL;
  406. }
  407. if( pxError != NULL )
  408. {
  409. *pxError = xError;
  410. }
  411. return pxFile;
  412. } /* FF_Open() */
  413. /*-----------------------------------------------------------*/
  414. /**
  415. * @public
  416. * @brief Tests if a Directory contains any other files or folders.
  417. *
  418. * @param pxIOManager FF_IOManager_t object returned from the FF_CreateIOManger() function.
  419. *
  420. **/
  421. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  422. BaseType_t FF_isDirEmpty( FF_IOManager_t * pxIOManager,
  423. const FF_T_WCHAR * pcPath )
  424. #else
  425. BaseType_t FF_isDirEmpty( FF_IOManager_t * pxIOManager,
  426. const char * pcPath )
  427. #endif
  428. {
  429. FF_DirEnt_t xDirEntry;
  430. FF_Error_t xError = FF_ERR_NONE;
  431. BaseType_t xReturn;
  432. if( pxIOManager == NULL )
  433. {
  434. xReturn = pdFALSE;
  435. }
  436. else
  437. {
  438. xError = FF_FindFirst( pxIOManager, &xDirEntry, pcPath );
  439. /* Assume the directory is empty until a file is
  440. * encountered with a name other than ".." or "." */
  441. xReturn = pdTRUE;
  442. while( xError == 0 )
  443. {
  444. /* As we can't be sure the first 2 entries contain
  445. * "." and "..", check it, not just count them
  446. */
  447. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  448. if( ( wcscmp( xDirEntry.pcFileName, L".." ) != 0 ) && ( wcscmp( xDirEntry.pcFileName, L"." ) != 0 ) )
  449. #else
  450. if( ( strcmp( xDirEntry.pcFileName, ".." ) != 0 ) && ( strcmp( xDirEntry.pcFileName, "." ) != 0 ) )
  451. #endif
  452. {
  453. xReturn = pdFALSE;
  454. break;
  455. }
  456. xError = FF_FindNext( pxIOManager, &xDirEntry );
  457. }
  458. }
  459. return xReturn;
  460. } /* FF_isDirEmpty() */
  461. /*-----------------------------------------------------------*/
  462. #if ( ffconfigPATH_CACHE != 0 )
  463. /* _HT_ After a directory has been renamed, the path cache becomes out-of-date */
  464. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  465. static void FF_RmPathCache( FF_IOManager_t * pxIOManager,
  466. const FF_T_WCHAR * pcPath )
  467. #else
  468. static void FF_RmPathCache( FF_IOManager_t * pxIOManager,
  469. const char * pcPath )
  470. #endif
  471. {
  472. /*
  473. * The directory 'path' will be removed or renamed
  474. * now clear all entries starting with 'path' in the path cache
  475. */
  476. BaseType_t xIndex;
  477. BaseType_t pathLen = STRLEN( pcPath );
  478. FF_PendSemaphore( pxIOManager->pvSemaphore );
  479. {
  480. for( xIndex = 0; xIndex < ffconfigPATH_CACHE_DEPTH; xIndex++ )
  481. {
  482. BaseType_t len2 = STRLEN( pxIOManager->xPartition.pxPathCache[ xIndex ].pcPath );
  483. if( ( len2 >= pathLen ) && FF_strmatch( pxIOManager->xPartition.pxPathCache[ xIndex ].pcPath, pcPath, pathLen ) )
  484. {
  485. pxIOManager->xPartition.pxPathCache[ xIndex ].pcPath[ 0 ] = '\0';
  486. pxIOManager->xPartition.pxPathCache[ xIndex ].ulDirCluster = 0;
  487. }
  488. }
  489. }
  490. FF_ReleaseSemaphore( pxIOManager->pvSemaphore );
  491. }
  492. #endif /* ffconfigPATH_CACHE */
  493. /*-----------------------------------------------------------*/
  494. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  495. FF_Error_t FF_RmDir( FF_IOManager_t * pxIOManager,
  496. const FF_T_WCHAR * pcPath )
  497. #else
  498. FF_Error_t FF_RmDir( FF_IOManager_t * pxIOManager,
  499. const char * pcPath )
  500. #endif
  501. {
  502. FF_FILE * pxFile;
  503. uint8_t ucEntryBuffer[ 32 ];
  504. FF_FetchContext_t xFetchContext;
  505. FF_Error_t xError = FF_ERR_NONE;
  506. if( pxIOManager == NULL )
  507. {
  508. xError = ( FF_Error_t ) ( FF_ERR_NULL_POINTER | FF_RMDIR );
  509. }
  510. #if ( ffconfigREMOVABLE_MEDIA != 0 )
  511. else if( ( pxIOManager->ucFlags & FF_IOMAN_DEVICE_IS_EXTRACTED ) != 0 )
  512. {
  513. xError = ( FF_Error_t ) ( FF_ERR_IOMAN_DRIVER_NOMEDIUM | FF_RMDIR );
  514. }
  515. #endif /* ffconfigREMOVABLE_MEDIA */
  516. else
  517. {
  518. pxFile = FF_Open( pxIOManager, pcPath, FF_MODE_DIR, &xError );
  519. if( pxFile != NULL )
  520. {
  521. pxFile->ulValidFlags |= FF_VALID_FLAG_DELETED;
  522. /* Clear the struct to allow a call to FF_CleanupEntryFetch() in any
  523. * state. */
  524. memset( &xFetchContext, '\0', sizeof( xFetchContext ) );
  525. /* This task will get the unique right to change directories. */
  526. FF_LockDirectory( pxIOManager );
  527. do /* while( pdFALSE ) */
  528. {
  529. /* This while loop is only introduced to be able to use break
  530. * statements. */
  531. if( FF_isDirEmpty( pxIOManager, pcPath ) == pdFALSE )
  532. {
  533. xError = ( FF_ERR_DIR_NOT_EMPTY | FF_RMDIR );
  534. break;
  535. }
  536. FF_LockFAT( pxIOManager );
  537. #if ( ffconfigHASH_CACHE != 0 )
  538. {
  539. /* A directory is removed so invalidate any hash table
  540. * referring to this directory. */
  541. FF_UnHashDir( pxIOManager, pxFile->ulObjectCluster );
  542. }
  543. #endif /* ffconfigHASH_CACHE */
  544. {
  545. /* Add parameter 0 to delete the entire chain!
  546. * The actual directory entries on disk will be freed. */
  547. xError = FF_UnlinkClusterChain( pxIOManager, pxFile->ulObjectCluster, 0 );
  548. }
  549. FF_UnlockFAT( pxIOManager );
  550. if( FF_isERR( xError ) )
  551. {
  552. break;
  553. }
  554. /* Now remove this directory from its parent directory.
  555. * Initialise the dirent Fetch Context object for faster removal of
  556. * dirents. */
  557. xError = FF_InitEntryFetch( pxIOManager, pxFile->ulDirCluster, &xFetchContext );
  558. if( FF_isERR( xError ) )
  559. {
  560. break;
  561. }
  562. #if ( ffconfigHASH_CACHE != 0 )
  563. {
  564. /* Invalidate any hash table of the parent directory
  565. * as well. */
  566. FF_UnHashDir( pxIOManager, pxFile->ulDirCluster );
  567. }
  568. #endif /* ffconfigHASH_CACHE */
  569. /* Edit the Directory Entry, so it will show as deleted.
  570. * First remove the LFN entries: */
  571. xError = FF_RmLFNs( pxIOManager, pxFile->usDirEntry, &xFetchContext );
  572. if( FF_isERR( xError ) )
  573. {
  574. break;
  575. }
  576. /* And remove the Short file name entry: */
  577. xError = FF_FetchEntryWithContext( pxIOManager, pxFile->usDirEntry, &xFetchContext, ucEntryBuffer );
  578. if( FF_isERR( xError ) == pdFALSE )
  579. {
  580. ucEntryBuffer[ 0 ] = FF_FAT_DELETED;
  581. FF_putShort( ucEntryBuffer, FF_FAT_DIRENT_CLUS_HIGH, ( uint32_t ) 0ul );
  582. FF_putShort( ucEntryBuffer, FF_FAT_DIRENT_CLUS_LOW, ( uint32_t ) 0ul );
  583. xError = FF_PushEntryWithContext( pxIOManager, pxFile->usDirEntry, &xFetchContext, ucEntryBuffer );
  584. }
  585. if( FF_isERR( xError ) )
  586. {
  587. break;
  588. }
  589. #if ( ffconfigPATH_CACHE != 0 )
  590. {
  591. /* We're removing a directory which might contain
  592. * subdirectories. Instead of iterating through all
  593. * subdirectories, just clear the path cache. */
  594. FF_RmPathCache( pxIOManager, pcPath );
  595. }
  596. #endif
  597. } while( pdFALSE );
  598. {
  599. FF_Error_t xTempError;
  600. xTempError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext );
  601. if( FF_isERR( xError ) == pdFALSE )
  602. {
  603. xError = xTempError;
  604. }
  605. FF_UnlockDirectory( pxIOManager );
  606. /* Free the file pointer resources. */
  607. xTempError = FF_Close( pxFile );
  608. if( FF_isERR( xError ) == pdFALSE )
  609. {
  610. xError = xTempError;
  611. }
  612. xTempError = FF_FlushCache( pxIOManager );
  613. if( FF_isERR( xError ) == pdFALSE )
  614. {
  615. xError = xTempError;
  616. }
  617. }
  618. } /* if( pxFile != NULL ) */
  619. } /* else if( pxIOManager != NULL ) */
  620. return xError;
  621. } /* FF_RmDir() */
  622. /*-----------------------------------------------------------*/
  623. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  624. FF_Error_t FF_RmFile( FF_IOManager_t * pxIOManager,
  625. const FF_T_WCHAR * pcPath )
  626. #else
  627. FF_Error_t FF_RmFile( FF_IOManager_t * pxIOManager,
  628. const char * pcPath )
  629. #endif
  630. {
  631. FF_FILE * pxFile;
  632. FF_Error_t xError = FF_ERR_NONE;
  633. uint8_t ucEntryBuffer[ 32 ];
  634. FF_FetchContext_t xFetchContext;
  635. /* Opening the file-to-be-deleted in WR mode has two advantages:
  636. * 1. The file handle gives all necessary information to delete it such
  637. * as the data clusters and directory entries.
  638. * 2. The file is now locked, it can not be opened by another task. */
  639. pxFile = FF_Open( pxIOManager, pcPath, FF_MODE_WRITE, &xError );
  640. if( pxFile != NULL )
  641. {
  642. /* FF_Close() will see this flag and won't do any disc access. */
  643. pxFile->ulValidFlags |= FF_VALID_FLAG_DELETED;
  644. /* Ensure there is actually a cluster chain to delete! */
  645. if( pxFile->ulObjectCluster != 0 )
  646. {
  647. /* Lock the FAT so its thread-safe. */
  648. FF_LockFAT( pxIOManager );
  649. {
  650. /* 0 to delete the entire chain! */
  651. xError = FF_UnlinkClusterChain( pxIOManager, pxFile->ulObjectCluster, 0 );
  652. }
  653. FF_UnlockFAT( pxIOManager );
  654. }
  655. if( FF_isERR( xError ) == pdFALSE )
  656. {
  657. /* Clear the struct to allow a call to FF_CleanupEntryFetch() in any
  658. * state. */
  659. memset( &xFetchContext, '\0', sizeof( xFetchContext ) );
  660. /* Get sole access to "directory changes" */
  661. FF_LockDirectory( pxIOManager );
  662. /* Edit the Directory Entry! (So it appears as deleted); */
  663. do
  664. {
  665. xError = FF_InitEntryFetch( pxIOManager, pxFile->ulDirCluster, &xFetchContext );
  666. if( FF_isERR( xError ) )
  667. {
  668. break;
  669. }
  670. #if ( ffconfigHASH_CACHE != 0 )
  671. {
  672. FF_UnHashDir( pxIOManager, pxFile->ulDirCluster );
  673. }
  674. #endif /* ffconfigHASH_CACHE */
  675. /* Remove LFN entries, if any. */
  676. xError = FF_RmLFNs( pxIOManager, ( uint16_t ) pxFile->usDirEntry, &xFetchContext );
  677. if( FF_isERR( xError ) )
  678. {
  679. break;
  680. }
  681. /* Remove the Short file name entry. */
  682. xError = FF_FetchEntryWithContext( pxIOManager, pxFile->usDirEntry, &xFetchContext, ucEntryBuffer );
  683. if( FF_isERR( xError ) == pdFALSE )
  684. {
  685. ucEntryBuffer[ 0 ] = FF_FAT_DELETED;
  686. FF_putShort( ucEntryBuffer, FF_FAT_DIRENT_CLUS_HIGH, ( uint32_t ) 0ul );
  687. FF_putShort( ucEntryBuffer, FF_FAT_DIRENT_CLUS_LOW, ( uint32_t ) 0ul );
  688. xError = FF_PushEntryWithContext( pxIOManager, pxFile->usDirEntry, &xFetchContext, ucEntryBuffer );
  689. }
  690. } while( pdFALSE );
  691. {
  692. FF_Error_t xTempError;
  693. xTempError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext );
  694. if( FF_isERR( xError ) == pdFALSE )
  695. {
  696. xError = xTempError;
  697. }
  698. FF_UnlockDirectory( pxIOManager );
  699. /* Free the file pointer resources. */
  700. xTempError = FF_Close( pxFile );
  701. if( FF_isERR( xError ) == pdFALSE )
  702. {
  703. xError = xTempError;
  704. }
  705. xTempError = FF_FlushCache( pxIOManager );
  706. if( FF_isERR( xError ) == pdFALSE )
  707. {
  708. xError = xTempError;
  709. }
  710. }
  711. }
  712. } /* if( pxFile != NULL ) */
  713. return xError;
  714. } /* FF_RmFile() */
  715. /*-----------------------------------------------------------*/
  716. /**
  717. * @public
  718. * @brief Moves a file or directory from source to destination.
  719. *
  720. * @param pxIOManager The FF_IOManager_t object pointer.
  721. * @param szSourceFile String of the source file to be moved or renamed.
  722. * @param szDestinationFile String of the destination file to where the source should be moved or renamed.
  723. *
  724. * @return FF_ERR_NONE on success.
  725. * @return FF_ERR_FILE_DESTINATION_EXISTS if the destination file exists.
  726. * @return FF_ERR_FILE_COULD_NOT_CREATE_DIRENT if dirent creation failed (fatal error!).
  727. * @return FF_ERR_FILE_DIR_NOT_FOUND if destination directory was not found.
  728. * @return FF_ERR_FILE_SOURCE_NOT_FOUND if the source file was not found.
  729. *
  730. **/
  731. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  732. FF_Error_t FF_Move( FF_IOManager_t * pxIOManager,
  733. const FF_T_WCHAR * szSourceFile,
  734. const FF_T_WCHAR * szDestinationFile,
  735. BaseType_t xDeleteIfExists )
  736. #else
  737. FF_Error_t FF_Move( FF_IOManager_t * pxIOManager,
  738. const char * szSourceFile,
  739. const char * szDestinationFile,
  740. BaseType_t xDeleteIfExists )
  741. #endif
  742. {
  743. FF_Error_t xError;
  744. FF_FILE * pSrcFile, * pxDestFile;
  745. FF_DirEnt_t xMyFile;
  746. uint8_t ucEntryBuffer[ 32 ];
  747. BaseType_t xIndex;
  748. uint32_t ulDirCluster = 0ul;
  749. FF_FetchContext_t xFetchContext;
  750. #if ( ffconfigPATH_CACHE != 0 )
  751. BaseType_t xIsDirectory = pdFALSE;
  752. #endif
  753. memset( &xFetchContext, '\0', sizeof( xFetchContext ) );
  754. if( pxIOManager == NULL )
  755. {
  756. xError = ( FF_Error_t ) ( FF_ERR_NULL_POINTER | FF_MOVE );
  757. }
  758. #if ( ffconfigREMOVABLE_MEDIA != 0 )
  759. else if( ( pxIOManager->ucFlags & FF_IOMAN_DEVICE_IS_EXTRACTED ) != 0 )
  760. {
  761. xError = ( FF_Error_t ) ( FF_ERR_IOMAN_DRIVER_NOMEDIUM | FF_MOVE );
  762. }
  763. #endif /* ffconfigREMOVABLE_MEDIA */
  764. else
  765. {
  766. /* Check destination file doesn't exist! */
  767. pxDestFile = FF_Open( pxIOManager, szDestinationFile, FF_MODE_READ, &xError );
  768. if( ( pxDestFile != NULL ) || ( FF_GETERROR( xError ) == FF_ERR_FILE_OBJECT_IS_A_DIR ) )
  769. {
  770. xError = ( FF_Error_t ) ( FF_ERR_FILE_DESTINATION_EXISTS | FF_MOVE );
  771. if( pxDestFile != NULL )
  772. {
  773. FF_Close( pxDestFile );
  774. if( xDeleteIfExists != pdFALSE )
  775. {
  776. xError = FF_RmFile( pxIOManager, szDestinationFile );
  777. }
  778. }
  779. }
  780. else
  781. {
  782. /* Discard the error set by FF_Open().
  783. * The target file (or directory) is not found: continue renaming. */
  784. xError = FF_ERR_NONE;
  785. }
  786. }
  787. if( FF_isERR( xError ) == pdFALSE )
  788. {
  789. /* About to move/rename 'szSourceFile'. When opening it with 'FF_MODE_WRITE'
  790. * only succeeds if it has no other open handle to it. */
  791. pSrcFile = FF_Open( pxIOManager, szSourceFile, FF_MODE_WRITE, &xError );
  792. if( FF_GETERROR( xError ) == FF_ERR_FILE_OBJECT_IS_A_DIR )
  793. {
  794. /* Open a directory for moving! */
  795. pSrcFile = FF_Open( pxIOManager, szSourceFile, FF_MODE_DIR, &xError );
  796. #if ( ffconfigPATH_CACHE != 0 )
  797. xIsDirectory = pdTRUE;
  798. #endif
  799. }
  800. if( pSrcFile != NULL )
  801. {
  802. /* Collect information about the current directory entry. */
  803. xError = FF_InitEntryFetch( pxIOManager, pSrcFile->ulDirCluster, &xFetchContext );
  804. if( FF_isERR( xError ) == pdFALSE )
  805. {
  806. xError = FF_FetchEntryWithContext( pxIOManager, pSrcFile->usDirEntry, &xFetchContext, ucEntryBuffer );
  807. if( FF_isERR( xError ) == pdFALSE )
  808. {
  809. xMyFile.ucAttrib = FF_getChar( ucEntryBuffer, ( uint16_t ) ( FF_FAT_DIRENT_ATTRIB ) );
  810. xMyFile.ulFileSize = pSrcFile->ulFileSize;
  811. xMyFile.ulObjectCluster = pSrcFile->ulObjectCluster;
  812. xMyFile.usCurrentItem = 0;
  813. xIndex = ( BaseType_t ) STRLEN( szDestinationFile );
  814. while( xIndex != 0 )
  815. {
  816. if( ( szDestinationFile[ xIndex ] == '\\' ) || ( szDestinationFile[ xIndex ] == '/' ) )
  817. {
  818. break;
  819. }
  820. xIndex--;
  821. }
  822. /* Copy the base name of the destination file. */
  823. STRNCPY( xMyFile.pcFileName, ( szDestinationFile + xIndex + 1 ), ffconfigMAX_FILENAME );
  824. if( xIndex == 0 )
  825. {
  826. xIndex = 1;
  827. }
  828. /* Find the (cluster of the) directory in which the target file will be located.
  829. * It must exist before calling FF_Move(). */
  830. ulDirCluster = FF_FindDir( pxIOManager, szDestinationFile, xIndex, &xError );
  831. }
  832. }
  833. }
  834. if( FF_isERR( xError ) == pdFALSE )
  835. {
  836. if( ulDirCluster != 0ul )
  837. {
  838. FF_FindParams_t xFindParams;
  839. memset( &xFindParams, '\0', sizeof( xFindParams ) );
  840. /* Clean up because FF_CreateDirent might want to write to the same sector. */
  841. xError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext );
  842. if( FF_isERR( xError ) == pdFALSE )
  843. {
  844. /* Destination directory was found, we can now create the new entry. */
  845. xFindParams.ulDirCluster = ulDirCluster;
  846. xError = FF_CreateDirent( pxIOManager, &xFindParams, &xMyFile );
  847. }
  848. if( FF_isERR( xError ) == pdFALSE )
  849. {
  850. /* Edit the Directory Entry! (So it appears as deleted); */
  851. FF_LockDirectory( pxIOManager );
  852. {
  853. xError = FF_RmLFNs( pxIOManager, pSrcFile->usDirEntry, &xFetchContext );
  854. if( FF_isERR( xError ) == pdFALSE )
  855. {
  856. xError = FF_FetchEntryWithContext( pxIOManager, pSrcFile->usDirEntry, &xFetchContext, ucEntryBuffer );
  857. if( FF_isERR( xError ) == pdFALSE )
  858. {
  859. FF_Error_t xTempError;
  860. ucEntryBuffer[ 0 ] = FF_FAT_DELETED;
  861. FF_putShort( ucEntryBuffer, FF_FAT_DIRENT_CLUS_HIGH, ( uint32_t ) 0ul );
  862. FF_putShort( ucEntryBuffer, FF_FAT_DIRENT_CLUS_LOW, ( uint32_t ) 0ul );
  863. xError = FF_PushEntryWithContext( pxIOManager, pSrcFile->usDirEntry, &xFetchContext, ucEntryBuffer );
  864. /* The contents of 'xFetchContext' has changed, flush it to disk now. */
  865. xTempError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext );
  866. if( FF_isERR( xError ) == pdFALSE )
  867. {
  868. xError = xTempError;
  869. }
  870. }
  871. }
  872. }
  873. FF_UnlockDirectory( pxIOManager );
  874. }
  875. #if ( ffconfigPATH_CACHE != 0 )
  876. {
  877. if( xIsDirectory != 0 )
  878. {
  879. /* We've renamed a directory which might contain
  880. * subdirectories. To avoid having false entries, clear
  881. * the path cache. */
  882. FF_RmPathCache( pxIOManager, szSourceFile );
  883. }
  884. }
  885. #endif
  886. }
  887. else /* ulDirCluster == 0ul */
  888. {
  889. xError = ( FF_Error_t ) ( FF_ERR_FILE_DIR_NOT_FOUND | FF_MOVE );
  890. }
  891. }
  892. if( pSrcFile != NULL )
  893. {
  894. /* The source file was opened in WRITE mode just to lock it.
  895. * Now clear the write flags to avoid writing back any changes. */
  896. pSrcFile->ucMode &= ~( FF_MODE_WRITE | FF_MODE_APPEND | FF_MODE_CREATE );
  897. FF_Close( pSrcFile );
  898. }
  899. }
  900. {
  901. FF_Error_t xTempError;
  902. xTempError = FF_FlushCache( pxIOManager );
  903. if( FF_isERR( xError ) == pdFALSE )
  904. {
  905. xError = xTempError;
  906. }
  907. xTempError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext );
  908. if( FF_isERR( xError ) == pdFALSE )
  909. {
  910. xError = xTempError;
  911. }
  912. }
  913. return xError;
  914. } /* FF_Move() */
  915. /*-----------------------------------------------------------*/
  916. /**
  917. * @public
  918. * @brief Get's the next Entry based on the data recorded in the FF_DirEnt_t object.
  919. *
  920. * @param pxFile FF_FILE object that was created by FF_Open().
  921. *
  922. * @return pdTRUE if End of File was reached. pdFALSE if not.
  923. * @return pdFALSE if a null pointer was provided.
  924. *
  925. **/
  926. BaseType_t FF_isEOF( FF_FILE * pxFile )
  927. {
  928. BaseType_t xReturn;
  929. if( ( pxFile != NULL ) && ( pxFile->ulFilePointer >= pxFile->ulFileSize ) )
  930. {
  931. xReturn = pdTRUE;
  932. }
  933. else
  934. {
  935. xReturn = pdFALSE;
  936. }
  937. return xReturn;
  938. } /* FF_isEOF() */
  939. /*-----------------------------------------------------------*/
  940. /**
  941. * @public
  942. * @brief Checks the number of bytes left on a read handle
  943. *
  944. * @param pxFile An open file handle
  945. *
  946. * @return Less than zero: an error code
  947. * @return Number of bytes left to read from handle
  948. **/
  949. int32_t FF_BytesLeft( FF_FILE * pxFile )
  950. {
  951. BaseType_t xReturn;
  952. if( pxFile == NULL )
  953. {
  954. xReturn = FF_ERR_NULL_POINTER | FF_BYTESLEFT;
  955. }
  956. else if( ( pxFile->ucMode & FF_MODE_READ ) == 0 )
  957. {
  958. xReturn = FF_ERR_FILE_NOT_OPENED_IN_READ_MODE | FF_BYTESLEFT;
  959. }
  960. else if( pxFile->ulFilePointer >= pxFile->ulFileSize )
  961. {
  962. xReturn = 0;
  963. }
  964. else
  965. {
  966. xReturn = pxFile->ulFileSize - pxFile->ulFilePointer;
  967. }
  968. return xReturn;
  969. } /* FF_BytesLeft() */
  970. /*-----------------------------------------------------------*/
  971. /**
  972. * @public
  973. * @brief Returns the file size of a read handle
  974. *
  975. * @param pxFile An open file handle
  976. *
  977. * @return Less than zero: an error code
  978. * @return Number of bytes left to read from handle
  979. **/
  980. FF_Error_t FF_GetFileSize( FF_FILE * pxFile,
  981. uint32_t * pulSize ) /* Writes # of bytes in a file to the parameter. */
  982. {
  983. BaseType_t xReturn;
  984. if( pxFile == NULL )
  985. {
  986. xReturn = ( FF_Error_t ) ( FF_ERR_NULL_POINTER | FF_BYTESLEFT );
  987. *( pulSize ) = ( uint32_t ) 0u;
  988. }
  989. else if( FF_isERR( FF_CheckValid( pxFile ) ) )
  990. {
  991. xReturn = ( FF_Error_t ) ( FF_ERR_FILE_BAD_HANDLE | FF_BYTESLEFT );
  992. *( pulSize ) = ( uint32_t ) 0u;
  993. }
  994. else
  995. {
  996. xReturn = 0;
  997. *( pulSize ) = pxFile->ulFileSize;
  998. }
  999. return xReturn;
  1000. } /* FF_GetFileSize */
  1001. int32_t FF_FileSize( FF_FILE * pxFile )
  1002. {
  1003. uint32_t ulLength;
  1004. FF_Error_t xResult;
  1005. /* Function is deprecated. Please use FF_GetFileSize(). */
  1006. xResult = FF_GetFileSize( pxFile, &( ulLength ) );
  1007. if( FF_isERR( xResult ) == 0 )
  1008. {
  1009. xResult = ( int32_t ) ulLength;
  1010. }
  1011. return ( int32_t ) xResult;
  1012. } /* FF_FileSize() */
  1013. /*-----------------------------------------------------------*/
  1014. static uint32_t FF_GetSequentialClusters( FF_IOManager_t * pxIOManager,
  1015. uint32_t ulStartCluster,
  1016. uint32_t ulLimit,
  1017. FF_Error_t * pxError )
  1018. {
  1019. uint32_t ulCurrentCluster;
  1020. uint32_t ulNextCluster = ulStartCluster;
  1021. uint32_t ulIndex = 0;
  1022. FF_FATBuffers_t xFATBuffers;
  1023. FF_InitFATBuffers( &xFATBuffers, FF_MODE_READ );
  1024. *pxError = FF_ERR_NONE;
  1025. FF_LockFAT( pxIOManager );
  1026. do
  1027. {
  1028. ulCurrentCluster = ulNextCluster;
  1029. ulNextCluster = FF_getFATEntry( pxIOManager, ulCurrentCluster, pxError, &xFATBuffers );
  1030. if( FF_isERR( *pxError ) )
  1031. {
  1032. ulIndex = 0;
  1033. break;
  1034. }
  1035. if( ulNextCluster == ( ulCurrentCluster + 1 ) )
  1036. {
  1037. ulIndex++;
  1038. }
  1039. else
  1040. {
  1041. break;
  1042. }
  1043. if( ( ulLimit != 0 ) && ( ulIndex == ulLimit ) )
  1044. {
  1045. break;
  1046. }
  1047. }
  1048. while( ulNextCluster == ( ulCurrentCluster + 1 ) );
  1049. FF_UnlockFAT( pxIOManager );
  1050. *pxError = FF_ReleaseFATBuffers( pxIOManager, &xFATBuffers );
  1051. return ulIndex;
  1052. } /* FF_GetSequentialClusters() */
  1053. /*-----------------------------------------------------------*/
  1054. static FF_Error_t FF_ReadClusters( FF_FILE * pxFile,
  1055. uint32_t ulCount,
  1056. uint8_t * buffer )
  1057. {
  1058. uint32_t ulSectors;
  1059. uint32_t ulSequentialClusters = 0;
  1060. uint32_t ulItemLBA;
  1061. FF_Error_t xError = FF_ERR_NONE;
  1062. while( ulCount != 0 )
  1063. {
  1064. if( ( ulCount - 1 ) > 0 )
  1065. {
  1066. ulSequentialClusters =
  1067. FF_GetSequentialClusters( pxFile->pxIOManager, pxFile->ulAddrCurrentCluster, ulCount - 1, &xError );
  1068. if( FF_isERR( xError ) )
  1069. {
  1070. break;
  1071. }
  1072. }
  1073. ulSectors = ( ulSequentialClusters + 1 ) * pxFile->pxIOManager->xPartition.ulSectorsPerCluster;
  1074. ulItemLBA = FF_Cluster2LBA( pxFile->pxIOManager, pxFile->ulAddrCurrentCluster );
  1075. ulItemLBA = FF_getRealLBA( pxFile->pxIOManager, ulItemLBA );
  1076. xError = FF_BlockRead( pxFile->pxIOManager, ulItemLBA, ulSectors, buffer, pdFALSE );
  1077. if( FF_isERR( xError ) )
  1078. {
  1079. break;
  1080. }
  1081. ulCount -= ( ulSequentialClusters + 1 );
  1082. FF_LockFAT( pxFile->pxIOManager );
  1083. {
  1084. pxFile->ulAddrCurrentCluster =
  1085. FF_TraverseFAT( pxFile->pxIOManager, pxFile->ulAddrCurrentCluster, ulSequentialClusters + 1, &xError );
  1086. }
  1087. FF_UnlockFAT( pxFile->pxIOManager );
  1088. if( FF_isERR( xError ) )
  1089. {
  1090. break;
  1091. }
  1092. pxFile->ulCurrentCluster += ( ulSequentialClusters + 1 );
  1093. buffer += ulSectors * pxFile->pxIOManager->usSectorSize;
  1094. ulSequentialClusters = 0;
  1095. }
  1096. return xError;
  1097. } /* FF_ReadClusters ()*/
  1098. /*-----------------------------------------------------------*/
  1099. static FF_Error_t FF_ExtendFile( FF_FILE * pxFile,
  1100. uint32_t ulSize )
  1101. {
  1102. FF_IOManager_t * pxIOManager = pxFile->pxIOManager;
  1103. uint32_t ulBytesPerCluster = pxIOManager->xPartition.usBlkSize * pxIOManager->xPartition.ulSectorsPerCluster;
  1104. uint32_t ulTotalClustersNeeded = ( ulSize + ulBytesPerCluster - 1 ) / ulBytesPerCluster;
  1105. uint32_t ulClusterToExtend;
  1106. /* Initialise xIndex just for the compiler. */
  1107. BaseType_t xIndex = 0;
  1108. FF_DirEnt_t xOriginalEntry;
  1109. FF_Error_t xError = FF_ERR_NONE;
  1110. FF_FATBuffers_t xFATBuffers;
  1111. if( ( pxFile->ucMode & FF_MODE_WRITE ) != FF_MODE_WRITE )
  1112. {
  1113. xError = ( FF_Error_t ) ( FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE | FF_EXTENDFILE );
  1114. }
  1115. else
  1116. {
  1117. if( ( pxFile->ulFileSize == 0 ) && ( pxFile->ulObjectCluster == 0 ) )
  1118. {
  1119. /* If there is no object cluster yet, create it.*/
  1120. pxFile->ulAddrCurrentCluster = FF_CreateClusterChain( pxFile->pxIOManager, &xError );
  1121. if( FF_isERR( xError ) == pdFALSE )
  1122. {
  1123. /* The directory denotes the address of the first data cluster of every file.
  1124. * Now change it to 'ulAddrCurrentCluster': */
  1125. xError = FF_GetEntry( pxIOManager, pxFile->usDirEntry, pxFile->ulDirCluster, &xOriginalEntry );
  1126. if( FF_isERR( xError ) == pdFALSE )
  1127. {
  1128. xOriginalEntry.ulObjectCluster = pxFile->ulAddrCurrentCluster;
  1129. xError = FF_PutEntry( pxIOManager, pxFile->usDirEntry, pxFile->ulDirCluster, &xOriginalEntry, NULL );
  1130. if( FF_isERR( xError ) == pdFALSE )
  1131. {
  1132. pxFile->ulObjectCluster = pxFile->ulAddrCurrentCluster;
  1133. pxFile->ulChainLength = 1;
  1134. pxFile->ulCurrentCluster = 0;
  1135. pxFile->ulEndOfChain = pxFile->ulAddrCurrentCluster;
  1136. }
  1137. }
  1138. }
  1139. }
  1140. else
  1141. {
  1142. /* This file already has at least one cluster. */
  1143. }
  1144. }
  1145. if( FF_isERR( xError ) == pdFALSE )
  1146. {
  1147. if( pxFile->ulChainLength == 0 )
  1148. {
  1149. /* This is the first extension requiring the chain length.
  1150. * Calculate it now: */
  1151. pxFile->ulChainLength = FF_GetChainLength( pxIOManager, pxFile->ulObjectCluster, &pxFile->ulEndOfChain, &xError );
  1152. }
  1153. }
  1154. if( ( FF_isERR( xError ) == pdFALSE ) && ( ulTotalClustersNeeded > pxFile->ulChainLength ) )
  1155. {
  1156. uint32_t ulCurrentCluster, ulNextCluster;
  1157. ulClusterToExtend = ( ulTotalClustersNeeded - pxFile->ulChainLength );
  1158. /* Now the file has at least 1 cluster, but it needs more clusters. */
  1159. ulNextCluster = pxFile->ulAddrCurrentCluster;
  1160. FF_LockFAT( pxIOManager );
  1161. ulCurrentCluster = FF_FindEndOfChain( pxIOManager, ulNextCluster, &xError );
  1162. if( FF_isERR( xError ) == pdFALSE )
  1163. {
  1164. for( xIndex = 0; xIndex < ( BaseType_t ) ulClusterToExtend; xIndex++ )
  1165. {
  1166. /* In FF_ExtendFile() */
  1167. ulNextCluster = FF_FindFreeCluster( pxIOManager, &xError, pdTRUE );
  1168. if( ( FF_isERR( xError ) == pdFALSE ) && ( ulNextCluster == 0UL ) )
  1169. {
  1170. xError = ( FF_Error_t ) ( FF_ERR_FAT_NO_FREE_CLUSTERS | FF_EXTENDFILE );
  1171. }
  1172. if( FF_isERR( xError ) )
  1173. {
  1174. break;
  1175. }
  1176. /* Can not use this buffer earlier because of FF_FindEndOfChain/FF_FindFreeCluster */
  1177. FF_InitFATBuffers( &xFATBuffers, FF_MODE_WRITE );
  1178. xError = FF_putFATEntry( pxIOManager, ulCurrentCluster, ulNextCluster, &xFATBuffers );
  1179. if( FF_isERR( xError ) )
  1180. {
  1181. break;
  1182. }
  1183. xError = FF_ReleaseFATBuffers( pxIOManager, &xFATBuffers );
  1184. if( FF_isERR( xError ) )
  1185. {
  1186. break;
  1187. }
  1188. ulCurrentCluster = ulNextCluster;
  1189. }
  1190. if( FF_isERR( xError ) == pdFALSE )
  1191. {
  1192. pxFile->ulEndOfChain = ulCurrentCluster;
  1193. }
  1194. pxFile->ulChainLength += xIndex;
  1195. }
  1196. FF_UnlockFAT( pxIOManager );
  1197. {
  1198. FF_Error_t xTempError;
  1199. xTempError = FF_DecreaseFreeClusters( pxIOManager, ( uint32_t ) xIndex ); /* Keep Tab of Numbers for fast FreeSize() */
  1200. if( FF_isERR( xError ) == pdFALSE )
  1201. {
  1202. xError = xTempError;
  1203. }
  1204. }
  1205. /* We must ensure that the ulAddrCurrentCluster is not out-of-sync with the CurrentCluster number.
  1206. * This could have occurred in append mode, where the file was opened with a filesize % clustersize == 0
  1207. * because of a seek, where the ulAddrCurrentCluster was not updated after extending. This caused the data to
  1208. * be written to the previous cluster(s). */
  1209. if( ( pxFile->ulCurrentCluster == pxFile->ulChainLength - 1 ) &&
  1210. ( pxFile->ulAddrCurrentCluster != pxFile->ulEndOfChain ) )
  1211. {
  1212. pxFile->ulAddrCurrentCluster = pxFile->ulEndOfChain;
  1213. }
  1214. /* By default, 'ffconfigFILE_EXTEND_FLUSHES_BUFFERS' is
  1215. * defined as 1.
  1216. * Users may set it to zero in order to increase the
  1217. * speed of writing to disk. */
  1218. #if ( ffconfigFILE_EXTEND_FLUSHES_BUFFERS != 0 )
  1219. {
  1220. FF_Error_t xTempError;
  1221. xTempError = FF_FlushCache( pxIOManager );
  1222. if( FF_isERR( xError ) == pdFALSE )
  1223. {
  1224. xError = xTempError;
  1225. }
  1226. }
  1227. #endif /* ffconfigFILE_EXTEND_FLUSHES_BUFFERS */
  1228. if( pxFile->ulFilePointer == pxFile->ulFileSize )
  1229. {
  1230. /* Writing at the end of a file, while new clusters have just been added.
  1231. * Make sure that the fields 'ulCurrentCluster' and 'ulAddrCurrentCluster' are
  1232. * set correctly.
  1233. */
  1234. FF_Error_t xTempError = FF_ERR_NONE;
  1235. uint32_t ulNewCluster = FF_getClusterChainNumber( pxIOManager, pxFile->ulFilePointer, 1 );
  1236. FF_LockFAT( pxIOManager );
  1237. {
  1238. pxFile->ulAddrCurrentCluster = FF_TraverseFAT( pxIOManager, pxFile->ulObjectCluster, ulNewCluster, &( xTempError ) );
  1239. pxFile->ulCurrentCluster = ulNewCluster;
  1240. }
  1241. FF_UnlockFAT( pxIOManager );
  1242. if( FF_isERR( xError ) == pdFALSE )
  1243. {
  1244. xError = xTempError;
  1245. }
  1246. }
  1247. } /* if( ulTotalClustersNeeded > pxFile->ulChainLength ) */
  1248. return xError;
  1249. } /* FF_ExtendFile() */
  1250. /*-----------------------------------------------------------*/
  1251. static FF_Error_t FF_WriteClusters( FF_FILE * pxFile,
  1252. uint32_t ulCount,
  1253. uint8_t * buffer )
  1254. {
  1255. uint32_t ulSectors;
  1256. uint32_t ulSequentialClusters = 0;
  1257. uint32_t ulItemLBA;
  1258. FF_Error_t xError = FF_ERR_NONE;
  1259. while( ulCount != 0 )
  1260. {
  1261. if( ulCount > 1U )
  1262. {
  1263. ulSequentialClusters =
  1264. FF_GetSequentialClusters( pxFile->pxIOManager, pxFile->ulAddrCurrentCluster, ulCount - 1, &xError );
  1265. if( FF_isERR( xError ) )
  1266. {
  1267. break;
  1268. }
  1269. }
  1270. else
  1271. {
  1272. /* Handling the last cluster which is a single one. */
  1273. }
  1274. ulSectors = ( ulSequentialClusters + 1 ) * pxFile->pxIOManager->xPartition.ulSectorsPerCluster;
  1275. ulItemLBA = FF_Cluster2LBA( pxFile->pxIOManager, pxFile->ulAddrCurrentCluster );
  1276. ulItemLBA = FF_getRealLBA( pxFile->pxIOManager, ulItemLBA );
  1277. xError = FF_BlockWrite( pxFile->pxIOManager, ulItemLBA, ulSectors, buffer, pdFALSE );
  1278. if( FF_isERR( xError ) )
  1279. {
  1280. break;
  1281. }
  1282. ulCount -= ulSequentialClusters + 1;
  1283. FF_LockFAT( pxFile->pxIOManager );
  1284. {
  1285. pxFile->ulAddrCurrentCluster =
  1286. FF_TraverseFAT( pxFile->pxIOManager, pxFile->ulAddrCurrentCluster, ulSequentialClusters + 1, &xError );
  1287. }
  1288. FF_UnlockFAT( pxFile->pxIOManager );
  1289. if( FF_isERR( xError ) )
  1290. {
  1291. break;
  1292. }
  1293. pxFile->ulCurrentCluster += ( ulSequentialClusters + 1 );
  1294. buffer += ulSectors * pxFile->pxIOManager->usSectorSize;
  1295. ulSequentialClusters = 0;
  1296. }
  1297. return xError;
  1298. } /* FF_WriteClusters */
  1299. /*-----------------------------------------------------------*/
  1300. /**
  1301. * @private
  1302. * @brief Calculate the Logical Block Address (LBA)
  1303. *
  1304. * @param pxFile The file handle
  1305. *
  1306. * @return LBA
  1307. *
  1308. * Must be set:
  1309. * - pxFile->ulFilePointer : byte offset in file
  1310. * - pxFile->ulAddrCurrentCluster : physical cluster on the partition
  1311. **/
  1312. static uint32_t FF_FileLBA( FF_FILE * pxFile )
  1313. {
  1314. uint32_t ulItemLBA;
  1315. ulItemLBA = FF_Cluster2LBA( pxFile->pxIOManager, pxFile->ulAddrCurrentCluster );
  1316. ulItemLBA += FF_getMajorBlockNumber( pxFile->pxIOManager, pxFile->ulFilePointer, 1 );
  1317. ulItemLBA = FF_getRealLBA( pxFile->pxIOManager, ulItemLBA );
  1318. ulItemLBA += FF_getMinorBlockNumber( pxFile->pxIOManager, pxFile->ulFilePointer, 1 );
  1319. return ulItemLBA;
  1320. } /* FF_FileLBA() */
  1321. /*-----------------------------------------------------------*/
  1322. /**
  1323. * @private
  1324. * @brief Depending on FilePointer, calculate CurrentCluster
  1325. * @brief and traverse the FAT to find the right ulAddrCurrentCluster
  1326. *
  1327. * @param pxFile The file handle
  1328. *
  1329. * @return FF_ERR_NONE on success
  1330. * @return Possible error returned by FF_TraverseFAT() or END_OF_DIR
  1331. *
  1332. * Side effects:
  1333. * - pxFile->ulCurrentCluster : relative cluster number (0 <= Num < ulChainLength)
  1334. * - pxFile->ulAddrCurrentCluster : fysical cluster on the partition
  1335. **/
  1336. static uint32_t FF_SetCluster( FF_FILE * pxFile,
  1337. FF_Error_t * pxError )
  1338. {
  1339. FF_IOManager_t * pxIOManager = pxFile->pxIOManager;
  1340. uint32_t ulNewCluster = FF_getClusterChainNumber( pxIOManager, pxFile->ulFilePointer, 1 );
  1341. FF_Error_t xResult = FF_ERR_NONE;
  1342. uint32_t ulReturn;
  1343. if( ulNewCluster > pxFile->ulCurrentCluster )
  1344. {
  1345. FF_LockFAT( pxIOManager );
  1346. {
  1347. pxFile->ulAddrCurrentCluster = FF_TraverseFAT( pxIOManager, pxFile->ulAddrCurrentCluster,
  1348. ulNewCluster - pxFile->ulCurrentCluster, &xResult );
  1349. }
  1350. FF_UnlockFAT( pxIOManager );
  1351. }
  1352. else if( ulNewCluster < pxFile->ulCurrentCluster )
  1353. {
  1354. FF_LockFAT( pxIOManager );
  1355. {
  1356. pxFile->ulAddrCurrentCluster = FF_TraverseFAT( pxIOManager, pxFile->ulObjectCluster, ulNewCluster, &xResult );
  1357. }
  1358. FF_UnlockFAT( pxIOManager );
  1359. }
  1360. else
  1361. {
  1362. /* Well positioned. */
  1363. }
  1364. if( FF_isERR( xResult ) == pdFALSE )
  1365. {
  1366. pxFile->ulCurrentCluster = ulNewCluster;
  1367. ulReturn = FF_FileLBA( pxFile );
  1368. }
  1369. else
  1370. {
  1371. ulReturn = 0;
  1372. }
  1373. *pxError = xResult;
  1374. return ulReturn;
  1375. } /* FF_SetCluster() */
  1376. /*-----------------------------------------------------------*/
  1377. static int32_t FF_ReadPartial( FF_FILE * pxFile,
  1378. uint32_t ulItemLBA,
  1379. uint32_t ulRelBlockPos,
  1380. uint32_t ulCount,
  1381. uint8_t * pucBuffer,
  1382. FF_Error_t * pxError )
  1383. {
  1384. FF_Error_t xError = FF_ERR_NONE;
  1385. uint32_t ulBytesRead;
  1386. /* Bytes to read are within a block and less than a block size. */
  1387. #if ( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 )
  1388. {
  1389. BaseType_t xLastRead;
  1390. /* Optimised method: each file handle holds one data block
  1391. * in cache: 'pxFile->pucBuffer'. */
  1392. /* See if the current block will be accessed after this read: */
  1393. if( ( ulRelBlockPos + ulCount ) >= ( uint32_t ) pxFile->pxIOManager->usSectorSize )
  1394. {
  1395. /* After this read, ulFilePointer will point to the next block/sector. */
  1396. xLastRead = pdTRUE;
  1397. }
  1398. else
  1399. {
  1400. /* It is not the last read within this block/sector. */
  1401. xLastRead = pdFALSE;
  1402. }
  1403. if( ( pxFile->ucState & FF_BUFSTATE_VALID ) == 0 )
  1404. {
  1405. xError = FF_BlockRead( pxFile->pxIOManager, ulItemLBA, 1, pxFile->pucBuffer, pdFALSE );
  1406. if( FF_isERR( xError ) == pdFALSE )
  1407. {
  1408. pxFile->ucState = FF_BUFSTATE_VALID;
  1409. }
  1410. }
  1411. if( ( pxFile->ucState & FF_BUFSTATE_VALID ) != 0 )
  1412. {
  1413. memcpy( pucBuffer, pxFile->pucBuffer + ulRelBlockPos, ulCount );
  1414. pxFile->ulFilePointer += ulCount;
  1415. ulBytesRead = ulCount;
  1416. if( ( xLastRead == pdTRUE ) && ( ( pxFile->ucState & FF_BUFSTATE_WRITTEN ) != 0 ) )
  1417. {
  1418. /* If the data was changed (file in 'update' mode), store the changes: */
  1419. xError = FF_BlockWrite( pxFile->pxIOManager, ulItemLBA, 1, pxFile->pucBuffer, pdFALSE );
  1420. }
  1421. }
  1422. else
  1423. {
  1424. ulBytesRead = 0ul;
  1425. }
  1426. if( xLastRead == pdTRUE )
  1427. {
  1428. /* As the next FF_Read() will go passed the current block, invalidate the buffer now. */
  1429. pxFile->ucState = FF_BUFSTATE_INVALID;
  1430. }
  1431. }
  1432. #else /* if ( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 ) */
  1433. {
  1434. FF_Buffer_t * pxBuffer;
  1435. /* Reading in the standard way, using FF_Buffer_t. */
  1436. pxBuffer = FF_GetBuffer( pxFile->pxIOManager, ulItemLBA, FF_MODE_READ );
  1437. if( pxBuffer == NULL )
  1438. {
  1439. xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_READ );
  1440. ulBytesRead = 0ul;
  1441. }
  1442. else
  1443. {
  1444. memcpy( pucBuffer, pxBuffer->pucBuffer + ulRelBlockPos, ulCount );
  1445. /* Releasing a buffer in FF_MODE_READ mode will not lead to an error,
  1446. * because no disk access is needed. */
  1447. xError = FF_ReleaseBuffer( pxFile->pxIOManager, pxBuffer );
  1448. pxFile->ulFilePointer += ulCount;
  1449. ulBytesRead = ulCount;
  1450. }
  1451. }
  1452. #endif /* if ( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 ) */
  1453. *pxError = xError;
  1454. return ulBytesRead;
  1455. } /* FF_ReadPartial() */
  1456. /*-----------------------------------------------------------*/
  1457. /**
  1458. * @public
  1459. * @brief Equivalent to fread()
  1460. *
  1461. * @param pxFile FF_FILE object that was created by FF_Open().
  1462. * @param ulElementSize The size of an element to read.
  1463. * @param ulCount The number of elements to read.
  1464. * @param buffer A pointer to a buffer of adequate size to be filled with the requested data.
  1465. *
  1466. * @return Number of bytes read.
  1467. *
  1468. * FF_Read() and FF_Write() work very similar. They both complete their task in 5 steps:
  1469. * 1. Read bytes up to a sector border: FF_ReadPartial()
  1470. * 2. Read sectors up to cluster border: FF_BlockRead()
  1471. * 3. Read complete clusters: FF_ReadClusters()
  1472. * 4. Read remaining sectors: FF_BlockRead()
  1473. * 5. Read remaining bytes: FF_ReadPartial()
  1474. **/
  1475. int32_t FF_Read( FF_FILE * pxFile,
  1476. uint32_t ulElementSize,
  1477. uint32_t ulCount,
  1478. uint8_t * pucBuffer )
  1479. {
  1480. uint32_t ulBytesLeft = ulElementSize * ulCount;
  1481. uint32_t ulBytesRead = 0;
  1482. uint32_t ulBytesToRead;
  1483. FF_IOManager_t * pxIOManager;
  1484. uint32_t ulRelBlockPos;
  1485. uint32_t ulItemLBA;
  1486. int32_t lResult;
  1487. uint32_t ulSectors;
  1488. uint32_t ulRelClusterPos;
  1489. uint32_t ulBytesPerCluster;
  1490. FF_Error_t xError;
  1491. if( pxFile == NULL )
  1492. {
  1493. xError = ( FF_Error_t ) ( FF_ERR_NULL_POINTER | FF_READ );
  1494. }
  1495. else
  1496. {
  1497. /* Check validity of the handle and the current position within the file. */
  1498. xError = FF_CheckValid( pxFile );
  1499. if( FF_isERR( xError ) == pdFALSE )
  1500. {
  1501. if( ( pxFile->ucMode & FF_MODE_READ ) == 0 )
  1502. {
  1503. /* File was not opened with READ mode access. */
  1504. xError = ( FF_Error_t ) ( FF_ERR_FILE_NOT_OPENED_IN_READ_MODE | FF_READ );
  1505. }
  1506. else if( pxFile->ulFilePointer >= pxFile->ulFileSize )
  1507. {
  1508. /* The end-of-file is reached. The error READ_ZERO will not be
  1509. * returned, it is just used to avoid further processing. */
  1510. xError = ( FF_Error_t ) ( FF_ERR_FILE_READ_ZERO | FF_READ );
  1511. }
  1512. else if( ( pxFile->ulFilePointer + ulBytesLeft ) > pxFile->ulFileSize )
  1513. {
  1514. /* Note that many bytes can be read. */
  1515. ulBytesLeft = pxFile->ulFileSize - pxFile->ulFilePointer;
  1516. }
  1517. }
  1518. else
  1519. {
  1520. /* The file handle is not valid. */
  1521. }
  1522. } /* else pxFile != NULL */
  1523. if( FF_isERR( xError ) == pdFALSE )
  1524. {
  1525. pxIOManager = pxFile->pxIOManager;
  1526. /* And calculate the Logical Block Address. */
  1527. ulItemLBA = FF_SetCluster( pxFile, &xError );
  1528. /* Get the position within a block. */
  1529. ulRelBlockPos = FF_getMinorBlockEntry( pxIOManager, pxFile->ulFilePointer, 1 );
  1530. /* Open a do {} while( 0 ) loop to allow easy breaks: */
  1531. do
  1532. {
  1533. if( ( ulRelBlockPos + ulBytesLeft ) <= ( uint32_t ) pxIOManager->usSectorSize )
  1534. {
  1535. /*---------- A small read within the current block only. */
  1536. ulBytesRead = FF_ReadPartial( pxFile, ulItemLBA, ulRelBlockPos, ulBytesLeft, pucBuffer, &xError );
  1537. break;
  1538. }
  1539. /*---------- Read (memcpy) to a Sector Boundary. */
  1540. if( ulRelBlockPos != 0 )
  1541. {
  1542. /* Not on a sector boundary, at this point the LBA is known. */
  1543. ulBytesToRead = pxIOManager->usSectorSize - ulRelBlockPos;
  1544. ulBytesRead = FF_ReadPartial( pxFile, ulItemLBA, ulRelBlockPos, ulBytesToRead, pucBuffer, &xError );
  1545. if( FF_isERR( xError ) )
  1546. {
  1547. break;
  1548. }
  1549. ulBytesLeft -= ulBytesRead;
  1550. pucBuffer += ulBytesRead;
  1551. }
  1552. /*---------- Read sectors, up to a Cluster Boundary. */
  1553. ulBytesPerCluster = ( pxIOManager->xPartition.ulSectorsPerCluster * pxIOManager->usSectorSize );
  1554. ulRelClusterPos = pxFile->ulFilePointer % ( ulBytesPerCluster * pxIOManager->xPartition.ucBlkFactor );
  1555. if( ( ulRelClusterPos != 0 ) && ( ( ulRelClusterPos + ulBytesLeft ) >= ulBytesPerCluster ) )
  1556. {
  1557. /* Need to get to cluster boundary. */
  1558. ulItemLBA = FF_SetCluster( pxFile, &xError );
  1559. if( FF_isERR( xError ) )
  1560. {
  1561. break;
  1562. }
  1563. ulSectors = pxIOManager->xPartition.ulSectorsPerCluster - ( ulRelClusterPos / pxIOManager->usSectorSize );
  1564. xError = FF_BlockRead( pxIOManager, ulItemLBA, ulSectors, pucBuffer, pdFALSE );
  1565. if( FF_isERR( xError ) )
  1566. {
  1567. break;
  1568. }
  1569. ulBytesToRead = ulSectors * pxIOManager->usSectorSize;
  1570. ulBytesLeft -= ulBytesToRead;
  1571. pucBuffer += ulBytesToRead;
  1572. ulBytesRead += ulBytesToRead;
  1573. pxFile->ulFilePointer += ulBytesToRead;
  1574. }
  1575. /*---------- Read entire clusters. */
  1576. if( ulBytesLeft >= ulBytesPerCluster )
  1577. {
  1578. uint32_t ulClusters;
  1579. FF_SetCluster( pxFile, &xError );
  1580. if( FF_isERR( xError ) )
  1581. {
  1582. break;
  1583. }
  1584. ulClusters = ulBytesLeft / ulBytesPerCluster;
  1585. xError = FF_ReadClusters( pxFile, ulClusters, pucBuffer );
  1586. if( FF_isERR( xError ) )
  1587. {
  1588. break;
  1589. }
  1590. ulBytesToRead = ulBytesPerCluster * ulClusters;
  1591. pxFile->ulFilePointer += ulBytesToRead;
  1592. ulBytesLeft -= ulBytesToRead;
  1593. pucBuffer += ulBytesToRead;
  1594. ulBytesRead += ulBytesToRead;
  1595. }
  1596. /*---------- Read Remaining Blocks. */
  1597. while( ulBytesLeft >= ( uint32_t ) pxIOManager->usSectorSize )
  1598. {
  1599. ulSectors = ulBytesLeft / pxIOManager->usSectorSize;
  1600. {
  1601. /* HT: I'd leave these pPart/ulOffset for readability */
  1602. /* and shorter code lines */
  1603. FF_Partition_t * pPart = &( pxIOManager->xPartition );
  1604. uint32_t ulOffset = ( pxFile->ulFilePointer / pxIOManager->usSectorSize ) % pPart->ulSectorsPerCluster;
  1605. uint32_t ulRemain = pPart->ulSectorsPerCluster - ulOffset;
  1606. if( ulSectors > ulRemain )
  1607. {
  1608. ulSectors = ulRemain;
  1609. }
  1610. }
  1611. ulItemLBA = FF_SetCluster( pxFile, &xError );
  1612. if( FF_isERR( xError ) )
  1613. {
  1614. break;
  1615. }
  1616. xError = FF_BlockRead( pxIOManager, ulItemLBA, ulSectors, pucBuffer, pdFALSE );
  1617. if( FF_isERR( xError ) )
  1618. {
  1619. break;
  1620. }
  1621. ulBytesToRead = ulSectors * pxIOManager->usSectorSize;
  1622. pxFile->ulFilePointer += ulBytesToRead;
  1623. ulBytesLeft -= ulBytesToRead;
  1624. pucBuffer += ulBytesToRead;
  1625. ulBytesRead += ulBytesToRead;
  1626. }
  1627. /*---------- Read (memcpy) Remaining Bytes */
  1628. if( ulBytesLeft == 0 )
  1629. {
  1630. break;
  1631. }
  1632. ulItemLBA = FF_SetCluster( pxFile, &xError );
  1633. if( FF_isERR( xError ) )
  1634. {
  1635. break;
  1636. }
  1637. /* Bytes to read are within a block and less than a block size. */
  1638. FF_ReadPartial( pxFile, ulItemLBA, 0, ulBytesLeft, pucBuffer, &xError );
  1639. if( FF_isERR( xError ) == pdFALSE )
  1640. {
  1641. ulBytesRead += ulBytesLeft;
  1642. }
  1643. }
  1644. while( pdFALSE );
  1645. } /* if( FF_isERR( xError ) == pdFALSE ) */
  1646. if( FF_GETERROR( xError ) == FF_ERR_FILE_READ_ZERO )
  1647. {
  1648. lResult = 0;
  1649. }
  1650. else if( FF_isERR( xError ) )
  1651. {
  1652. lResult = xError;
  1653. }
  1654. else
  1655. {
  1656. lResult = ( int32_t ) ( ulBytesRead / ulElementSize );
  1657. }
  1658. return lResult;
  1659. } /* FF_Read() */
  1660. /*-----------------------------------------------------------*/
  1661. /**
  1662. * @public
  1663. * @brief Equivalent to fgetc()
  1664. *
  1665. * @param pxFile FF_FILE object that was created by FF_Open().
  1666. *
  1667. * @return The character that was read (cast as a 32-bit interger). -1 on EOF.
  1668. * @return FF_Error_t code. (Check with if(FF_isERR(xRetVal)) {}).
  1669. * @return -1 EOF (end of file).
  1670. *
  1671. **/
  1672. int32_t FF_GetC( FF_FILE * pxFile )
  1673. {
  1674. uint32_t ulItemLBA;
  1675. uint8_t ucReturnedChar;
  1676. uint32_t ulRelBlockPos;
  1677. FF_Error_t xResult;
  1678. if( pxFile == NULL )
  1679. {
  1680. xResult = FF_ERR_NULL_POINTER | FF_GETC; /* Ensure this is a signed error. */
  1681. }
  1682. else if( ( pxFile->ucMode & FF_MODE_READ ) == 0 )
  1683. {
  1684. xResult = FF_ERR_FILE_NOT_OPENED_IN_READ_MODE | FF_GETC;
  1685. }
  1686. else if( pxFile->ulFilePointer >= pxFile->ulFileSize )
  1687. {
  1688. /* The end-of-file is reached. The error READ_ZERO will not be
  1689. * returned, it is just used to avoid further processing. */
  1690. xResult = FF_ERR_FILE_READ_ZERO | FF_READ;
  1691. }
  1692. else
  1693. {
  1694. ulRelBlockPos = FF_getMinorBlockEntry( pxFile->pxIOManager, pxFile->ulFilePointer, 1 );
  1695. ulItemLBA = FF_SetCluster( pxFile, &xResult );
  1696. if( FF_isERR( xResult ) == pdFALSE )
  1697. {
  1698. FF_ReadPartial( pxFile, ulItemLBA, ulRelBlockPos, 1, &ucReturnedChar, &xResult );
  1699. if( FF_isERR( xResult ) == pdFALSE )
  1700. {
  1701. xResult = ( int32_t ) ( ( uint32_t ) ucReturnedChar );
  1702. }
  1703. }
  1704. }
  1705. return ( int32_t ) xResult;
  1706. } /* FF_GetC() */
  1707. /*-----------------------------------------------------------*/
  1708. /**
  1709. * @public
  1710. * @brief Gets a Line from a Text File, but no more than ulLimit characters. The line will be NULL terminated.
  1711. *
  1712. * The behaviour of this function is undefined when called on a binary file.
  1713. * It should just read in ulLimit bytes of binary, and ZERO terminate the line.
  1714. *
  1715. * This function works for both UNIX line feeds, and Windows CRLF type files.
  1716. *
  1717. * @param pxFile The FF_FILE object pointer.
  1718. * @param szLine The character buffer where the line should be stored.
  1719. * @param ulLimit This should be the max number of characters that szLine can hold.
  1720. *
  1721. * @return The number of characters read from the line, on success.
  1722. * @return 0 when no more lines are available, or when ulLimit is 0.
  1723. * @return FF_ERR_NULL_POINTER if pxFile or szLine are NULL;
  1724. *
  1725. **/
  1726. int32_t FF_GetLine( FF_FILE * pxFile,
  1727. char * pcLine,
  1728. uint32_t ulLimit )
  1729. {
  1730. int32_t iChar = 0;
  1731. BaseType_t xIndex;
  1732. FF_Error_t xResult = FF_ERR_NONE;
  1733. if( ( pxFile == NULL ) || ( pcLine == NULL ) )
  1734. {
  1735. xResult = FF_ERR_NULL_POINTER | FF_GETLINE;
  1736. }
  1737. else
  1738. {
  1739. for( xIndex = 0; xIndex < ( BaseType_t ) ( ulLimit - 1 ); ++xIndex )
  1740. {
  1741. iChar = FF_GetC( pxFile );
  1742. if( FF_isERR( iChar ) == pdFALSE )
  1743. {
  1744. pcLine[ xIndex ] = ( char ) iChar;
  1745. if( iChar == '\n' )
  1746. {
  1747. /* Read until the first linefeed. Move xIndex forward so the
  1748. * null terminator does not overwrite the \n. xIndex must be less
  1749. * thank ( ulLimit - 1 ), so incrementing it here cannot make it
  1750. * greater than ulLimit - 1, so the NULL can be inserted without
  1751. * overflowing the buffer. */
  1752. xIndex++;
  1753. break;
  1754. }
  1755. }
  1756. else
  1757. {
  1758. if( ( FF_GETERROR( iChar ) == FF_ERR_FILE_READ_ZERO ) && ( xIndex > 0 ) )
  1759. {
  1760. /* Although FF_GetC() returns an End Of File,
  1761. * the last few characters will be returned first. */
  1762. iChar = xIndex;
  1763. }
  1764. break;
  1765. }
  1766. }
  1767. /* Make sure that the resulting string always ends with a zero: */
  1768. pcLine[ xIndex ] = '\0';
  1769. /*_RB_ In some paths this will be the second time FF_isERR() is called
  1770. * on the same value. */
  1771. if( FF_isERR( iChar ) == pdFALSE )
  1772. {
  1773. /* Return the number of bytes read. */
  1774. xResult = xIndex;
  1775. }
  1776. else
  1777. {
  1778. /* Return iChar as an error code (see FF_GetC()). */
  1779. xResult = iChar;
  1780. }
  1781. }
  1782. return xResult;
  1783. } /* FF_GetLine() */
  1784. /*-----------------------------------------------------------*/
  1785. static int32_t FF_WritePartial( FF_FILE * pxFile,
  1786. uint32_t ulItemLBA,
  1787. uint32_t ulRelBlockPos,
  1788. uint32_t ulCount,
  1789. const uint8_t * pucBuffer,
  1790. FF_Error_t * pxError )
  1791. {
  1792. FF_Error_t xError;
  1793. uint32_t ulBytesWritten;
  1794. #if ( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 )
  1795. {
  1796. BaseType_t xLastRead;
  1797. if( ( ulRelBlockPos + ulCount ) >= ( uint32_t ) pxFile->pxIOManager->usSectorSize )
  1798. {
  1799. /* After this read, ulFilePointer will point to the next block/sector. */
  1800. xLastRead = pdTRUE;
  1801. }
  1802. else
  1803. {
  1804. /* It is not the last read within this block/sector. */
  1805. xLastRead = pdFALSE;
  1806. }
  1807. if( ( ( pxFile->ucState & FF_BUFSTATE_VALID ) == 0 ) &&
  1808. ( ( ulRelBlockPos != 0 ) || ( pxFile->ulFilePointer < pxFile->ulFileSize ) ) )
  1809. {
  1810. xError = FF_BlockRead( pxFile->pxIOManager, ulItemLBA, 1, pxFile->pucBuffer, pdFALSE );
  1811. /* pxFile->ucState will be set later on. */
  1812. }
  1813. else
  1814. {
  1815. xError = FF_ERR_NONE;
  1816. /* the buffer is valid or a whole block/sector will be written, so it is
  1817. * not necessary to read the contents first. */
  1818. }
  1819. if( FF_isERR( xError ) == pdFALSE )
  1820. {
  1821. memcpy( pxFile->pucBuffer + ulRelBlockPos, pucBuffer, ulCount );
  1822. if( xLastRead == pdTRUE )
  1823. {
  1824. xError = FF_BlockWrite( pxFile->pxIOManager, ulItemLBA, 1, pxFile->pucBuffer, pdFALSE );
  1825. pxFile->ucState = FF_BUFSTATE_INVALID;
  1826. }
  1827. else
  1828. {
  1829. pxFile->ucState |= FF_BUFSTATE_WRITTEN | FF_BUFSTATE_VALID;
  1830. }
  1831. }
  1832. else
  1833. {
  1834. pxFile->ucState = FF_BUFSTATE_INVALID;
  1835. }
  1836. }
  1837. #else /* if ( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 ) */
  1838. {
  1839. FF_Buffer_t * pxBuffer;
  1840. if( ( ulRelBlockPos == 0 ) && ( pxFile->ulFilePointer >= pxFile->ulFileSize ) )
  1841. {
  1842. /* An entire sector will be written. */
  1843. pxBuffer = FF_GetBuffer( pxFile->pxIOManager, ulItemLBA, FF_MODE_WR_ONLY );
  1844. }
  1845. else
  1846. {
  1847. /* A partial write will be done, make sure to read the contents before
  1848. * changing anything. */
  1849. pxBuffer = FF_GetBuffer( pxFile->pxIOManager, ulItemLBA, FF_MODE_WRITE );
  1850. }
  1851. if( pxBuffer == NULL )
  1852. {
  1853. xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_WRITE );
  1854. }
  1855. else
  1856. {
  1857. /* Here we copy to the sector boundary. */
  1858. memcpy( ( pxBuffer->pucBuffer + ulRelBlockPos ), pucBuffer, ulCount );
  1859. xError = FF_ReleaseBuffer( pxFile->pxIOManager, pxBuffer );
  1860. }
  1861. }
  1862. #endif /* if ( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 ) */
  1863. if( FF_isERR( xError ) == pdFALSE )
  1864. {
  1865. pxFile->ulFilePointer += ulCount;
  1866. ulBytesWritten = ulCount;
  1867. if( pxFile->ulFilePointer > pxFile->ulFileSize )
  1868. {
  1869. pxFile->ulFileSize = pxFile->ulFilePointer;
  1870. }
  1871. }
  1872. else
  1873. {
  1874. ulBytesWritten = 0ul;
  1875. }
  1876. *pxError = xError;
  1877. return ulBytesWritten;
  1878. } /* FF_WritePartial() */
  1879. /*-----------------------------------------------------------*/
  1880. /**
  1881. * @public
  1882. * @brief Writes data to a File.
  1883. *
  1884. * @param pxFile FILE Pointer.
  1885. * @param ulElementSize Size of an Element of Data to be copied. (in bytes).
  1886. * @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.
  1887. * @param pucBuffer Byte-wise pucBuffer containing the data to be written.
  1888. *
  1889. * FF_Read() and FF_Write() work very similar. They both complete their task in 5 steps:
  1890. * 1. Write bytes up to a sector border: FF_WritePartial()
  1891. * 2. Write sectors up to cluster border: FF_BlockWrite()
  1892. * 3. Write complete clusters: FF_WriteClusters()
  1893. * 4. Write remaining sectors: FF_BlockWrite()
  1894. * 5. Write remaining bytes: FF_WritePartial()
  1895. * @return
  1896. **/
  1897. int32_t FF_Write( FF_FILE * pxFile,
  1898. uint32_t ulElementSize,
  1899. uint32_t ulCount,
  1900. uint8_t * pucBuffer )
  1901. {
  1902. uint32_t ulBytesLeft = ulElementSize * ulCount;
  1903. uint32_t nBytesWritten = 0;
  1904. uint32_t nBytesToWrite;
  1905. FF_IOManager_t * pxIOManager;
  1906. uint32_t ulRelBlockPos;
  1907. uint32_t ulItemLBA;
  1908. int32_t lResult;
  1909. uint32_t ulSectors;
  1910. uint32_t ulRelClusterPos;
  1911. uint32_t ulBytesPerCluster;
  1912. FF_Error_t xError;
  1913. if( pxFile == NULL )
  1914. {
  1915. xError = ( FF_Error_t ) ( FF_ERR_NULL_POINTER | FF_READ );
  1916. }
  1917. else
  1918. {
  1919. /* Check validity of the handle and the current position within the file. */
  1920. xError = FF_CheckValid( pxFile );
  1921. if( FF_isERR( xError ) == pdFALSE )
  1922. {
  1923. if( ( pxFile->ucMode & FF_MODE_WRITE ) == 0 )
  1924. {
  1925. xError = ( FF_Error_t ) ( FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE | FF_WRITE );
  1926. }
  1927. /* Make sure a write is after the append point. */
  1928. else if( ( pxFile->ucMode & FF_MODE_APPEND ) != 0 )
  1929. {
  1930. if( pxFile->ulFilePointer < pxFile->ulFileSize )
  1931. {
  1932. xError = FF_Seek( pxFile, 0, FF_SEEK_END );
  1933. }
  1934. }
  1935. }
  1936. }
  1937. if( FF_isERR( xError ) == pdFALSE )
  1938. {
  1939. pxIOManager = pxFile->pxIOManager;
  1940. /* Open a do{} while( 0 ) loop to allow the use of breaks */
  1941. do
  1942. {
  1943. /* Extend File for at least ulBytesLeft!
  1944. * Handle file-space allocation
  1945. + 1 byte because the code assumes there is always a next cluster */
  1946. xError = FF_ExtendFile( pxFile, pxFile->ulFilePointer + ulBytesLeft + 1 );
  1947. if( FF_isERR( xError ) )
  1948. {
  1949. /* On every error, break from the while( 0 ) loop. */
  1950. break;
  1951. }
  1952. ulRelBlockPos = FF_getMinorBlockEntry( pxIOManager, pxFile->ulFilePointer, 1 ); /* Get the position within a block. */
  1953. ulItemLBA = FF_SetCluster( pxFile, &xError );
  1954. if( FF_isERR( xError ) )
  1955. {
  1956. break;
  1957. }
  1958. if( ( ulRelBlockPos + ulBytesLeft ) <= ( uint32_t ) pxIOManager->usSectorSize )
  1959. {
  1960. /* Bytes to write are within a block and and do not go passed the current block. */
  1961. nBytesWritten = FF_WritePartial( pxFile, ulItemLBA, ulRelBlockPos, ulBytesLeft, pucBuffer, &xError );
  1962. break;
  1963. }
  1964. /*---------- Write (memcpy) to a Sector Boundary. */
  1965. if( ulRelBlockPos != 0 )
  1966. {
  1967. /* Not writing on a sector boundary, at this point the LBA is known. */
  1968. nBytesToWrite = pxIOManager->usSectorSize - ulRelBlockPos;
  1969. nBytesWritten = FF_WritePartial( pxFile, ulItemLBA, ulRelBlockPos, nBytesToWrite, pucBuffer, &xError );
  1970. if( FF_isERR( xError ) )
  1971. {
  1972. break;
  1973. }
  1974. ulBytesLeft -= nBytesWritten;
  1975. pucBuffer += nBytesWritten;
  1976. }
  1977. /*---------- Write sectors, up to a Cluster Boundary. */
  1978. ulBytesPerCluster = ( pxIOManager->xPartition.ulSectorsPerCluster * pxIOManager->usSectorSize );
  1979. ulRelClusterPos = FF_getClusterPosition( pxIOManager, pxFile->ulFilePointer, 1 );
  1980. if( ( ulRelClusterPos != 0 ) && ( ( ulRelClusterPos + ulBytesLeft ) >= ulBytesPerCluster ) )
  1981. {
  1982. /* Need to get to cluster boundary */
  1983. ulItemLBA = FF_SetCluster( pxFile, &xError );
  1984. if( FF_isERR( xError ) )
  1985. {
  1986. break;
  1987. }
  1988. ulSectors = pxIOManager->xPartition.ulSectorsPerCluster - ( ulRelClusterPos / pxIOManager->usSectorSize );
  1989. xError = FF_BlockWrite( pxIOManager, ulItemLBA, ulSectors, pucBuffer, pdFALSE );
  1990. if( FF_isERR( xError ) )
  1991. {
  1992. break;
  1993. }
  1994. nBytesToWrite = ulSectors * pxIOManager->usSectorSize;
  1995. ulBytesLeft -= nBytesToWrite;
  1996. pucBuffer += nBytesToWrite;
  1997. nBytesWritten += nBytesToWrite;
  1998. pxFile->ulFilePointer += nBytesToWrite;
  1999. if( pxFile->ulFilePointer > pxFile->ulFileSize )
  2000. {
  2001. pxFile->ulFileSize = pxFile->ulFilePointer;
  2002. }
  2003. }
  2004. /*---------- Write entire Clusters. */
  2005. if( ulBytesLeft >= ulBytesPerCluster )
  2006. {
  2007. uint32_t ulClusters;
  2008. FF_SetCluster( pxFile, &xError );
  2009. if( FF_isERR( xError ) )
  2010. {
  2011. break;
  2012. }
  2013. ulClusters = ( ulBytesLeft / ulBytesPerCluster );
  2014. xError = FF_WriteClusters( pxFile, ulClusters, pucBuffer );
  2015. if( FF_isERR( xError ) )
  2016. {
  2017. break;
  2018. }
  2019. nBytesToWrite = ulBytesPerCluster * ulClusters;
  2020. ulBytesLeft -= nBytesToWrite;
  2021. pucBuffer += nBytesToWrite;
  2022. nBytesWritten += nBytesToWrite;
  2023. pxFile->ulFilePointer += nBytesToWrite;
  2024. if( pxFile->ulFilePointer > pxFile->ulFileSize )
  2025. {
  2026. pxFile->ulFileSize = pxFile->ulFilePointer;
  2027. }
  2028. }
  2029. /*---------- Write Remaining Blocks */
  2030. while( ulBytesLeft >= ( uint32_t ) pxIOManager->usSectorSize )
  2031. {
  2032. ulSectors = ulBytesLeft / pxIOManager->usSectorSize;
  2033. {
  2034. /* HT: I'd leave these pPart/ulOffset for readability... */
  2035. FF_Partition_t * pPart = &( pxIOManager->xPartition );
  2036. uint32_t ulOffset = ( pxFile->ulFilePointer / pxIOManager->usSectorSize ) % pPart->ulSectorsPerCluster;
  2037. uint32_t ulRemain = pPart->ulSectorsPerCluster - ulOffset;
  2038. if( ulSectors > ulRemain )
  2039. {
  2040. ulSectors = ulRemain;
  2041. }
  2042. }
  2043. ulItemLBA = FF_SetCluster( pxFile, &xError );
  2044. if( FF_isERR( xError ) )
  2045. {
  2046. break;
  2047. }
  2048. xError = FF_BlockWrite( pxIOManager, ulItemLBA, ulSectors, pucBuffer, pdFALSE );
  2049. if( FF_isERR( xError ) )
  2050. {
  2051. break;
  2052. }
  2053. nBytesToWrite = ulSectors * pxIOManager->usSectorSize;
  2054. ulBytesLeft -= nBytesToWrite;
  2055. pucBuffer += nBytesToWrite;
  2056. nBytesWritten += nBytesToWrite;
  2057. pxFile->ulFilePointer += nBytesToWrite;
  2058. if( pxFile->ulFilePointer > pxFile->ulFileSize )
  2059. {
  2060. pxFile->ulFileSize = pxFile->ulFilePointer;
  2061. }
  2062. }
  2063. /*---------- Write (memcpy) Remaining Bytes */
  2064. if( ulBytesLeft == 0 )
  2065. {
  2066. break;
  2067. }
  2068. ulItemLBA = FF_SetCluster( pxFile, &xError );
  2069. if( FF_isERR( xError ) )
  2070. {
  2071. break;
  2072. }
  2073. FF_WritePartial( pxFile, ulItemLBA, 0, ulBytesLeft, pucBuffer, &xError );
  2074. nBytesWritten += ulBytesLeft;
  2075. }
  2076. while( pdFALSE );
  2077. }
  2078. if( FF_isERR( xError ) )
  2079. {
  2080. lResult = xError;
  2081. }
  2082. else
  2083. {
  2084. lResult = ( int32_t ) ( nBytesWritten / ulElementSize );
  2085. }
  2086. return lResult;
  2087. } /* FF_Write() */
  2088. /*-----------------------------------------------------------*/
  2089. /**
  2090. * @public
  2091. * @brief Writes a char to a FILE.
  2092. *
  2093. * @param pxFile FILE Pointer.
  2094. * @param ucValue Char to be placed in the file.
  2095. *
  2096. * @return Returns the value written to the file, or a value less than 0.
  2097. *
  2098. **/
  2099. int32_t FF_PutC( FF_FILE * pxFile,
  2100. uint8_t ucValue )
  2101. {
  2102. uint32_t ulItemLBA;
  2103. uint32_t ulRelBlockPos;
  2104. FF_Error_t xResult;
  2105. if( pxFile == NULL )
  2106. { /* Ensure we don't have a Null file pointer on a Public interface. */
  2107. xResult = FF_ERR_NULL_POINTER | FF_PUTC;
  2108. }
  2109. else if( ( pxFile->ucMode & FF_MODE_WRITE ) == 0 )
  2110. {
  2111. xResult = FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE | FF_PUTC;
  2112. }
  2113. else
  2114. {
  2115. xResult = FF_ERR_NONE;
  2116. do
  2117. {
  2118. /* Make sure a write is after the append point. */
  2119. if( ( pxFile->ucMode & FF_MODE_APPEND ) != 0 )
  2120. {
  2121. if( pxFile->ulFilePointer < pxFile->ulFileSize )
  2122. {
  2123. xResult = FF_Seek( pxFile, 0, FF_SEEK_END );
  2124. if( FF_isERR( xResult ) )
  2125. {
  2126. break;
  2127. }
  2128. }
  2129. }
  2130. ulRelBlockPos = FF_getMinorBlockEntry( pxFile->pxIOManager, pxFile->ulFilePointer, 1 );
  2131. /* Handle File Space Allocation. */
  2132. /* We'll write 1 byte and always have a next cluster reserved. */
  2133. xResult = FF_ExtendFile( pxFile, pxFile->ulFilePointer + 2 );
  2134. if( FF_isERR( xResult ) )
  2135. {
  2136. break;
  2137. }
  2138. ulItemLBA = FF_SetCluster( pxFile, &xResult );
  2139. if( FF_isERR( xResult ) )
  2140. {
  2141. break;
  2142. }
  2143. FF_WritePartial( pxFile, ulItemLBA, ulRelBlockPos, 1, &ucValue, &xResult );
  2144. if( FF_isERR( xResult ) == pdFALSE )
  2145. {
  2146. xResult = ( FF_Error_t ) ucValue;
  2147. }
  2148. } while( pdFALSE );
  2149. }
  2150. return xResult;
  2151. } /* FF_PutC() */
  2152. /*-----------------------------------------------------------*/
  2153. /**
  2154. * @public
  2155. * @brief Equivalent to fseek()
  2156. *
  2157. * @param pxFile FF_FILE object that was created by FF_Open().
  2158. * @param ulOffset An integer (+/-) to seek to, from the specified origin.
  2159. * @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).
  2160. *
  2161. * @return 0 on Sucess,
  2162. * @return -2 if offset results in an invalid position in the file.
  2163. * @return FF_ERR_NULL_POINTER if a FF_FILE pointer was not received.
  2164. * @return -3 if an invalid origin was provided.
  2165. *
  2166. **/
  2167. FF_Error_t FF_Seek( FF_FILE * pxFile,
  2168. int32_t lOffset,
  2169. BaseType_t xOrigin )
  2170. {
  2171. FF_Error_t xError;
  2172. uint32_t ulPosition = 0ul;
  2173. xError = FF_CheckValid( pxFile );
  2174. if( FF_isERR( xError ) == pdFALSE )
  2175. {
  2176. xError = FF_FlushCache( pxFile->pxIOManager );
  2177. #if ( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 )
  2178. {
  2179. if( FF_isERR( xError ) == pdFALSE )
  2180. {
  2181. /* Here we must ensure that if the user tries to seek, and we had data in the file's
  2182. * write buffer that this is written to disk. */
  2183. if( ( pxFile->ucState & FF_BUFSTATE_WRITTEN ) != 0 )
  2184. {
  2185. xError = FF_BlockWrite( pxFile->pxIOManager, FF_FileLBA( pxFile ), 1, pxFile->pucBuffer, pdFALSE );
  2186. }
  2187. pxFile->ucState = FF_BUFSTATE_INVALID;
  2188. }
  2189. }
  2190. #endif /* ffconfigOPTIMISE_UNALIGNED_ACCESS */
  2191. if( FF_isERR( xError ) == pdFALSE )
  2192. {
  2193. if( xOrigin == FF_SEEK_SET )
  2194. {
  2195. ulPosition = ( uint32_t ) lOffset;
  2196. }
  2197. else if( xOrigin == FF_SEEK_CUR )
  2198. {
  2199. if( lOffset >= ( int32_t ) 0 )
  2200. {
  2201. ulPosition = pxFile->ulFilePointer + ( ( uint32_t ) lOffset );
  2202. }
  2203. else
  2204. {
  2205. ulPosition = pxFile->ulFilePointer - ( ( uint32_t ) ( -lOffset ) );
  2206. }
  2207. }
  2208. else if( xOrigin == FF_SEEK_END )
  2209. {
  2210. /* 'FF_SEEK_END' only allows zero or negative values. */
  2211. if( lOffset <= ( int32_t ) 0 )
  2212. {
  2213. ulPosition = pxFile->ulFileSize - ( ( uint32_t ) ( -lOffset ) );
  2214. }
  2215. }
  2216. else
  2217. {
  2218. xError = ( FF_Error_t ) ( FF_SEEK | FF_ERR_FILE_SEEK_INVALID_ORIGIN );
  2219. /* To supress a compiler warning. */
  2220. ulPosition = ( uint32_t ) 0u;
  2221. }
  2222. if( FF_isERR( xError ) == pdFALSE )
  2223. {
  2224. if( ulPosition <= ( uint32_t ) pxFile->ulFileSize )
  2225. {
  2226. if( ulPosition != ( uint32_t ) pxFile->ulFilePointer )
  2227. {
  2228. pxFile->ulFilePointer = ulPosition;
  2229. FF_SetCluster( pxFile, &xError );
  2230. }
  2231. }
  2232. else
  2233. {
  2234. xError = ( FF_Error_t ) ( FF_SEEK | FF_ERR_FILE_SEEK_INVALID_POSITION );
  2235. }
  2236. }
  2237. }
  2238. }
  2239. return xError;
  2240. } /* FF_Seek() */
  2241. /*-----------------------------------------------------------*/
  2242. #if ( ffconfigREMOVABLE_MEDIA != 0 )
  2243. /**
  2244. * @public
  2245. * @brief Invalidate all file handles belonging to pxIOManager
  2246. *
  2247. * @param pIoMan FF_IOManager_t object that was created by FF_CreateIOManger().
  2248. *
  2249. * @return 0 if no handles were open
  2250. * @return >0 the amount of handles that were invalidated
  2251. * @return <0 probably an invalid FF_IOManager_t pointer
  2252. *
  2253. **/
  2254. int32_t FF_Invalidate( FF_IOManager_t * pxIOManager )
  2255. {
  2256. int32_t xResult;
  2257. FF_FILE * pxFileChain;
  2258. if( pxIOManager == NULL )
  2259. {
  2260. xResult = FF_ERR_NULL_POINTER | FF_INVALIDATE;
  2261. }
  2262. else
  2263. {
  2264. xResult = 0;
  2265. FF_PendSemaphore( pxIOManager->pvSemaphore );
  2266. {
  2267. pxIOManager->ucFlags |= FF_IOMAN_DEVICE_IS_EXTRACTED;
  2268. /* Semaphore is required, or linked list might change */
  2269. pxFileChain = ( FF_FILE * ) pxIOManager->FirstFile;
  2270. if( pxFileChain != NULL )
  2271. {
  2272. /* Count elements in FirstFile */
  2273. do
  2274. {
  2275. pxFileChain->ulValidFlags |= FF_VALID_FLAG_INVALID;
  2276. xResult++;
  2277. pxFileChain = pxFileChain->pxNext;
  2278. }
  2279. while( pxFileChain != NULL );
  2280. }
  2281. }
  2282. FF_ReleaseSemaphore( pxIOManager->pvSemaphore );
  2283. }
  2284. return xResult;
  2285. } /* FF_Invalidate() */
  2286. #endif /* ffconfigREMOVABLE_MEDIA */
  2287. /*-----------------------------------------------------------*/
  2288. /**
  2289. * @public
  2290. * @brief Check validity of file handle
  2291. *
  2292. * @param pxFile FF_FILE object that was created by FF_Open().
  2293. *
  2294. * @return 0 on sucess.
  2295. * @return FF_ERR_NULL_POINTER if a null pointer was provided.
  2296. * @return FF_ERR_FILE_BAD_HANDLE if handle is not recognized
  2297. * @return FF_ERR_FILE_MEDIA_REMOVED please call FF_Close
  2298. *
  2299. **/
  2300. FF_Error_t FF_CheckValid( FF_FILE * pxFile )
  2301. {
  2302. FF_FILE * pxFileChain;
  2303. FF_Error_t xError;
  2304. if( ( pxFile == NULL ) || ( pxFile->pxIOManager == NULL ) )
  2305. {
  2306. xError = ( FF_Error_t ) ( FF_ERR_NULL_POINTER | FF_CHECKVALID );
  2307. }
  2308. else
  2309. {
  2310. FF_PendSemaphore( pxFile->pxIOManager->pvSemaphore );
  2311. {
  2312. pxFileChain = ( FF_FILE * ) pxFile->pxIOManager->FirstFile;
  2313. xError = ( FF_Error_t ) ( FF_ERR_FILE_BAD_HANDLE | FF_CHECKVALID );
  2314. while( pxFileChain != NULL )
  2315. {
  2316. if( pxFileChain == pxFile )
  2317. {
  2318. #if ( ffconfigREMOVABLE_MEDIA != 0 )
  2319. if( ( pxFileChain->ulValidFlags & FF_VALID_FLAG_INVALID ) != 0 )
  2320. {
  2321. /* The medium has been removed while this file handle was open. */
  2322. xError = ( FF_Error_t ) ( FF_ERR_FILE_MEDIA_REMOVED | FF_CHECKVALID );
  2323. }
  2324. else
  2325. #endif
  2326. {
  2327. /* Found the handle, so it is a valid / existing handle. */
  2328. xError = FF_ERR_NONE;
  2329. }
  2330. break;
  2331. }
  2332. pxFileChain = pxFileChain->pxNext;
  2333. }
  2334. }
  2335. FF_ReleaseSemaphore( pxFile->pxIOManager->pvSemaphore );
  2336. }
  2337. return xError;
  2338. } /* FF_CheckValid() */
  2339. /*-----------------------------------------------------------*/
  2340. #if ( ffconfigTIME_SUPPORT != 0 )
  2341. /**
  2342. * @public
  2343. * @brief Set the time-stamp(s) of a file entry
  2344. *
  2345. * @param pxFile FF_FILE object that was created by FF_Open().
  2346. * @param pxTime FF_SystemTime_t the time stamp
  2347. * @param uxWhat UBaseType_t a combination of enum ETimeMask
  2348. *
  2349. * @return 0 or FF_Error_t
  2350. *
  2351. **/
  2352. FF_Error_t FF_SetFileTime( FF_FILE * pxFile,
  2353. FF_SystemTime_t * pxTime,
  2354. UBaseType_t uxWhat )
  2355. {
  2356. FF_DirEnt_t xOriginalEntry;
  2357. FF_Error_t xError;
  2358. xError = FF_CheckValid( pxFile );
  2359. if( FF_isERR( xError ) == pdFALSE )
  2360. {
  2361. if( pxFile->ulValidFlags & FF_VALID_FLAG_DELETED )
  2362. { /*if (pxFile->FileDeleted) */
  2363. xError = ( FF_Error_t ) ( FF_ERR_FILE_NOT_FOUND | FF_SETFILETIME );
  2364. }
  2365. else if( ( pxFile->ucMode & ( FF_MODE_WRITE | FF_MODE_APPEND ) ) == 0 )
  2366. {
  2367. xError = ( FF_Error_t ) ( FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE | FF_SETFILETIME );
  2368. }
  2369. else
  2370. {
  2371. /* Update the Dirent! */
  2372. xError = FF_GetEntry( pxFile->pxIOManager, pxFile->usDirEntry, pxFile->ulDirCluster, &xOriginalEntry );
  2373. if( FF_isERR( xError ) == pdFALSE )
  2374. {
  2375. if( uxWhat & ETimeCreate )
  2376. {
  2377. xOriginalEntry.xCreateTime = *pxTime; /*/< Date and Time Created. */
  2378. }
  2379. if( uxWhat & ETimeMod )
  2380. {
  2381. xOriginalEntry.xModifiedTime = *pxTime; /*/< Date and Time Modified. */
  2382. }
  2383. if( uxWhat & ETimeAccess )
  2384. {
  2385. xOriginalEntry.xAccessedTime = *pxTime; /*/< Date of Last Access. */
  2386. }
  2387. xError = FF_PutEntry( pxFile->pxIOManager, pxFile->usDirEntry, pxFile->ulDirCluster, &xOriginalEntry, NULL );
  2388. }
  2389. if( FF_isERR( xError ) == pdFALSE )
  2390. {
  2391. xError = FF_FlushCache( pxFile->pxIOManager ); /* Ensure all modfied blocks are flushed to disk! */
  2392. }
  2393. }
  2394. }
  2395. return xError;
  2396. } /* FF_SetFileTime() */
  2397. #endif /* ffconfigTIME_SUPPORT */
  2398. /*-----------------------------------------------------------*/
  2399. #if ( ffconfigTIME_SUPPORT != 0 )
  2400. /**
  2401. * @public
  2402. * @brief Set the time-stamp(s) of a file entry (by name)
  2403. *
  2404. * @param pxIOManager FF_IOManager_t device handle
  2405. * @param pcPath int8_t/FF_T_WCHAR name of the file
  2406. * @param pxTime FF_SystemTime_t the time stamp
  2407. * @param uxWhat UBaseType_t a combination of enum ETimeMask
  2408. *
  2409. * @return 0 or FF_Error_t
  2410. *
  2411. **/
  2412. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  2413. FF_Error_t FF_SetTime( FF_IOManager_t * pxIOManager,
  2414. const FF_T_WCHAR * pcPath,
  2415. FF_SystemTime_t * pxTime,
  2416. UBaseType_t uxWhat )
  2417. #else
  2418. FF_Error_t FF_SetTime( FF_IOManager_t * pxIOManager,
  2419. const char * pcPath,
  2420. FF_SystemTime_t * pxTime,
  2421. UBaseType_t uxWhat )
  2422. #endif /* ffconfigUNICODE_UTF16_SUPPORT */
  2423. {
  2424. FF_DirEnt_t xOriginalEntry;
  2425. FF_Error_t xError;
  2426. uint32_t ulFileCluster;
  2427. BaseType_t xIndex;
  2428. FF_FindParams_t xFindParams;
  2429. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  2430. FF_T_WCHAR pcFileName[ ffconfigMAX_FILENAME ];
  2431. #else
  2432. char pcFileName[ ffconfigMAX_FILENAME ];
  2433. #endif /* ffconfigUNICODE_UTF16_SUPPORT */
  2434. xIndex = ( BaseType_t ) STRLEN( pcPath );
  2435. memset( &xFindParams, '\0', sizeof( xFindParams ) );
  2436. while( xIndex != 0 )
  2437. {
  2438. if( ( pcPath[ xIndex ] == '\\' ) || ( pcPath[ xIndex ] == '/' ) )
  2439. {
  2440. break;
  2441. }
  2442. xIndex--;
  2443. }
  2444. STRNCPY( pcFileName, ( pcPath + xIndex + 1 ), ffconfigMAX_FILENAME );
  2445. if( xIndex == 0 )
  2446. {
  2447. xIndex = 1;
  2448. }
  2449. xFindParams.ulDirCluster = FF_FindDir( pxIOManager, pcPath, ( uint16_t ) xIndex, &xError );
  2450. if( FF_isERR( xError ) == pdFALSE )
  2451. {
  2452. if( xFindParams.ulDirCluster == 0 )
  2453. {
  2454. xError = ( FF_Error_t ) ( FF_ERR_FILE_NOT_FOUND | FF_SETTIME );
  2455. }
  2456. else
  2457. {
  2458. ulFileCluster = FF_FindEntryInDir( pxIOManager, &xFindParams, pcFileName, 0, &xOriginalEntry, &xError );
  2459. if( ( FF_isERR( xError ) == pdFALSE ) || ( FF_GETERROR( xError ) == FF_ERR_DIR_END_OF_DIR ) )
  2460. {
  2461. if( ulFileCluster == 0ul )
  2462. {
  2463. /*FF_PRINTF ("FF_SetTime: Can not find '%s'\n", pcFileName); */
  2464. xError = ( FF_Error_t ) ( FF_ERR_FILE_NOT_FOUND | FF_SETTIME );
  2465. }
  2466. }
  2467. }
  2468. }
  2469. if( FF_isERR( xError ) == pdFALSE )
  2470. {
  2471. /* Update the Dirent! */
  2472. if( uxWhat & ETimeCreate )
  2473. {
  2474. xOriginalEntry.xCreateTime = *pxTime; /*/< Date and Time Created. */
  2475. }
  2476. if( uxWhat & ETimeMod )
  2477. {
  2478. xOriginalEntry.xModifiedTime = *pxTime; /*/< Date and Time Modified. */
  2479. }
  2480. if( uxWhat & ETimeAccess )
  2481. {
  2482. xOriginalEntry.xAccessedTime = *pxTime; /*/< Date of Last Access. */
  2483. }
  2484. xError = FF_PutEntry( pxIOManager, xOriginalEntry.usCurrentItem - 1, xFindParams.ulDirCluster, &xOriginalEntry, NULL );
  2485. if( FF_isERR( xError ) == pdFALSE )
  2486. {
  2487. xError = FF_FlushCache( pxIOManager ); /* Ensure all modified blocks are flushed to disk! */
  2488. }
  2489. }
  2490. return xError;
  2491. } /* FF_SetTime() */
  2492. #endif /* ffconfigTIME_SUPPORT */
  2493. /*-----------------------------------------------------------*/
  2494. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  2495. FF_Error_t FF_SetPerm( FF_IOManager_t * pxIOManager,
  2496. const FF_T_WCHAR * pcPath,
  2497. UBaseType_t aPerm )
  2498. #else
  2499. FF_Error_t FF_SetPerm( FF_IOManager_t * pxIOManager,
  2500. const char * pcPath,
  2501. UBaseType_t aPerm )
  2502. #endif
  2503. {
  2504. FF_DirEnt_t xOriginalEntry;
  2505. FF_Error_t xError;
  2506. uint32_t ulFileCluster;
  2507. BaseType_t xIndex;
  2508. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  2509. FF_T_WCHAR pcFileName[ ffconfigMAX_FILENAME ];
  2510. #else
  2511. char pcFileName[ ffconfigMAX_FILENAME ];
  2512. #endif
  2513. FF_FindParams_t xFindParams;
  2514. xIndex = ( BaseType_t ) STRLEN( pcPath );
  2515. memset( &xFindParams, '\0', sizeof( xFindParams ) );
  2516. while( xIndex != 0 )
  2517. {
  2518. if( ( pcPath[ xIndex ] == '\\' ) || ( pcPath[ xIndex ] == '/' ) )
  2519. {
  2520. break;
  2521. }
  2522. xIndex--;
  2523. }
  2524. STRNCPY( pcFileName, ( pcPath + xIndex + 1 ), ffconfigMAX_FILENAME );
  2525. if( xIndex == 0 )
  2526. {
  2527. xIndex = 1;
  2528. }
  2529. /* Open a do {} while( pdFALSE ) loop to allow the use of break statements. */
  2530. do
  2531. {
  2532. xFindParams.ulDirCluster = FF_FindDir( pxIOManager, pcPath, ( uint16_t ) xIndex, &xError );
  2533. if( xError )
  2534. {
  2535. break;
  2536. }
  2537. if( !xFindParams.ulDirCluster )
  2538. {
  2539. xError = ( FF_Error_t ) ( FF_ERR_FILE_NOT_FOUND | FF_SETTIME );
  2540. break;
  2541. }
  2542. ulFileCluster = FF_FindEntryInDir( pxIOManager, &xFindParams, pcFileName, 0, &xOriginalEntry, &xError );
  2543. if( FF_isERR( xError ) )
  2544. {
  2545. break;
  2546. }
  2547. if( ulFileCluster == 0ul )
  2548. {
  2549. /*FF_PRINTF ("FF_SetTime: Can not find '%s'\n", pcFileName); */
  2550. xError = ( FF_Error_t ) ( FF_ERR_FILE_NOT_FOUND | FF_SETTIME );
  2551. break;
  2552. }
  2553. /* #define FF_FAT_ATTR_READONLY 0x01 */
  2554. /* #define FF_FAT_ATTR_HIDDEN 0x02 */
  2555. /* #define FF_FAT_ATTR_SYSTEM 0x04 */
  2556. /* #define FF_FAT_ATTR_VOLID 0x08 */
  2557. /* #define FF_FAT_ATTR_DIR 0x10 */
  2558. /* #define FF_FAT_ATTR_ARCHIVE 0x20 */
  2559. /* #define FF_FAT_ATTR_LFN 0x0F */
  2560. #define FF_FAT_ATTR_USER ( ( uint8_t ) FF_FAT_ATTR_READONLY | FF_FAT_ATTR_HIDDEN | FF_FAT_ATTR_SYSTEM | FF_FAT_ATTR_ARCHIVE )
  2561. /* Update the Dirent! */
  2562. xOriginalEntry.ucAttrib &= ~FF_FAT_ATTR_USER;
  2563. xOriginalEntry.ucAttrib |= ( aPerm & FF_FAT_ATTR_USER );
  2564. xError = FF_PutEntry( pxIOManager, xOriginalEntry.usCurrentItem - 1, xFindParams.ulDirCluster, &xOriginalEntry, NULL );
  2565. if( FF_isERR( xError ) == pdFALSE )
  2566. {
  2567. xError = FF_FlushCache( pxIOManager ); /* Ensure all modfied blocks are flushed to disk! */
  2568. }
  2569. }
  2570. while( pdFALSE );
  2571. return xError;
  2572. } /* FF_SetPerm() */
  2573. /*-----------------------------------------------------------*/
  2574. /**
  2575. * @public
  2576. * @brief Equivalent to fclose()
  2577. *
  2578. * @param pxFile FF_FILE object that was created by FF_Open().
  2579. *
  2580. * @return 0 on sucess.
  2581. * @return -1 if a null pointer was provided.
  2582. *
  2583. **/
  2584. FF_Error_t FF_Close( FF_FILE * pxFile )
  2585. {
  2586. FF_FILE * pxFileChain;
  2587. FF_DirEnt_t xOriginalEntry;
  2588. FF_Error_t xError;
  2589. /* Opening a do {} while( 0 ) loop to allow the use of the break statement. */
  2590. do
  2591. {
  2592. if( pxFile == NULL )
  2593. {
  2594. xError = ( FF_Error_t ) ( FF_ERR_NULL_POINTER | FF_CLOSE );
  2595. break;
  2596. }
  2597. /* It is important to check that user doesn't supply invalid
  2598. * handle or a handle invalid because of "media removed" */
  2599. xError = FF_CheckValid( pxFile );
  2600. #if ( ffconfigREMOVABLE_MEDIA != 0 )
  2601. {
  2602. if( FF_GETERROR( xError ) == FF_ERR_FILE_MEDIA_REMOVED )
  2603. {
  2604. FF_PendSemaphore( pxFile->pxIOManager->pvSemaphore );
  2605. {
  2606. pxFileChain = ( FF_FILE * ) pxFile->pxIOManager->FirstFile;
  2607. if( pxFileChain == pxFile )
  2608. {
  2609. pxFile->pxIOManager->FirstFile = pxFile->pxNext;
  2610. }
  2611. else
  2612. {
  2613. while( pxFileChain )
  2614. {
  2615. if( pxFileChain->pxNext == pxFile )
  2616. {
  2617. pxFileChain->pxNext = pxFile->pxNext;
  2618. break;
  2619. }
  2620. pxFileChain = pxFileChain->pxNext; /* Forgot this one */
  2621. }
  2622. }
  2623. } /* Semaphore released, linked list was shortened! */
  2624. FF_ReleaseSemaphore( pxFile->pxIOManager->pvSemaphore );
  2625. #if ( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 )
  2626. {
  2627. ffconfigFREE( pxFile->pucBuffer );
  2628. }
  2629. #endif /* ffconfigOPTIMISE_UNALIGNED_ACCESS */
  2630. ffconfigFREE( pxFile ); /* So at least we have freed the pointer. */
  2631. xError = FF_ERR_NONE;
  2632. break;
  2633. }
  2634. }
  2635. #endif /* ffconfigREMOVABLE_MEDIA */
  2636. if( FF_isERR( xError ) )
  2637. {
  2638. /* FF_ERR_FILE_BAD_HANDLE or FF_ERR_NULL_POINTER */
  2639. break;
  2640. }
  2641. /* So here we have a normal valid file handle. */
  2642. /* Sometimes FreeRTOS+FAT will leave a trailing cluster on the end of a cluster chain.
  2643. * To ensure we're compliant we shall now check for this condition and truncate it. */
  2644. if( ( ( pxFile->ulValidFlags & FF_VALID_FLAG_DELETED ) == 0 ) &&
  2645. ( ( pxFile->ucMode & ( FF_MODE_WRITE | FF_MODE_APPEND | FF_MODE_CREATE ) ) != 0 ) )
  2646. {
  2647. uint32_t ulClusterSize;
  2648. /* File is not deleted and it was opened for writing or updating */
  2649. ulClusterSize = pxFile->pxIOManager->xPartition.usBlkSize * pxFile->pxIOManager->xPartition.ulSectorsPerCluster;
  2650. if( ( ( pxFile->ulFileSize % ulClusterSize ) == 0 ) && ( pxFile->ulObjectCluster != 0ul ) )
  2651. {
  2652. /* The file's length is a multiple of cluster size. This means
  2653. * that an extra cluster has been reserved, which wasn't necessary. */
  2654. xError = FF_Truncate( pxFile, pdTRUE );
  2655. }
  2656. /* Get the directory entry and update it to show the new file size */
  2657. if( FF_isERR( xError ) == pdFALSE )
  2658. {
  2659. xError = FF_GetEntry( pxFile->pxIOManager, pxFile->usDirEntry, pxFile->ulDirCluster, &xOriginalEntry );
  2660. /* Now update the directory entry */
  2661. if( ( FF_isERR( xError ) == pdFALSE ) &&
  2662. ( ( pxFile->ulFileSize != xOriginalEntry.ulFileSize ) || ( pxFile->ulFileSize == 0UL ) ) )
  2663. {
  2664. if( pxFile->ulFileSize == 0UL )
  2665. {
  2666. xOriginalEntry.ulObjectCluster = 0;
  2667. }
  2668. xOriginalEntry.ulFileSize = pxFile->ulFileSize;
  2669. xError = FF_PutEntry( pxFile->pxIOManager, pxFile->usDirEntry, pxFile->ulDirCluster, &xOriginalEntry, NULL );
  2670. }
  2671. }
  2672. }
  2673. /* Handle Linked list! */
  2674. FF_PendSemaphore( pxFile->pxIOManager->pvSemaphore );
  2675. { /* Semaphore is required, or linked list could become corrupted. */
  2676. pxFileChain = ( FF_FILE * ) pxFile->pxIOManager->FirstFile;
  2677. if( pxFileChain == pxFile )
  2678. {
  2679. pxFile->pxIOManager->FirstFile = pxFile->pxNext;
  2680. }
  2681. else
  2682. {
  2683. while( pxFileChain )
  2684. {
  2685. if( pxFileChain->pxNext == pxFile )
  2686. {
  2687. /* Found it, remove it from the list. */
  2688. pxFileChain->pxNext = pxFile->pxNext;
  2689. break;
  2690. }
  2691. pxFileChain = pxFileChain->pxNext;
  2692. }
  2693. }
  2694. } /* Semaphore released, linked list was shortened! */
  2695. FF_ReleaseSemaphore( pxFile->pxIOManager->pvSemaphore );
  2696. #if ( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 )
  2697. {
  2698. if( pxFile->pucBuffer != NULL )
  2699. {
  2700. /* Ensure any unaligned points are pushed to the disk! */
  2701. if( pxFile->ucState & FF_BUFSTATE_WRITTEN )
  2702. {
  2703. FF_Error_t xTempError;
  2704. xTempError = FF_BlockWrite( pxFile->pxIOManager, FF_FileLBA( pxFile ), 1, pxFile->pucBuffer, pdFALSE );
  2705. if( FF_isERR( xError ) == pdFALSE )
  2706. {
  2707. xError = xTempError;
  2708. }
  2709. }
  2710. ffconfigFREE( pxFile->pucBuffer );
  2711. }
  2712. }
  2713. #endif /* if ( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 ) */
  2714. if( FF_isERR( xError ) == pdFALSE )
  2715. {
  2716. xError = FF_FlushCache( pxFile->pxIOManager ); /* Ensure all modified blocks are flushed to disk! */
  2717. }
  2718. ffconfigFREE( pxFile );
  2719. }
  2720. while( pdFALSE );
  2721. return xError;
  2722. } /* FF_Close() */
  2723. /*-----------------------------------------------------------*/
  2724. /**
  2725. * @public
  2726. * @brief Make Filesize equal to the FilePointer and truncates the file to this position
  2727. *
  2728. * @param pxFile FF_FILE object that was created by FF_Open().
  2729. *
  2730. * @return 0 on sucess.
  2731. * @return negative if some error occurred
  2732. *
  2733. **/
  2734. FF_Error_t FF_SetEof( FF_FILE * pxFile )
  2735. {
  2736. FF_Error_t xError;
  2737. /* Check if the file was not deleted and if it was opened with write permissions: */
  2738. if( ( ( pxFile->ulValidFlags & FF_VALID_FLAG_DELETED ) == 0 ) &&
  2739. ( ( pxFile->ucMode & ( FF_MODE_WRITE | FF_MODE_APPEND | FF_MODE_CREATE ) ) != 0 ) )
  2740. {
  2741. pxFile->ulFileSize = pxFile->ulFilePointer;
  2742. if( pxFile->ulObjectCluster != 0ul )
  2743. {
  2744. xError = FF_Truncate( pxFile, pdFALSE );
  2745. }
  2746. else
  2747. {
  2748. xError = FF_ERR_NONE;
  2749. }
  2750. }
  2751. else
  2752. {
  2753. xError = ( FF_Error_t ) ( FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE | FF_SETEOF );
  2754. }
  2755. return xError;
  2756. } /* FF_SetEof() */
  2757. /*-----------------------------------------------------------*/
  2758. /**
  2759. * @public
  2760. * @brief Truncate a file to 'pxFile->ulFileSize'
  2761. *
  2762. * @param pxFile FF_FILE object that was created by FF_Open().
  2763. *
  2764. * @return 0 on sucess.
  2765. * @return negative if some error occurred
  2766. *
  2767. **/
  2768. static FF_Error_t FF_Truncate( FF_FILE * pxFile,
  2769. BaseType_t bClosing )
  2770. {
  2771. FF_Error_t xError;
  2772. FF_IOManager_t * pxIOManager = pxFile->pxIOManager;
  2773. uint32_t ulClusterSize;
  2774. uint32_t ulClusterCount;
  2775. uint32_t ulClustersNeeded;
  2776. /* The number of bytes contained in a cluster. */
  2777. ulClusterSize = pxIOManager->xPartition.usBlkSize * pxIOManager->xPartition.ulSectorsPerCluster;
  2778. /* See how many clusters have been allocated. */
  2779. ulClusterCount = FF_GetChainLength( pxIOManager, pxFile->ulObjectCluster, NULL, &xError );
  2780. /* Calculate the actual number of clusters needed, rounding up */
  2781. ulClustersNeeded = ( pxFile->ulFileSize + ulClusterSize - 1 ) / ulClusterSize;
  2782. if( bClosing != pdFALSE )
  2783. {
  2784. /* The handle will be closed after truncating. This function is called
  2785. * because Filesize is an exact multiple of ulClusterSize. */
  2786. ulClustersNeeded = pxFile->ulFileSize / ulClusterSize;
  2787. }
  2788. else
  2789. {
  2790. /* This function is called to make the file size equal to the current
  2791. * position within the file. Always keep an extra cluster to write to. */
  2792. ulClustersNeeded = ( pxFile->ulFileSize + ulClusterSize ) / ulClusterSize;
  2793. }
  2794. /* First change the FAT chain. */
  2795. if( ( FF_isERR( xError ) == pdFALSE ) && ( ulClusterCount > ulClustersNeeded ) )
  2796. {
  2797. if( ulClustersNeeded == 0ul )
  2798. {
  2799. FF_LockFAT( pxIOManager );
  2800. {
  2801. /* In FF_Truncate() */
  2802. xError = FF_UnlinkClusterChain( pxIOManager, pxFile->ulObjectCluster, 0 );
  2803. }
  2804. FF_UnlockFAT( pxIOManager );
  2805. if( FF_isERR( xError ) == pdFALSE )
  2806. {
  2807. FF_DirEnt_t xOriginalEntry;
  2808. /* The directory denotes the address of the first data cluster of every file.
  2809. * Now change it to 'ulAddrCurrentCluster': */
  2810. xError = FF_GetEntry( pxIOManager, pxFile->usDirEntry, pxFile->ulDirCluster, &xOriginalEntry );
  2811. if( FF_isERR( xError ) == pdFALSE )
  2812. {
  2813. xOriginalEntry.ulObjectCluster = 0ul;
  2814. xError = FF_PutEntry( pxIOManager, pxFile->usDirEntry, pxFile->ulDirCluster, &xOriginalEntry, NULL );
  2815. if( FF_isERR( xError ) == pdFALSE )
  2816. {
  2817. pxFile->ulObjectCluster = 0ul;
  2818. pxFile->ulChainLength = 0ul;
  2819. pxFile->ulCurrentCluster = 0ul;
  2820. pxFile->ulEndOfChain = 0ul;
  2821. }
  2822. }
  2823. }
  2824. }
  2825. else
  2826. {
  2827. FF_LockFAT( pxIOManager );
  2828. {
  2829. uint32_t ulTruncateCluster = FF_TraverseFAT( pxIOManager, pxFile->ulObjectCluster, ulClustersNeeded - 1, &xError );
  2830. if( FF_isERR( xError ) == pdFALSE )
  2831. {
  2832. xError = FF_UnlinkClusterChain( pxIOManager, ulTruncateCluster, 1 );
  2833. }
  2834. }
  2835. FF_UnlockFAT( pxIOManager );
  2836. }
  2837. }
  2838. return xError;
  2839. } /* FF_Truncate() */
  2840. /*-----------------------------------------------------------*/