ff_dir.c 135 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731
  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_dir.c
  28. * @ingroup DIR
  29. *
  30. * @defgroup DIR Handles Directory Traversal
  31. * @brief Handles DIR access and traversal.
  32. *
  33. * Provides FindFirst() and FindNext() Interfaces
  34. **/
  35. #include "ff_headers.h"
  36. #include <stdio.h>
  37. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  38. #include <wchar.h>
  39. #endif
  40. #if defined( WIN32 )
  41. #define wcsicmp _wcsicmp
  42. #else
  43. #define wcsicmp wcscasecmp
  44. #include <ctype.h>
  45. #endif
  46. /* Calculate a simple LFN checmsum. */
  47. static uint8_t FF_CreateChkSum( const uint8_t * pa_pShortName );
  48. static BaseType_t FF_ShortNameExists( FF_IOManager_t * pxIOManager,
  49. uint32_t ulDirCluster,
  50. char * pcShortName,
  51. FF_Error_t * pxError );
  52. #if ( ffconfigSHORTNAME_CASE != 0 )
  53. /* For short-name entries, NT/XP etc store case information in byte 0x0c
  54. * Use this to show proper case of "README.txt" or "source.H".
  55. */
  56. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  57. static void FF_CaseShortName( FF_T_WCHAR * pcName,
  58. uint8_t attrib );
  59. #else
  60. static void FF_CaseShortName( char * pcName,
  61. uint8_t attrib );
  62. #endif
  63. #endif /* ffconfigSHORTNAME_CASE */
  64. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  65. /* For unicode, the short name can be expanded to wchar
  66. * by inserting zero's.
  67. */
  68. static void FF_ShortNameExpand( FF_T_WCHAR * );
  69. #endif
  70. /*
  71. * Transform a name as stored on disk "README__TXT"
  72. * to a nul-terminated string: "README.TXT", "FILE001".
  73. * A dot is only added if an extension is present.
  74. */
  75. static void FF_ProcessShortName( char * pcName );
  76. #if ( ffconfigTIME_SUPPORT != 0 )
  77. static void FF_PlaceTime( uint8_t * pucEntryBuffer,
  78. uint32_t Offset,
  79. FF_SystemTime_t * pxTime );
  80. static void FF_PlaceDate( uint8_t * pucEntryBuffer,
  81. uint32_t Offset,
  82. FF_SystemTime_t * pxTime );
  83. static void FF_GetTime( FF_SystemTime_t * pxTime,
  84. const uint8_t * pucEntryBuffer,
  85. uint32_t ulOffset );
  86. static void FF_GetDate( FF_SystemTime_t * pxTime,
  87. const uint8_t * pucEntryBuffer,
  88. uint32_t ulOffset );
  89. #endif /* ffconfigTIME_SUPPORT */
  90. static FF_Error_t FF_Traverse( FF_IOManager_t * pxIOManager,
  91. uint32_t ulEntry,
  92. FF_FetchContext_t * pxContext );
  93. static int32_t FF_FindFreeDirent( FF_IOManager_t * pxIOManager,
  94. FF_FindParams_t * pxFindParams,
  95. uint16_t usSequential );
  96. #if ( ffconfigLFN_SUPPORT != 0 )
  97. static int8_t FF_CreateLFNEntry( uint8_t * pucEntryBuffer,
  98. uint8_t * pcName,
  99. UBaseType_t uxNameLength,
  100. UBaseType_t uxLFN,
  101. uint8_t ucCheckSum );
  102. #endif /* ffconfigLFN_SUPPORT */
  103. static BaseType_t FF_ValidShortChar( char cChar );
  104. #if ( ffconfigLFN_SUPPORT != 0 )
  105. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  106. static FF_Error_t FF_CreateLFNs( FF_IOManager_t * pxIOManager,
  107. uint32_t ulDirCluster,
  108. FF_T_WCHAR * pcName,
  109. uint8_t ucCheckSum,
  110. uint16_t usEntry );
  111. #else
  112. static FF_Error_t FF_CreateLFNs( FF_IOManager_t * pxIOManager,
  113. uint32_t ulDirCluster,
  114. char * pcName,
  115. uint8_t ucCheckSum,
  116. uint16_t usEntry );
  117. #endif /* if ( ffconfigUNICODE_UTF16_SUPPORT != 0 ) */
  118. #endif /* if ( ffconfigLFN_SUPPORT != 0 ) */
  119. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  120. static void FF_MakeNameCompliant( FF_T_WCHAR * pcName );
  121. #else
  122. static void FF_MakeNameCompliant( char * pcName );
  123. #endif
  124. #if ( FF_NOSTRCASECMP == 0 )
  125. static portINLINE unsigned char prvToLower( unsigned char c )
  126. {
  127. unsigned char cReturnChar;
  128. if( ( c >= 'A' ) && ( c <= 'Z' ) )
  129. {
  130. cReturnChar = c + 0x20;
  131. }
  132. else
  133. {
  134. cReturnChar = c;
  135. }
  136. return cReturnChar;
  137. }
  138. int strcasecmp( const char * pcString1,
  139. const char * pcString2 )
  140. {
  141. unsigned char c1, c2;
  142. do
  143. {
  144. c1 = *pcString1++;
  145. c2 = *pcString2++;
  146. c1 = ( unsigned char ) prvToLower( ( unsigned char ) c1 );
  147. c2 = ( unsigned char ) prvToLower( ( unsigned char ) c2 );
  148. }
  149. while( ( c1 == c2 ) && ( c1 != '\0' ) );
  150. return ( int ) c1 - c2;
  151. } /* strcasecmp() */
  152. #endif /* if ( FF_NOSTRCASECMP == 0 ) */
  153. /*-----------------------------------------------------------*/
  154. static uint8_t FF_CreateChkSum( const uint8_t * pa_pShortName )
  155. {
  156. uint8_t cNameLen;
  157. uint8_t ChkSum = 0;
  158. for( cNameLen = 11; cNameLen != 0; cNameLen-- )
  159. {
  160. ChkSum = ( uint8_t )
  161. ( ( ( ChkSum & 1 ) ? 0x80 : 0 ) + ( ChkSum >> 1 ) + *( pa_pShortName++ ) );
  162. }
  163. return ChkSum;
  164. } /* FF_CreateChkSum() */
  165. /*-----------------------------------------------------------*/
  166. /* _HT_ Does not need a wchar version because a short name is treated a normal string of bytes */
  167. static BaseType_t FF_ShortNameExists( FF_IOManager_t * pxIOManager,
  168. uint32_t ulDirCluster,
  169. char * pcShortName,
  170. FF_Error_t * pxError )
  171. {
  172. BaseType_t xIndex;
  173. const uint8_t * pucEntryBuffer = NULL; /* initialisation not necessary, just for the compiler */
  174. uint8_t ucAttrib;
  175. FF_FetchContext_t xFetchContext;
  176. char pcMyShortName[ FF_SIZEOF_DIRECTORY_ENTRY ];
  177. BaseType_t xResult = -1;
  178. #if ( ffconfigHASH_CACHE != 0 )
  179. uint32_t ulHash;
  180. #endif
  181. *pxError = FF_ERR_NONE;
  182. #if ( ffconfigHASH_CACHE != 0 )
  183. {
  184. if( !FF_DirHashed( pxIOManager, ulDirCluster ) )
  185. {
  186. /* Hash the directory. */
  187. FF_HashDir( pxIOManager, ulDirCluster );
  188. }
  189. #if ffconfigHASH_FUNCTION == CRC16
  190. {
  191. ulHash = ( uint32_t ) FF_GetCRC16( ( uint8_t * ) pcShortName, strlen( pcShortName ) );
  192. }
  193. #else /* ffconfigHASH_FUNCTION == CRC8 */
  194. {
  195. ulHash = ( uint32_t ) FF_GetCRC8( ( uint8_t * ) pcShortName, strlen( pcShortName ) );
  196. }
  197. #endif
  198. {
  199. /* FF_CheckDirentHash result: 0 not found, 1 found, -1 directory not hashed */
  200. xResult = FF_CheckDirentHash( pxIOManager, ulDirCluster, ulHash );
  201. }
  202. }
  203. #endif /* if ( ffconfigHASH_CACHE != 0 ) */
  204. if( xResult < 0 )
  205. {
  206. xResult = pdFALSE;
  207. *pxError = FF_InitEntryFetch( pxIOManager, ulDirCluster, &xFetchContext );
  208. if( FF_isERR( *pxError ) == pdFALSE )
  209. {
  210. for( xIndex = 0; xIndex < FF_MAX_ENTRIES_PER_DIRECTORY; xIndex++ )
  211. {
  212. /* Call FF_FetchEntryWithContext only once for every block (usually 512 bytes) */
  213. if( ( xIndex == 0 ) ||
  214. ( pucEntryBuffer >= xFetchContext.pxBuffer->pucBuffer + ( pxIOManager->usSectorSize - FF_SIZEOF_DIRECTORY_ENTRY ) ) )
  215. {
  216. *pxError = FF_FetchEntryWithContext( pxIOManager, ( uint32_t ) xIndex, &xFetchContext, NULL );
  217. if( FF_isERR( *pxError ) )
  218. {
  219. break;
  220. }
  221. pucEntryBuffer = xFetchContext.pxBuffer->pucBuffer;
  222. }
  223. else
  224. {
  225. /* Advance 32 bytes to get the next directory entry. */
  226. pucEntryBuffer += FF_SIZEOF_DIRECTORY_ENTRY;
  227. }
  228. if( FF_isEndOfDir( pucEntryBuffer ) )
  229. {
  230. break;
  231. }
  232. if( FF_isDeleted( pucEntryBuffer ) == pdFALSE )
  233. {
  234. ucAttrib = FF_getChar( pucEntryBuffer, FF_FAT_DIRENT_ATTRIB );
  235. if( ( ucAttrib & FF_FAT_ATTR_LFN ) != FF_FAT_ATTR_LFN )
  236. {
  237. memcpy( pcMyShortName, pucEntryBuffer, sizeof( pcMyShortName ) );
  238. FF_ProcessShortName( pcMyShortName );
  239. if( strcmp( ( const char * ) pcShortName, ( const char * ) pcMyShortName ) == 0 )
  240. {
  241. xResult = pdTRUE;
  242. break;
  243. }
  244. }
  245. }
  246. } /* for ( xIndex = 0; xIndex < FF_MAX_ENTRIES_PER_DIRECTORY; xIndex++ ) */
  247. }
  248. *pxError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext );
  249. }
  250. return xResult;
  251. } /* FF_ShortNameExists() */
  252. /*-----------------------------------------------------------*/
  253. /* _HT_ When adding many files to a single directory, FF_FindEntryInDir was sometimes */
  254. /* _HT_ called 3 times before inserting a single file. With these changes it is called one time only */
  255. /* _HT_ pxFindParams caches some information: */
  256. /* _HT_ 1: the first free entry 2: whether the short-name version already exists */
  257. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  258. uint32_t FF_FindEntryInDir( FF_IOManager_t * pxIOManager,
  259. FF_FindParams_t * pxFindParams,
  260. const FF_T_WCHAR * pcName,
  261. uint8_t pa_Attrib,
  262. FF_DirEnt_t * pxDirEntry,
  263. FF_Error_t * pxError )
  264. #else
  265. uint32_t FF_FindEntryInDir( FF_IOManager_t * pxIOManager,
  266. FF_FindParams_t * pxFindParams,
  267. const char * pcName,
  268. uint8_t pa_Attrib,
  269. FF_DirEnt_t * pxDirEntry,
  270. FF_Error_t * pxError )
  271. #endif /* if ( ffconfigUNICODE_UTF16_SUPPORT != 0 ) */
  272. {
  273. FF_FetchContext_t xFetchContext;
  274. /* const pointer to read from pBuffer */
  275. const uint8_t * src = NULL;
  276. /* As we're walking through a directory, we might as well
  277. * find the first free entry to help FF_FindFreeDirent( )
  278. * The result will be stored in 'pxFindParams->lFreeEntry' */
  279. BaseType_t entriesNeeded;
  280. BaseType_t freeCount = 0;
  281. FF_Error_t xError;
  282. /* If the file name fits into a short file name
  283. * then the existence of that short file name will be checked as well. */
  284. BaseType_t testShortname;
  285. uint32_t xResult = 0ul;
  286. #if ( ffconfigUNICODE_UTF8_SUPPORT == 1 )
  287. int32_t utf8Error;
  288. #endif
  289. #if ( ffconfigLFN_SUPPORT != 0 )
  290. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  291. FF_T_WCHAR * pcCurPtr; /* Pointer to store a LFN. */
  292. FF_T_WCHAR * pcLastPtr = pxDirEntry->pcFileName + sizeof( pxDirEntry->pcFileName );
  293. #else
  294. char * pcCurPtr; /* Pointer to store a LFN. */
  295. char * pcLastPtr = pxDirEntry->pcFileName + sizeof( pxDirEntry->pcFileName );
  296. #endif /* ffconfigUNICODE_UTF16_SUPPORT */
  297. uint16_t lfnItem = 0;
  298. uint8_t ucCheckSum = 0;
  299. BaseType_t xLFNCount = 0;
  300. BaseType_t xLFNTotal = 0;
  301. uint8_t lastAttrib;
  302. BaseType_t xIndex;
  303. #endif /* ffconfigLFN_SUPPORT */
  304. #if ( ffconfigLFN_SUPPORT != 0 )
  305. {
  306. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  307. BaseType_t NameLen = ( BaseType_t ) wcslen( ( const char * ) pcName );
  308. #else
  309. BaseType_t NameLen = ( BaseType_t ) strlen( ( const char * ) pcName );
  310. #endif
  311. /* Find enough places for the LFNs and the ShortName. */
  312. entriesNeeded = ( uint8_t ) ( ( NameLen + 12 ) / 13 ) + 1;
  313. }
  314. #else
  315. {
  316. entriesNeeded = 1;
  317. }
  318. #endif /* ffconfigLFN_SUPPORT */
  319. if( ( pxFindParams->ulFlags & FIND_FLAG_FITS_SHORT_OK ) == FIND_FLAG_FITS_SHORT_OK )
  320. {
  321. testShortname = pdTRUE;
  322. }
  323. else
  324. {
  325. testShortname = pdFALSE;
  326. }
  327. pxDirEntry->ucAttrib = 0;
  328. if( ( pxFindParams->ulFlags & FIND_FLAG_CREATE_FLAG ) != 0 )
  329. {
  330. /* A file is to be created: keep track of the first free entry big enough
  331. * to hold this file name. */
  332. pxFindParams->lFreeEntry = -1;
  333. }
  334. else
  335. {
  336. pxFindParams->lFreeEntry = 0;
  337. }
  338. xError = FF_InitEntryFetch( pxIOManager, pxFindParams->ulDirCluster, &xFetchContext );
  339. if( FF_isERR( xError ) == pdFALSE )
  340. {
  341. for( pxDirEntry->usCurrentItem = 0; pxDirEntry->usCurrentItem < FF_MAX_ENTRIES_PER_DIRECTORY; pxDirEntry->usCurrentItem++ )
  342. {
  343. if( ( src == NULL ) ||
  344. ( src >= xFetchContext.pxBuffer->pucBuffer + ( pxIOManager->usSectorSize - FF_SIZEOF_DIRECTORY_ENTRY ) ) )
  345. {
  346. xError = FF_FetchEntryWithContext( pxIOManager, pxDirEntry->usCurrentItem, &xFetchContext, NULL );
  347. if( FF_isERR( xError ) != pdFALSE )
  348. {
  349. break;
  350. }
  351. src = xFetchContext.pxBuffer->pucBuffer;
  352. }
  353. else
  354. {
  355. /* Advance 32 bytes. */
  356. src += FF_SIZEOF_DIRECTORY_ENTRY;
  357. }
  358. if( FF_isEndOfDir( src ) )
  359. {
  360. /* 0x00 end-of-dir. */
  361. break;
  362. }
  363. if( FF_isDeleted( src ) )
  364. {
  365. /* Entry not used or deleted. */
  366. pxDirEntry->ucAttrib = 0;
  367. if( ( pxFindParams->lFreeEntry < 0 ) && ( ++freeCount == entriesNeeded ) )
  368. {
  369. /* Remember the beginning entry in the sequential sequence. */
  370. pxFindParams->lFreeEntry = ( pxDirEntry->usCurrentItem - ( entriesNeeded - 1 ) );
  371. }
  372. continue;
  373. }
  374. /* The current entry is in use, so reset the free-entry-counter */
  375. freeCount = 0;
  376. #if ( ffconfigLFN_SUPPORT != 0 )
  377. {
  378. lastAttrib = pxDirEntry->ucAttrib;
  379. }
  380. #endif
  381. pxDirEntry->ucAttrib = FF_getChar( src, FF_FAT_DIRENT_ATTRIB );
  382. if( ( pxDirEntry->ucAttrib & FF_FAT_ATTR_LFN ) == FF_FAT_ATTR_LFN )
  383. {
  384. /* LFN Processing. */
  385. #if ( ffconfigLFN_SUPPORT != 0 )
  386. {
  387. if( ( xLFNCount == 0 ) || ( ( lastAttrib & FF_FAT_ATTR_LFN ) != FF_FAT_ATTR_LFN ) )
  388. {
  389. xLFNTotal = xLFNCount = ( BaseType_t ) ( src[ 0 ] & ~0x40 );
  390. lfnItem = pxDirEntry->usCurrentItem;
  391. ucCheckSum = FF_getChar( src, FF_FAT_LFN_CHECKSUM );
  392. pcLastPtr[ -1 ] = '\0';
  393. }
  394. if( xLFNCount != 0 )
  395. {
  396. xLFNCount--;
  397. pcCurPtr = pxDirEntry->pcFileName + ( xLFNCount * 13 );
  398. /*
  399. * This section needs to extract the name and do the comparison
  400. * dependent on UNICODE settings in the FreeRTOSFATConfig.h file.
  401. */
  402. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  403. {
  404. /* Add UTF-16 Routine here. */
  405. /* Copy first 5 UTF-16 chars ( 10 bytes ). */
  406. memcpy( pcCurPtr, &src[ FF_FAT_LFN_NAME_1 ], 10 );
  407. /* Increment Filename pointer 5 utf16 chars. */
  408. pcCurPtr += 5;
  409. /* Copy next 6 chars ( 12 bytes ). */
  410. memcpy( pcCurPtr, &src[ FF_FAT_LFN_NAME_2 ], 12 );
  411. pcCurPtr += 6;
  412. /* You're getting the idea by now! */
  413. memcpy( pcCurPtr, &src[ FF_FAT_LFN_NAME_3 ], 4 );
  414. pcCurPtr += 2;
  415. } /* ffconfigUNICODE_UTF16_SUPPORT */
  416. #elif ( ffconfigUNICODE_UTF8_SUPPORT != 0 )
  417. {
  418. /* UTF-8 Routine here. */
  419. for( xIndex = 0; ( xIndex < 5 ) && ( pcCurPtr < pcLastPtr ); xIndex++ )
  420. {
  421. /* Was there a surrogate sequence? -- Add handling here. */
  422. utf8Error = FF_Utf16ctoUtf8c( ( uint8_t * ) pcCurPtr, ( uint16_t * ) &src[ FF_FAT_LFN_NAME_1 + ( 2 * xIndex ) ], pcLastPtr - pcCurPtr );
  423. if( utf8Error > 0 )
  424. {
  425. pcCurPtr += utf8Error;
  426. }
  427. else
  428. {
  429. if( FF_GETERROR( utf8Error ) == FF_ERR_UNICODE_INVALID_SEQUENCE )
  430. {
  431. /* Handle potential surrogate sequence across entries. */
  432. }
  433. }
  434. }
  435. for( xIndex = 0; xIndex < 6 && pcCurPtr < pcLastPtr; xIndex++ )
  436. {
  437. /* Was there a surrogate sequence? -- To add handling here. */
  438. utf8Error = FF_Utf16ctoUtf8c( ( uint8_t * ) pcCurPtr, ( uint16_t * ) &src[ FF_FAT_LFN_NAME_2 + ( 2 * xIndex ) ], pcLastPtr - pcCurPtr );
  439. if( utf8Error > 0 )
  440. {
  441. pcCurPtr += utf8Error;
  442. }
  443. else
  444. {
  445. if( FF_GETERROR( utf8Error ) == FF_ERR_UNICODE_INVALID_SEQUENCE )
  446. {
  447. /* Handle potential surrogate sequence across entries. */
  448. }
  449. }
  450. }
  451. for( xIndex = 0; xIndex < 2 && pcCurPtr < pcLastPtr; xIndex++ )
  452. {
  453. /* Was there a surrogate sequence? -- To add handling here. */
  454. utf8Error = FF_Utf16ctoUtf8c( ( uint8_t * ) pcCurPtr, ( uint16_t * ) &src[ FF_FAT_LFN_NAME_3 + ( 2 * xIndex ) ], pcLastPtr - pcCurPtr );
  455. if( utf8Error > 0 )
  456. {
  457. pcCurPtr += utf8Error;
  458. }
  459. else
  460. {
  461. if( FF_GETERROR( utf8Error ) == FF_ERR_UNICODE_INVALID_SEQUENCE )
  462. {
  463. /* Handle potential surrogate sequence across entries. */
  464. }
  465. }
  466. }
  467. } /* ffconfigUNICODE_UTF8_SUPPORT */
  468. #else /* if ( ffconfigUNICODE_UTF16_SUPPORT != 0 ) */
  469. { /* use ASCII notation. */
  470. for( xIndex = 0; ( xIndex < 10 ) && ( pcCurPtr < pcLastPtr ); xIndex += 2 )
  471. {
  472. *( pcCurPtr++ ) = src[ FF_FAT_LFN_NAME_1 + xIndex ];
  473. }
  474. for( xIndex = 0; ( xIndex < 12 ) && ( pcCurPtr < pcLastPtr ); xIndex += 2 )
  475. {
  476. *( pcCurPtr++ ) = src[ FF_FAT_LFN_NAME_2 + xIndex ];
  477. }
  478. for( xIndex = 0; ( xIndex < 4 ) && ( pcCurPtr < pcLastPtr ); xIndex += 2 )
  479. {
  480. *( pcCurPtr++ ) = src[ FF_FAT_LFN_NAME_3 + xIndex ];
  481. }
  482. }
  483. #endif /* ( ffconfigUNICODE_UTF16_SUPPORT == 0 ) && !( ffconfigUNICODE_UTF8_SUPPORT == 0 ) */
  484. if( ( xLFNCount == xLFNTotal - 1 ) && ( pcCurPtr < pcLastPtr ) )
  485. {
  486. *pcCurPtr = '\0'; /* Important when name len is multiple of 13. */
  487. }
  488. } /* if( xLFNCount ) */
  489. }
  490. #endif /* ffconfigLFN_SUPPORT */
  491. continue;
  492. }
  493. if( ( pxDirEntry->ucAttrib & FF_FAT_ATTR_VOLID ) == FF_FAT_ATTR_VOLID )
  494. {
  495. #if ( ffconfigLFN_SUPPORT != 0 )
  496. {
  497. xLFNTotal = 0;
  498. }
  499. #endif /* ffconfigLFN_SUPPORT */
  500. continue;
  501. }
  502. #if ( ffconfigLFN_SUPPORT != 0 )
  503. if( ( xLFNTotal == 0 ) || ( ucCheckSum != FF_CreateChkSum( src ) ) )
  504. #endif /* ffconfigLFN_SUPPORT */
  505. {
  506. /* This entry has only a short name, or the checksum isn't correct
  507. * Use the short name for comparison */
  508. memcpy( pxDirEntry->pcFileName, src, 11 );
  509. FF_ProcessShortName( ( char * ) pxDirEntry->pcFileName );
  510. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  511. {
  512. /* FileName now contains a 8-bit short name
  513. * Expand it to a FF_T_WCHAR string. */
  514. FF_ShortNameExpand( pxDirEntry->pcFileName );
  515. }
  516. #endif /* ffconfigUNICODE_UTF16_SUPPORT */
  517. #if ( ffconfigLFN_SUPPORT != 0 )
  518. {
  519. xLFNTotal = 0;
  520. }
  521. #endif /* ffconfigLFN_SUPPORT */
  522. }
  523. /* This function FF_FindEntryInDir( ) is either called with
  524. * pa_Attrib==0 or with pa_Attrib==FF_FAT_ATTR_DIR
  525. * In the last case the caller is looking for a directory */
  526. if( ( pxDirEntry->ucAttrib & pa_Attrib ) == pa_Attrib )
  527. {
  528. if( testShortname )
  529. {
  530. /* Both strings are stored in the directory format
  531. * e.g. "README TXT", without a dot */
  532. if( memcmp( src, pxFindParams->pcEntryBuffer, 11 ) == 0 )
  533. {
  534. pxFindParams->ulFlags |= FIND_FLAG_SHORTNAME_CHECKED | FIND_FLAG_SHORTNAME_FOUND;
  535. }
  536. }
  537. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  538. if( wcsicmp( ( const char * ) pcName, ( const char * ) pxDirEntry->pcFileName ) == 0 )
  539. #else
  540. if( FF_stricmp( ( const char * ) pcName, ( const char * ) pxDirEntry->pcFileName ) == 0 )
  541. #endif /* ffconfigUNICODE_UTF16_SUPPORT */
  542. {
  543. /* Finally get the complete information. */
  544. #if ( ffconfigLFN_SUPPORT != 0 )
  545. if( xLFNTotal )
  546. {
  547. xError = FF_PopulateLongDirent( pxIOManager, pxDirEntry, ( uint16_t ) lfnItem, &xFetchContext );
  548. if( FF_isERR( xError ) )
  549. {
  550. break;
  551. }
  552. }
  553. else
  554. #endif /* ffconfigLFN_SUPPORT */
  555. {
  556. FF_PopulateShortDirent( pxIOManager, pxDirEntry, src );
  557. /* HT: usCurrentItem wasn't increased here. */
  558. pxDirEntry->usCurrentItem++;
  559. }
  560. /* Object found, the cluster number will be returned. */
  561. xResult = pxDirEntry->ulObjectCluster;
  562. break;
  563. }
  564. }
  565. #if ( ffconfigLFN_SUPPORT != 0 )
  566. {
  567. xLFNTotal = 0;
  568. }
  569. #endif
  570. } /* for( ; pxDirEntry->usCurrentItem < FF_MAX_ENTRIES_PER_DIRECTORY; pxDirEntry->usCurrentItem++ ) */
  571. {
  572. FF_Error_t xTempError;
  573. xTempError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext );
  574. if( FF_isERR( xError ) == pdFALSE )
  575. {
  576. xError = xTempError;
  577. }
  578. }
  579. } /* if( FF_isERR( xError ) == pdFALSE ) */
  580. if( FF_isERR( xError ) == pdFALSE )
  581. {
  582. /* If a free entry wasn't found yet, put it to the current (last) item */
  583. if( pxFindParams->lFreeEntry < 0 )
  584. {
  585. pxFindParams->lFreeEntry = pxDirEntry->usCurrentItem;
  586. }
  587. /* If we were checking the existence of the short-name
  588. * set the Checked flag now */
  589. if( testShortname )
  590. {
  591. pxFindParams->ulFlags |= FIND_FLAG_SHORTNAME_CHECKED;
  592. }
  593. }
  594. if( pxError != NULL )
  595. {
  596. *pxError = xError;
  597. }
  598. return xResult;
  599. } /* FF_FindEntryInDir() */
  600. /*-----------------------------------------------------------*/
  601. /**
  602. * @private
  603. **/
  604. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  605. uint32_t FF_FindDir( FF_IOManager_t * pxIOManager,
  606. const FF_T_WCHAR * pcPath,
  607. uint16_t pathLen,
  608. FF_Error_t * pxError )
  609. #else
  610. uint32_t FF_FindDir( FF_IOManager_t * pxIOManager,
  611. const char * pcPath,
  612. uint16_t pathLen,
  613. FF_Error_t * pxError )
  614. #endif
  615. {
  616. uint16_t it = 0; /* Re-entrancy Variables for FF_strtok( ). */
  617. BaseType_t last = pdFALSE;
  618. FF_DirEnt_t xMyDirectory;
  619. FF_FindParams_t xFindParams;
  620. FF_Error_t xError;
  621. BaseType_t xFound;
  622. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  623. FF_T_WCHAR mytoken[ ffconfigMAX_FILENAME ];
  624. FF_T_WCHAR * pcToken;
  625. #else
  626. char mytoken[ ffconfigMAX_FILENAME ];
  627. char * pcToken;
  628. #endif
  629. #if ( ffconfigPATH_CACHE != 0 )
  630. BaseType_t xIndex;
  631. #endif
  632. memset( &xFindParams, '\0', sizeof( xFindParams ) );
  633. xFindParams.ulDirCluster = pxIOManager->xPartition.ulRootDirCluster;
  634. xError = FF_ERR_NONE;
  635. if( pathLen <= 1 )
  636. {
  637. /* Must be the root directory.
  638. * 'xFindParams.ulDirCluster' will be returned containing 'pxIOManager->xPartition.ulRootDirCluster'. */
  639. xFound = pdTRUE;
  640. }
  641. else
  642. {
  643. /* Only the root directory '/' shall have a trailing slash in its name. */
  644. if( ( pcPath[ pathLen - 1 ] == '\\' ) || ( pcPath[ pathLen - 1 ] == '/' ) )
  645. {
  646. pathLen--;
  647. }
  648. xFound = pdFALSE;
  649. #if ( ffconfigPATH_CACHE != 0 ) /* Is the requested pcPath in the PATH CACHE? */
  650. {
  651. FF_PendSemaphore( pxIOManager->pvSemaphore ); /* Thread safety on shared object! */
  652. {
  653. for( xIndex = 0; xIndex < ffconfigPATH_CACHE_DEPTH; xIndex++ )
  654. {
  655. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  656. if( wcslen( pxIOManager->xPartition.pxPathCache[ xIndex ].pcPath ) == ( size_t ) pathLen )
  657. #else
  658. if( strlen( pxIOManager->xPartition.pxPathCache[ xIndex ].pcPath ) == ( size_t ) pathLen )
  659. #endif
  660. {
  661. if( FF_strmatch( pxIOManager->xPartition.pxPathCache[ xIndex ].pcPath, pcPath, pathLen ) )
  662. {
  663. xFindParams.ulDirCluster = pxIOManager->xPartition.pxPathCache[ xIndex ].ulDirCluster;
  664. xFound = pdTRUE;
  665. break;
  666. }
  667. }
  668. }
  669. }
  670. FF_ReleaseSemaphore( pxIOManager->pvSemaphore );
  671. }
  672. #endif /* ffconfigPATH_CACHE */
  673. }
  674. if( xFound == pdFALSE )
  675. {
  676. pcToken = FF_strtok( pcPath, mytoken, &it, &last, pathLen );
  677. do
  678. {
  679. xMyDirectory.usCurrentItem = 0;
  680. xFindParams.ulDirCluster = FF_FindEntryInDir( pxIOManager, &xFindParams, pcToken, ( uint8_t ) FF_FAT_ATTR_DIR, &xMyDirectory, &xError );
  681. if( xFindParams.ulDirCluster == 0ul )
  682. {
  683. break;
  684. }
  685. pcToken = FF_strtok( pcPath, mytoken, &it, &last, pathLen );
  686. } while( pcToken != NULL );
  687. if( ( pcToken != NULL ) &&
  688. ( ( FF_isERR( xError ) == pdFALSE ) || ( FF_GETERROR( xError ) == FF_ERR_DIR_END_OF_DIR ) ) )
  689. {
  690. xError = ( FF_Error_t ) ( FF_FINDDIR | FF_ERR_FILE_INVALID_PATH );
  691. }
  692. #if ( ffconfigPATH_CACHE != 0 ) /* Update the PATH CACHE with a new PATH. */
  693. {
  694. /* Only cache if the dir was actually found! */
  695. if( ( FF_isERR( xError ) == pdFALSE ) && ( xFindParams.ulDirCluster != 0ul ) )
  696. {
  697. FF_PendSemaphore( pxIOManager->pvSemaphore );
  698. {
  699. if( pathLen < ffconfigMAX_FILENAME ) /* Ensure the PATH won't cause a buffer overrun. */
  700. {
  701. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  702. {
  703. memcpy( pxIOManager->xPartition.pxPathCache[ pxIOManager->xPartition.ulPCIndex ].pcPath, pcPath, pathLen * sizeof( FF_T_WCHAR ) );
  704. }
  705. #else
  706. {
  707. memcpy( pxIOManager->xPartition.pxPathCache[ pxIOManager->xPartition.ulPCIndex ].pcPath, pcPath, pathLen );
  708. }
  709. #endif
  710. pxIOManager->xPartition.pxPathCache[ pxIOManager->xPartition.ulPCIndex ].pcPath[ pathLen ] = '\0';
  711. pxIOManager->xPartition.pxPathCache[ pxIOManager->xPartition.ulPCIndex ].ulDirCluster = xFindParams.ulDirCluster;
  712. pxIOManager->xPartition.ulPCIndex += 1;
  713. if( pxIOManager->xPartition.ulPCIndex >= ffconfigPATH_CACHE_DEPTH )
  714. {
  715. pxIOManager->xPartition.ulPCIndex = 0;
  716. }
  717. }
  718. }
  719. FF_ReleaseSemaphore( pxIOManager->pvSemaphore );
  720. }
  721. }
  722. #endif /* ffconfigPATH_CACHE */
  723. } /* if( pathLen > 1 ) */
  724. if( pxError != NULL )
  725. {
  726. *pxError = xError;
  727. }
  728. return xFindParams.ulDirCluster;
  729. } /* FF_FindDir() */
  730. /*-----------------------------------------------------------*/
  731. #if ( ffconfigSHORTNAME_CASE != 0 )
  732. /**
  733. * @private
  734. * For short-name entries, NT/XP etc store case information in byte 0x0c
  735. * Use this to show proper case of "README.txt" or "source.H"
  736. **/
  737. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  738. static void FF_CaseShortName( FF_T_WCHAR * pcName,
  739. uint8_t attrib )
  740. #else
  741. static void FF_CaseShortName( char * pcName,
  742. uint8_t attrib )
  743. #endif
  744. {
  745. uint8_t testAttrib = FF_FAT_CASE_ATTR_BASE;
  746. for( ; *pcName != '\0'; pcName++ )
  747. {
  748. if( *pcName == '.' )
  749. {
  750. testAttrib = FF_FAT_CASE_ATTR_EXT;
  751. }
  752. else if( ( attrib & testAttrib ) != 0 )
  753. {
  754. if( ( *pcName >= 'A' ) && ( *pcName <= 'Z' ) )
  755. {
  756. *pcName += 0x20;
  757. }
  758. }
  759. else if( ( *pcName >= 'a' ) && ( *pcName <= 'z' ) )
  760. {
  761. *pcName -= 0x20;
  762. }
  763. }
  764. }
  765. #endif /* ffconfigSHORTNAME_CASE */
  766. /*-----------------------------------------------------------*/
  767. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  768. /**
  769. * @private
  770. * Expand a short-name, adding a zero after each character
  771. **/
  772. static void FF_ShortNameExpand( FF_T_WCHAR * pFileName )
  773. {
  774. int8_t * pSource = ( ( int8_t * ) pFileName ) + 13;
  775. int8_t * pTarget = ( ( int8_t * ) pFileName ) + 26;
  776. /* "aaaaaaaa.eee": 12 characters plus a zero makes 13
  777. * Copy from the right to the left */
  778. while( pTarget > ( int8_t * ) pFileName )
  779. {
  780. pTarget[ -1 ] = 0;
  781. pTarget[ -2 ] = *( --pSource );
  782. pTarget -= 2;
  783. }
  784. }
  785. #endif /* ffconfigUNICODE_UTF16_SUPPORT */
  786. /*-----------------------------------------------------------*/
  787. /**
  788. * @private
  789. **/
  790. static void FF_ProcessShortName( char * pcName )
  791. {
  792. char pcShortName[ 13 ];
  793. char * pcTarget = pcName;
  794. int iSource;
  795. memcpy( pcShortName, pcName, 11 );
  796. for( iSource = 0; iSource < 11; iSource++ )
  797. {
  798. if( pcShortName[ iSource ] == 0x20 )
  799. {
  800. if( iSource >= 8 )
  801. {
  802. break;
  803. }
  804. iSource = 7;
  805. }
  806. else
  807. {
  808. if( iSource == 8 )
  809. {
  810. *( pcTarget++ ) = '.';
  811. }
  812. *( pcTarget++ ) = pcShortName[ iSource ];
  813. }
  814. }
  815. *pcTarget = '\0';
  816. }
  817. /*-----------------------------------------------------------*/
  818. #if ( ffconfigTIME_SUPPORT != 0 )
  819. static void FF_PlaceTime( uint8_t * pucEntryBuffer,
  820. uint32_t Offset,
  821. FF_SystemTime_t * pxTime )
  822. {
  823. uint16_t myShort;
  824. /* HT time changes:
  825. * E.g. Unzip needs to use original time rather than
  826. * the result of FF_GetSystemTime */
  827. myShort = 0;
  828. myShort |= ( ( pxTime->Hour << 11 ) & 0xF800 );
  829. myShort |= ( ( pxTime->Minute << 5 ) & 0x07E0 );
  830. myShort |= ( ( pxTime->Second / 2 ) & 0x001F );
  831. FF_putShort( pucEntryBuffer, ( uint16_t ) Offset, myShort );
  832. }
  833. #endif /* ffconfigTIME_SUPPORT */
  834. /*-----------------------------------------------------------*/
  835. #if ( ffconfigTIME_SUPPORT != 0 )
  836. static void FF_PlaceDate( uint8_t * pucEntryBuffer,
  837. uint32_t Offset,
  838. FF_SystemTime_t * pxTime )
  839. {
  840. uint16_t myShort;
  841. /* HT time changes:
  842. * Unzip needs to use original date rather than
  843. * the current date, so make it a parameter. */
  844. myShort = 0;
  845. myShort |= ( ( ( pxTime->Year - 1980 ) << 9 ) & 0xFE00 );
  846. myShort |= ( ( pxTime->Month << 5 ) & 0x01E0 );
  847. myShort |= ( pxTime->Day & 0x001F );
  848. FF_putShort( pucEntryBuffer, ( uint16_t ) Offset, myShort );
  849. }
  850. #endif /* ffconfigTIME_SUPPORT */
  851. /*-----------------------------------------------------------*/
  852. #if ( ffconfigTIME_SUPPORT != 0 )
  853. static void FF_GetTime( FF_SystemTime_t * pxTime,
  854. const uint8_t * pucEntryBuffer,
  855. uint32_t Offset )
  856. {
  857. uint16_t myShort;
  858. myShort = FF_getShort( pucEntryBuffer, ( uint16_t ) Offset );
  859. pxTime->Hour = ( ( ( myShort & 0xF800 ) >> 11 ) & 0x001F );
  860. pxTime->Minute = ( ( ( myShort & 0x07E0 ) >> 5 ) & 0x003F );
  861. pxTime->Second = 2 * ( myShort & 0x01F );
  862. }
  863. #endif /* ffconfigTIME_SUPPORT */
  864. /*-----------------------------------------------------------*/
  865. #if ( ffconfigTIME_SUPPORT != 0 )
  866. static void FF_GetDate( FF_SystemTime_t * pxTime,
  867. const uint8_t * pucEntryBuffer,
  868. uint32_t Offset )
  869. {
  870. uint16_t myShort;
  871. myShort = FF_getShort( pucEntryBuffer, ( uint16_t ) Offset );
  872. pxTime->Year = 1980 + ( ( ( myShort & 0xFE00 ) >> 9 ) & 0x07F );
  873. pxTime->Month = ( ( ( myShort & 0x01E0 ) >> 5 ) & 0x000F );
  874. pxTime->Day = myShort & 0x01F;
  875. }
  876. #endif /* ffconfigTIME_SUPPORT */
  877. /*-----------------------------------------------------------*/
  878. void FF_PopulateShortDirent( FF_IOManager_t * pxIOManager,
  879. FF_DirEnt_t * pxDirEntry,
  880. const uint8_t * pucEntryBuffer )
  881. {
  882. memcpy( pxDirEntry->pcFileName, pucEntryBuffer, 11 ); /* Copy the filename into the Dirent object. */
  883. #if ( ffconfigLFN_SUPPORT != 0 ) && ( ffconfigINCLUDE_SHORT_NAME != 0 )
  884. memcpy( pxDirEntry->pcShortName, pucEntryBuffer, 11 );
  885. pxDirEntry->pcShortName[ 11 ] = '\0';
  886. FF_ProcessShortName( pxDirEntry->pcShortName ); /* For debuggers only. */
  887. #endif
  888. FF_ProcessShortName( ( char * ) pxDirEntry->pcFileName ); /* Format the shortname, for pleasant viewing. */
  889. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  890. /* FileName contains a 8-bit short name
  891. * Expand it to a FF_T_WCHAR string */
  892. FF_ShortNameExpand( pxDirEntry->pcFileName );
  893. #endif
  894. ( void ) pxIOManager; /* Silence a compiler warning, about not referencing pxIOManager. */
  895. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  896. FF_tolower( pxDirEntry->pcFileName, ( uint32_t ) wcslen( pxDirEntry->pcFileName ) );
  897. #else
  898. FF_tolower( pxDirEntry->pcFileName, ( uint32_t ) strlen( pxDirEntry->pcFileName ) );
  899. #endif
  900. /* Get the item's Cluster address. */
  901. pxDirEntry->ulObjectCluster =
  902. ( ( uint32_t ) FF_getShort( pucEntryBuffer, FF_FAT_DIRENT_CLUS_HIGH ) << 16 ) |
  903. ( uint32_t ) FF_getShort( pucEntryBuffer, FF_FAT_DIRENT_CLUS_LOW );
  904. #if ( ffconfigTIME_SUPPORT != 0 )
  905. /* Get the creation Time & Date. */
  906. FF_GetTime( &pxDirEntry->xCreateTime, pucEntryBuffer, FF_FAT_DIRENT_CREATE_TIME );
  907. FF_GetDate( &pxDirEntry->xCreateTime, pucEntryBuffer, FF_FAT_DIRENT_CREATE_DATE );
  908. /* Get the modified Time & Date
  909. * HT Here xCreateTime became xModifiedTime: */
  910. FF_GetTime( &pxDirEntry->xModifiedTime, pucEntryBuffer, FF_FAT_DIRENT_LASTMOD_TIME );
  911. FF_GetDate( &pxDirEntry->xModifiedTime, pucEntryBuffer, FF_FAT_DIRENT_LASTMOD_DATE );
  912. /* Get the last accessed Date. */
  913. FF_GetDate( &pxDirEntry->xAccessedTime, pucEntryBuffer, FF_FAT_DIRENT_LASTACC_DATE );
  914. pxDirEntry->xAccessedTime.Hour = 0;
  915. pxDirEntry->xAccessedTime.Minute = 0;
  916. pxDirEntry->xAccessedTime.Second = 0;
  917. #endif /* if ( ffconfigTIME_SUPPORT != 0 ) */
  918. /* Get the filesize. */
  919. pxDirEntry->ulFileSize = FF_getLong( pucEntryBuffer, ( uint16_t ) ( FF_FAT_DIRENT_FILESIZE ) );
  920. /* Get the attribute. */
  921. pxDirEntry->ucAttrib = FF_getChar( pucEntryBuffer, ( uint16_t ) ( FF_FAT_DIRENT_ATTRIB ) );
  922. }
  923. /*-----------------------------------------------------------*/
  924. /* Initialises a context object for FF_FetchEntryWithContext( */
  925. FF_Error_t FF_InitEntryFetch( FF_IOManager_t * pxIOManager,
  926. uint32_t ulDirCluster,
  927. FF_FetchContext_t * pxContext )
  928. {
  929. FF_Error_t xError;
  930. memset( pxContext, 0, sizeof( FF_FetchContext_t ) );
  931. /* Get the total length of the chain. */
  932. pxContext->ulChainLength = FF_GetChainLength( pxIOManager, ulDirCluster, NULL, &xError );
  933. if( FF_isERR( xError ) == pdFALSE )
  934. {
  935. pxContext->ulDirCluster = ulDirCluster;
  936. pxContext->ulCurrentClusterLCN = ulDirCluster;
  937. if( pxIOManager->xPartition.ucType != FF_T_FAT32 )
  938. {
  939. /* Handle Root Dirs that don't have cluster chains! */
  940. if( pxContext->ulDirCluster == pxIOManager->xPartition.ulRootDirCluster )
  941. {
  942. /* This is a RootDIR, special consideration needs to be made, because it doesn't have a Cluster chain! */
  943. pxContext->ulChainLength = pxIOManager->xPartition.ulRootDirSectors / pxIOManager->xPartition.ulSectorsPerCluster;
  944. if( pxContext->ulChainLength == 0 ) /* Some media has ulRootDirSectors < ulSectorsPerCluster. This is wrong, as it should be atleast 1 cluster! */
  945. {
  946. pxContext->ulChainLength = 1;
  947. }
  948. }
  949. }
  950. }
  951. return xError;
  952. } /* FF_InitEntryFetch() */
  953. /*-----------------------------------------------------------*/
  954. FF_Error_t FF_CleanupEntryFetch( FF_IOManager_t * pxIOManager,
  955. FF_FetchContext_t * pxContext )
  956. {
  957. FF_Error_t xError = FF_ERR_NONE;
  958. if( pxContext->pxBuffer )
  959. {
  960. xError = FF_ReleaseBuffer( pxIOManager, pxContext->pxBuffer );
  961. pxContext->pxBuffer = NULL;
  962. }
  963. return xError;
  964. } /* FF_CleanupEntryFetch() */
  965. /*-----------------------------------------------------------*/
  966. /**
  967. * @private
  968. * @brief Find the cluster for a given Entry within a directory
  969. * @brief Make an exception for the root directory ( non FAT32 only ):
  970. * @brief Just calculate the cluster ( don't consult the actual FAT )
  971. *
  972. * @param pxIOManager FF_IOManager_t object that was created by FF_CreateIOManger( ).
  973. * @param ulEntry The sequence number of the entry of interest
  974. * @param pxContext Context of current search
  975. *
  976. * @Return FF_ERR_NONE on success
  977. * @Return Possible error returned by FF_TraverseFAT( ) or END_OF_DIR
  978. *
  979. * Side effects:
  980. * - pxContext->ulCurrentClusterNum : relative cluster number ( 0 <= Num < ulChainLength )
  981. * - pxContext->ulCurrentClusterLCN : fysical cluster on the partition
  982. **/
  983. static FF_Error_t FF_Traverse( FF_IOManager_t * pxIOManager,
  984. uint32_t ulEntry,
  985. FF_FetchContext_t * pxContext )
  986. {
  987. uint32_t ulClusterNum = FF_getClusterChainNumber( pxIOManager, ulEntry, ( uint16_t ) FF_SIZEOF_DIRECTORY_ENTRY );
  988. FF_Error_t xError = FF_ERR_NONE;
  989. /* Check if we're past the last cluster ( ulChainLength is also valid for root sectors ). */
  990. if( ( ulClusterNum + 1 ) > pxContext->ulChainLength )
  991. {
  992. xError = FF_ERR_DIR_END_OF_DIR | FF_TRAVERSE; /* End of Dir was reached! */
  993. }
  994. else if( ( pxIOManager->xPartition.ucType != FF_T_FAT32 ) &&
  995. ( pxContext->ulDirCluster == pxIOManager->xPartition.ulRootDirCluster ) )
  996. {
  997. /* Double-check if the entry number isn't too high. */
  998. if( ulEntry > ( ( pxIOManager->xPartition.ulRootDirSectors * pxIOManager->xPartition.usBlkSize ) / FF_SIZEOF_DIRECTORY_ENTRY ) )
  999. {
  1000. xError = ( FF_Error_t ) ( FF_ERR_DIR_END_OF_DIR | FF_FETCHENTRYWITHCONTEXT );
  1001. }
  1002. else
  1003. {
  1004. pxContext->ulCurrentClusterLCN = pxContext->ulDirCluster;
  1005. }
  1006. }
  1007. else if( ulClusterNum != pxContext->ulCurrentClusterNum )
  1008. {
  1009. /* Traverse the fat gently! */
  1010. if( ulClusterNum > pxContext->ulCurrentClusterNum )
  1011. {
  1012. /* Start traverse from the current entry. */
  1013. pxContext->ulCurrentClusterLCN = FF_TraverseFAT( pxIOManager, pxContext->ulCurrentClusterLCN, ( ulClusterNum - pxContext->ulCurrentClusterNum ), &xError );
  1014. }
  1015. else
  1016. {
  1017. /* Start traverse from the beginning. */
  1018. pxContext->ulCurrentClusterLCN = FF_TraverseFAT( pxIOManager, pxContext->ulDirCluster, ulClusterNum, &xError );
  1019. }
  1020. }
  1021. if( FF_isERR( xError ) == pdFALSE )
  1022. {
  1023. pxContext->ulCurrentClusterNum = ulClusterNum;
  1024. }
  1025. return xError;
  1026. } /* FF_Traverse() */
  1027. /*-----------------------------------------------------------*/
  1028. FF_Error_t FF_FetchEntryWithContext( FF_IOManager_t * pxIOManager,
  1029. uint32_t ulEntry,
  1030. FF_FetchContext_t * pxContext,
  1031. uint8_t * pEntryBuffer )
  1032. {
  1033. uint32_t ulItemLBA;
  1034. uint32_t ulRelItem;
  1035. FF_Error_t xError;
  1036. xError = FF_Traverse( pxIOManager, ulEntry, pxContext );
  1037. if( FF_isERR( xError ) == pdFALSE )
  1038. {
  1039. ulRelItem = FF_getMinorBlockEntry( pxIOManager, ulEntry, ( uint32_t ) FF_SIZEOF_DIRECTORY_ENTRY );
  1040. ulItemLBA = FF_Cluster2LBA( pxIOManager, pxContext->ulCurrentClusterLCN ) +
  1041. FF_getMajorBlockNumber( pxIOManager, ulEntry, ( uint32_t ) FF_SIZEOF_DIRECTORY_ENTRY );
  1042. if( ( pxIOManager->xPartition.ucType != FF_T_FAT32 ) &&
  1043. ( pxContext->ulDirCluster == pxIOManager->xPartition.ulRootDirCluster ) )
  1044. {
  1045. ulItemLBA += ( ulEntry / ( ( pxIOManager->xPartition.usBlkSize * pxIOManager->xPartition.ulSectorsPerCluster ) /
  1046. FF_SIZEOF_DIRECTORY_ENTRY ) * pxIOManager->xPartition.ulSectorsPerCluster );
  1047. }
  1048. ulItemLBA = FF_getRealLBA( pxIOManager, ulItemLBA ) + FF_getMinorBlockNumber( pxIOManager, ulRelItem, ( uint32_t ) FF_SIZEOF_DIRECTORY_ENTRY );
  1049. if( ( pxContext->pxBuffer == NULL ) ||
  1050. ( pxContext->pxBuffer->ulSector != ulItemLBA ) ||
  1051. ( ( pxContext->pxBuffer->ucMode & FF_MODE_WRITE ) != 0 ) )
  1052. {
  1053. if( pxContext->pxBuffer != NULL )
  1054. {
  1055. xError = FF_ReleaseBuffer( pxIOManager, pxContext->pxBuffer );
  1056. pxContext->pxBuffer = NULL;
  1057. }
  1058. if( FF_isERR( xError ) == pdFALSE )
  1059. {
  1060. pxContext->pxBuffer = FF_GetBuffer( pxIOManager, ulItemLBA, FF_MODE_READ );
  1061. if( pxContext->pxBuffer == NULL )
  1062. {
  1063. xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_FETCHENTRYWITHCONTEXT );
  1064. }
  1065. }
  1066. }
  1067. if( ( pEntryBuffer != NULL ) && ( pxContext->pxBuffer != NULL ) )
  1068. {
  1069. memcpy( pEntryBuffer, pxContext->pxBuffer->pucBuffer + ( ulRelItem * FF_SIZEOF_DIRECTORY_ENTRY ), FF_SIZEOF_DIRECTORY_ENTRY );
  1070. }
  1071. }
  1072. return xError;
  1073. } /* FF_FetchEntryWithContext() */
  1074. /*-----------------------------------------------------------*/
  1075. FF_Error_t FF_PushEntryWithContext( FF_IOManager_t * pxIOManager,
  1076. uint32_t ulEntry,
  1077. FF_FetchContext_t * pxContext,
  1078. uint8_t * pEntryBuffer )
  1079. {
  1080. uint32_t ulItemLBA;
  1081. uint32_t ulRelItem;
  1082. FF_Error_t xError;
  1083. xError = FF_Traverse( pxIOManager, ulEntry, pxContext );
  1084. if( FF_isERR( xError ) == pdFALSE )
  1085. {
  1086. ulRelItem = FF_getMinorBlockEntry( pxIOManager, ulEntry, ( uint32_t ) FF_SIZEOF_DIRECTORY_ENTRY );
  1087. ulItemLBA = FF_Cluster2LBA( pxIOManager, pxContext->ulCurrentClusterLCN ) + FF_getMajorBlockNumber( pxIOManager, ulEntry, ( uint32_t ) FF_SIZEOF_DIRECTORY_ENTRY );
  1088. if( ( pxIOManager->xPartition.ucType != FF_T_FAT32 ) &&
  1089. ( pxContext->ulDirCluster == pxIOManager->xPartition.ulRootDirCluster ) )
  1090. {
  1091. ulItemLBA += ( ulEntry /
  1092. ( ( pxIOManager->xPartition.usBlkSize * pxIOManager->xPartition.ulSectorsPerCluster ) / FF_SIZEOF_DIRECTORY_ENTRY ) * pxIOManager->xPartition.ulSectorsPerCluster );
  1093. }
  1094. ulItemLBA = FF_getRealLBA( pxIOManager, ulItemLBA ) + FF_getMinorBlockNumber( pxIOManager, ulRelItem, ( uint32_t ) FF_SIZEOF_DIRECTORY_ENTRY );
  1095. if( ( pxContext->pxBuffer == NULL ) ||
  1096. ( pxContext->pxBuffer->ulSector != ulItemLBA ) ||
  1097. ( ( pxContext->pxBuffer->ucMode & FF_MODE_WRITE ) == 0 ) )
  1098. {
  1099. if( pxContext->pxBuffer != NULL )
  1100. {
  1101. xError = FF_ReleaseBuffer( pxIOManager, pxContext->pxBuffer );
  1102. pxContext->pxBuffer = NULL;
  1103. }
  1104. if( FF_isERR( xError ) == pdFALSE )
  1105. {
  1106. pxContext->pxBuffer = FF_GetBuffer( pxIOManager, ulItemLBA, FF_MODE_WRITE );
  1107. if( pxContext->pxBuffer == NULL )
  1108. {
  1109. xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_FETCHENTRYWITHCONTEXT );
  1110. }
  1111. }
  1112. }
  1113. /* Now change the entry: */
  1114. if( pxContext->pxBuffer != NULL )
  1115. {
  1116. memcpy( pxContext->pxBuffer->pucBuffer + ( ulRelItem * FF_SIZEOF_DIRECTORY_ENTRY ), pEntryBuffer, FF_SIZEOF_DIRECTORY_ENTRY );
  1117. }
  1118. }
  1119. return xError;
  1120. } /* FF_PushEntryWithContext() */
  1121. /*-----------------------------------------------------------*/
  1122. /**
  1123. * @private
  1124. **/
  1125. FF_Error_t FF_GetEntry( FF_IOManager_t * pxIOManager,
  1126. uint16_t usEntry,
  1127. uint32_t ulDirCluster,
  1128. FF_DirEnt_t * pxDirEntry )
  1129. {
  1130. /* A 32 byte directory entry. */
  1131. uint8_t ucEntryBuffer[ FF_SIZEOF_DIRECTORY_ENTRY ];
  1132. FF_FetchContext_t xFetchContext;
  1133. FF_Error_t xError;
  1134. #if ( ffconfigLFN_SUPPORT == 0 )
  1135. BaseType_t xLFNCount;
  1136. #endif
  1137. xError = FF_InitEntryFetch( pxIOManager, ulDirCluster, &xFetchContext );
  1138. if( FF_isERR( xError ) == pdFALSE )
  1139. {
  1140. xError = FF_FetchEntryWithContext( pxIOManager, usEntry, &xFetchContext, ucEntryBuffer );
  1141. if( ( FF_isERR( xError ) == pdFALSE ) &&
  1142. ( FF_isDeleted( ucEntryBuffer ) == pdFALSE ) )
  1143. {
  1144. if( FF_isEndOfDir( ucEntryBuffer ) != pdFALSE )
  1145. {
  1146. xError = ( FF_Error_t ) ( FF_ERR_DIR_END_OF_DIR | FF_GETENTRY );
  1147. }
  1148. else
  1149. {
  1150. pxDirEntry->ucAttrib = FF_getChar( ucEntryBuffer, ( uint16_t ) ( FF_FAT_DIRENT_ATTRIB ) );
  1151. if( ( pxDirEntry->ucAttrib & FF_FAT_ATTR_LFN ) == FF_FAT_ATTR_LFN )
  1152. {
  1153. #if ( ffconfigLFN_SUPPORT != 0 )
  1154. xError = FF_PopulateLongDirent( pxIOManager, pxDirEntry, usEntry, &xFetchContext );
  1155. #else
  1156. /* LFN Processing. */
  1157. xLFNCount = ( BaseType_t ) ( ucEntryBuffer[ 0 ] & ~0x40 );
  1158. pxDirEntry->usCurrentItem += ( xLFNCount - 1 );
  1159. #endif
  1160. }
  1161. else if( ( pxDirEntry->ucAttrib & FF_FAT_ATTR_VOLID ) != FF_FAT_ATTR_VOLID )
  1162. {
  1163. FF_PopulateShortDirent( pxIOManager, pxDirEntry, ucEntryBuffer );
  1164. pxDirEntry->usCurrentItem += 1;
  1165. }
  1166. }
  1167. }
  1168. {
  1169. FF_Error_t xTempError;
  1170. xTempError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext );
  1171. if( FF_isERR( xError ) == pdFALSE )
  1172. {
  1173. xError = xTempError;
  1174. }
  1175. }
  1176. }
  1177. return xError;
  1178. } /* FF_GetEntry() */
  1179. /*-----------------------------------------------------------*/
  1180. FF_Error_t FF_PopulateLongDirent( FF_IOManager_t * pxIOManager,
  1181. FF_DirEnt_t * pxDirEntry,
  1182. uint16_t usEntry,
  1183. FF_FetchContext_t * pxFetchContext )
  1184. {
  1185. /* First get the entire name as UTF-16 from the LFN's.
  1186. * Then transform into the API's native string format. */
  1187. FF_Error_t xError;
  1188. BaseType_t xNumLFNs;
  1189. uint8_t ucCheckSum;
  1190. /* A 32 byte directory entry. */
  1191. uint8_t pucEntryBuffer[ FF_SIZEOF_DIRECTORY_ENTRY ];
  1192. char pcShortName[ 13 ];
  1193. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  1194. UBaseType_t uiLfnLength = 0;
  1195. #endif
  1196. #if ( ffconfigUNICODE_UTF16_SUPPORT == 0 )
  1197. BaseType_t xIndex, y;
  1198. #endif
  1199. #if ( ffconfigUNICODE_UTF16_SUPPORT == 0 ) && ( ffconfigUNICODE_UTF8_SUPPORT == 0 )
  1200. char * pcLastPtr = pxDirEntry->pcFileName + sizeof( pxDirEntry->pcFileName );
  1201. char * pcCurPtr;
  1202. #endif
  1203. #if ( ffconfigUNICODE_UTF8_SUPPORT != 0 )
  1204. uint16_t nLfnBegin;
  1205. uint16_t usUtf8Len = 0;
  1206. #endif /* ffconfigUNICODE_UTF8_SUPPORT */
  1207. do
  1208. {
  1209. xError = FF_FetchEntryWithContext( pxIOManager, usEntry++, pxFetchContext, pucEntryBuffer );
  1210. if( FF_isERR( xError ) )
  1211. {
  1212. /* After breaking from this do {} while ( pdFALSE ) loop, xResult will be returned. */
  1213. break;
  1214. }
  1215. xNumLFNs = ( BaseType_t ) ( pucEntryBuffer[ 0 ] & ~0x40 );
  1216. ucCheckSum = FF_getChar( pucEntryBuffer, FF_FAT_LFN_CHECKSUM );
  1217. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  1218. {
  1219. /* UTF-16 Can simply get segments of the UTF-16 sequence
  1220. * going forward in the directory entries ( but reversed order ). */
  1221. while( xNumLFNs > 0 )
  1222. {
  1223. /* Avoid stack intensive use of a UTF-16 buffer. Stream direct to FileName dirent field in correct format. */
  1224. /* memcpy direct! -UTF-16 support. */
  1225. memcpy( pxDirEntry->pcFileName + ( ( xNumLFNs - 1 ) * 13 ) + 0, &( pucEntryBuffer[ FF_FAT_LFN_NAME_1 ] ), 10 );
  1226. memcpy( pxDirEntry->pcFileName + ( ( xNumLFNs - 1 ) * 13 ) + 5, &( pucEntryBuffer[ FF_FAT_LFN_NAME_2 ] ), 12 );
  1227. memcpy( pxDirEntry->pcFileName + ( ( xNumLFNs - 1 ) * 13 ) + 11, &( pucEntryBuffer[ FF_FAT_LFN_NAME_3 ] ), 4 );
  1228. uiLfnLength += 13;
  1229. xError = FF_FetchEntryWithContext( pxIOManager, usEntry++, pxFetchContext, pucEntryBuffer );
  1230. if( FF_isERR( xError ) )
  1231. {
  1232. break;
  1233. }
  1234. xNumLFNs--;
  1235. }
  1236. if( FF_isERR( xError ) )
  1237. {
  1238. break;
  1239. }
  1240. pxDirEntry->pcFileName[ uiLfnLength ] = '\0';
  1241. }
  1242. #endif /* ffconfigUNICODE_UTF16_SUPPORT */
  1243. #if ( ffconfigUNICODE_UTF8_SUPPORT != 0 )
  1244. {
  1245. /* UTF-8 Sequence, we can only convert this from the beginning, must receive entries in reverse. */
  1246. nLfnBegin = usEntry - 1;
  1247. for( xIndex = 0; xIndex < xNumLFNs; xIndex++ )
  1248. {
  1249. xError = FF_FetchEntryWithContext( pxIOManager, ( nLfnBegin + ( xNumLFNs - 1 ) - xIndex ), pxFetchContext, pucEntryBuffer );
  1250. if( FF_isERR( xError ) )
  1251. {
  1252. break;
  1253. }
  1254. /* Now have the first part of the UTF-16 sequence. Stream into a UTF-8 sequence. */
  1255. for( y = 0; y < 5; y++ )
  1256. {
  1257. xError = FF_Utf16ctoUtf8c( ( uint8_t * ) &pxDirEntry->pcFileName[ usUtf8Len ],
  1258. ( uint16_t * ) &pucEntryBuffer[ FF_FAT_LFN_NAME_1 + ( y * 2 ) ], sizeof( pxDirEntry->pcFileName ) - usUtf8Len );
  1259. if( xError > 0 )
  1260. {
  1261. usUtf8Len += ( uint16_t ) xError;
  1262. }
  1263. }
  1264. for( y = 0; y < 6; y++ )
  1265. {
  1266. xError = FF_Utf16ctoUtf8c( ( uint8_t * ) &pxDirEntry->pcFileName[ usUtf8Len ],
  1267. ( uint16_t * ) &pucEntryBuffer[ FF_FAT_LFN_NAME_2 + ( y * 2 ) ], sizeof( pxDirEntry->pcFileName ) - usUtf8Len );
  1268. if( xError > 0 )
  1269. {
  1270. usUtf8Len += ( uint16_t ) xError;
  1271. }
  1272. }
  1273. for( y = 0; y < 2; y++ )
  1274. {
  1275. xError = FF_Utf16ctoUtf8c( ( uint8_t * ) &pxDirEntry->pcFileName[ usUtf8Len ],
  1276. ( uint16_t * ) &pucEntryBuffer[ FF_FAT_LFN_NAME_3 + ( y * 2 ) ], sizeof( pxDirEntry->pcFileName ) - usUtf8Len );
  1277. if( xError > 0 )
  1278. {
  1279. usUtf8Len += ( uint16_t ) xError;
  1280. }
  1281. }
  1282. usEntry++;
  1283. }
  1284. if( FF_isERR( xError ) )
  1285. {
  1286. break;
  1287. }
  1288. pxDirEntry->pcFileName[ usUtf8Len ] = '\0';
  1289. /* Put Entry context to correct position. */
  1290. xError = FF_FetchEntryWithContext( pxIOManager, usEntry - 1, pxFetchContext, pucEntryBuffer );
  1291. if( FF_isERR( xError ) )
  1292. {
  1293. break;
  1294. }
  1295. }
  1296. #endif /* ( ffconfigUNICODE_UTF8_SUPPORT != 0 ) */
  1297. #if ( ffconfigUNICODE_UTF16_SUPPORT == 0 ) && ( ffconfigUNICODE_UTF8_SUPPORT == 0 ) /* No Unicode, simple ASCII. */
  1298. {
  1299. pcLastPtr[ -1 ] = '\0';
  1300. y = xNumLFNs;
  1301. while( xNumLFNs-- )
  1302. {
  1303. pcCurPtr = pxDirEntry->pcFileName + ( xNumLFNs * 13 );
  1304. for( xIndex = 0; ( xIndex < 10 ) && ( pcCurPtr < pcLastPtr ); xIndex += 2 )
  1305. {
  1306. *( pcCurPtr++ ) = pucEntryBuffer[ FF_FAT_LFN_NAME_1 + xIndex ];
  1307. }
  1308. for( xIndex = 0; ( xIndex < 12 ) && ( pcCurPtr < pcLastPtr ); xIndex += 2 )
  1309. {
  1310. *( pcCurPtr++ ) = pucEntryBuffer[ FF_FAT_LFN_NAME_2 + xIndex ];
  1311. }
  1312. for( xIndex = 0; ( xIndex < 4 ) && ( pcCurPtr < pcLastPtr ); xIndex += 2 )
  1313. {
  1314. *( pcCurPtr++ ) = pucEntryBuffer[ FF_FAT_LFN_NAME_3 + xIndex ];
  1315. }
  1316. if( ( xNumLFNs == ( y - 1 ) ) && ( pcCurPtr < pcLastPtr ) )
  1317. {
  1318. *pcCurPtr = '\0';
  1319. }
  1320. xError = FF_FetchEntryWithContext( pxIOManager, usEntry++, pxFetchContext, pucEntryBuffer );
  1321. if( FF_isERR( xError ) )
  1322. {
  1323. break;
  1324. }
  1325. }
  1326. if( FF_isERR( xError ) )
  1327. {
  1328. break;
  1329. }
  1330. }
  1331. #endif /* ( ffconfigUNICODE_UTF16_SUPPORT == 0 ) && ( ffconfigUNICODE_UTF8_SUPPORT == 0 ) */
  1332. /* Process the Shortname. -- LFN Transformation is now complete.
  1333. * Process the ShortName Entry. */
  1334. /* if SHORTNAMES must be included, simple byte copy into shortname buffer. */
  1335. #if ( ffconfigLFN_SUPPORT != 0 ) && ( ffconfigINCLUDE_SHORT_NAME != 0 )
  1336. {
  1337. memcpy( pxDirEntry->pcShortName, pucEntryBuffer, 11 );
  1338. pxDirEntry->pcShortName[ 11 ] = '\0';
  1339. FF_ProcessShortName( pxDirEntry->pcShortName );
  1340. }
  1341. #endif /* ( != 0 ffconfigLFN_SUPPORT ) && ( ffconfigINCLUDE_SHORT_NAME != 0 ) */
  1342. memcpy( pcShortName, pucEntryBuffer, 11 );
  1343. FF_ProcessShortName( pcShortName );
  1344. if( ucCheckSum != FF_CreateChkSum( pucEntryBuffer ) )
  1345. {
  1346. strcpy( pxDirEntry->pcFileName, pcShortName );
  1347. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  1348. {
  1349. FF_ShortNameExpand( pxDirEntry->pcFileName );
  1350. }
  1351. #endif /* ffconfigUNICODE_UTF16_SUPPORT */
  1352. }
  1353. /* Finally fill in the other details. */
  1354. pxDirEntry->ulObjectCluster =
  1355. ( ( uint32_t ) FF_getShort( pucEntryBuffer, FF_FAT_DIRENT_CLUS_HIGH ) << 16 ) |
  1356. ( uint32_t ) FF_getShort( pucEntryBuffer, FF_FAT_DIRENT_CLUS_LOW );
  1357. #if ( ffconfigTIME_SUPPORT != 0 )
  1358. {
  1359. /* Get the creation Time & Date. */
  1360. FF_GetTime( &pxDirEntry->xCreateTime, pucEntryBuffer, FF_FAT_DIRENT_CREATE_TIME );
  1361. FF_GetDate( &pxDirEntry->xCreateTime, pucEntryBuffer, FF_FAT_DIRENT_CREATE_DATE );
  1362. /* Get the modified Time & Date. */
  1363. /* HT Here xCreateTime has become xModifiedTime, as it should: */
  1364. FF_GetTime( &pxDirEntry->xModifiedTime, pucEntryBuffer, FF_FAT_DIRENT_LASTMOD_TIME );
  1365. FF_GetDate( &pxDirEntry->xModifiedTime, pucEntryBuffer, FF_FAT_DIRENT_LASTMOD_DATE );
  1366. /* Get the last accessed Date. */
  1367. FF_GetDate( &pxDirEntry->xAccessedTime, pucEntryBuffer, FF_FAT_DIRENT_LASTACC_DATE );
  1368. /* HT Why should these times be zero'd ? */
  1369. pxDirEntry->xAccessedTime.Hour = 0;
  1370. pxDirEntry->xAccessedTime.Minute = 0;
  1371. pxDirEntry->xAccessedTime.Second = 0;
  1372. }
  1373. #endif /* ffconfigTIME_SUPPORT */
  1374. /* Get the filesize. */
  1375. pxDirEntry->ulFileSize = FF_getLong( pucEntryBuffer, ( uint16_t ) ( FF_FAT_DIRENT_FILESIZE ) );
  1376. /* Get the attribute. */
  1377. pxDirEntry->ucAttrib = FF_getChar( pucEntryBuffer, ( uint16_t ) ( FF_FAT_DIRENT_ATTRIB ) );
  1378. pxDirEntry->usCurrentItem = usEntry;
  1379. }
  1380. while( pdFALSE );
  1381. return xError;
  1382. } /* FF_PopulateLongDirent() */
  1383. /*-----------------------------------------------------------*/
  1384. /**
  1385. * @public
  1386. * @brief Find's the first directory entry for the provided path.
  1387. *
  1388. * All values recorded in pxDirEntry must be preserved to and between calls to
  1389. * FF_FindNext( ).
  1390. *
  1391. * If ffconfigFINDAPI_ALLOW_WILDCARDS is defined, then path will have the following behaviour:
  1392. *
  1393. * path = "\" - Open the root dir, and iterate through all items.
  1394. * path = "\*.c" - Open the root dir, showing only files matching *.c wildcard.
  1395. * path = "\sub1\newdir" - Get the DIRENT for the newdir directory in /sub1/ if one exists.
  1396. * path = "\sub1\newdir\" - Open the directory /sub1/newdir/ and iterate through all items.
  1397. * path = "\sub1\newdir\*.c" - Open the directory /sub1/newdir/ and iterate through all items matching the *.c wildcard.
  1398. *
  1399. * It is important to distinguish the differences in behaviour between opening a Find operation
  1400. * on a path like /sub1 and /sub1/. ( /sub1 gets the sub1 dirent from the / dir, whereas /sub/ opens the sub1 dir ).
  1401. *
  1402. * Note, as compatible with other similar APIs, FreeRTOS+FAT also accepts \sub1\* for the same behaviour as
  1403. * /sub1/.
  1404. *
  1405. * @param pxIOManager FF_IOManager_t object that was created by FF_CreateIOManger( ).
  1406. * @param pxDirEntry FF_DirEnt_t object to store the entry information.
  1407. * @param path String to of the path to the Dir being listed.
  1408. *
  1409. * @Return 0 on success
  1410. * @Return FF_ERR_DEVICE_DRIVER_FAILED if device access failed.
  1411. * @Return -2 if Dir was not found.
  1412. *
  1413. **/
  1414. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  1415. FF_Error_t FF_FindFirst( FF_IOManager_t * pxIOManager,
  1416. FF_DirEnt_t * pxDirEntry,
  1417. const FF_T_WCHAR * pcPath )
  1418. #else
  1419. FF_Error_t FF_FindFirst( FF_IOManager_t * pxIOManager,
  1420. FF_DirEnt_t * pxDirEntry,
  1421. const char * pcPath )
  1422. #endif
  1423. {
  1424. FF_Error_t xError;
  1425. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  1426. uint16_t PathLen = ( uint16_t ) wcslen( pcPath );
  1427. #else
  1428. uint16_t PathLen = ( uint16_t ) strlen( pcPath );
  1429. #endif
  1430. #if ( ffconfigFINDAPI_ALLOW_WILDCARDS != 0 )
  1431. BaseType_t xIndex = 0;
  1432. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  1433. const FF_T_WCHAR * pcWildCard; /* Check for a Wild-card. */
  1434. #else
  1435. const char * pcWildCard; /* Check for a Wild-card. */
  1436. #endif
  1437. #endif
  1438. memset( pxDirEntry, 0, sizeof( FF_DirEnt_t ) );
  1439. if( pxIOManager == NULL )
  1440. {
  1441. xError = ( FF_Error_t ) ( FF_ERR_NULL_POINTER | FF_FINDFIRST );
  1442. }
  1443. #if ( ffconfigREMOVABLE_MEDIA != 0 )
  1444. else if( ( pxIOManager->ucFlags & FF_IOMAN_DEVICE_IS_EXTRACTED ) != 0 )
  1445. {
  1446. xError = ( FF_Error_t ) ( FF_ERR_IOMAN_DRIVER_NOMEDIUM | FF_FINDFIRST );
  1447. }
  1448. #endif /* ffconfigREMOVABLE_MEDIA */
  1449. else
  1450. {
  1451. #if ( ffconfigFINDAPI_ALLOW_WILDCARDS != 0 )
  1452. {
  1453. pxDirEntry->pcWildCard[ 0 ] = '\0'; /* WildCard blank if its not a wildCard. */
  1454. pcWildCard = &pcPath[ PathLen - 1 ];
  1455. if( PathLen != 0 )
  1456. {
  1457. /* Open the dir of the last token. */
  1458. while( ( *pcWildCard != '\\' ) && ( *pcWildCard != '/' ) )
  1459. {
  1460. xIndex++;
  1461. pcWildCard--;
  1462. if( PathLen == xIndex )
  1463. {
  1464. break;
  1465. }
  1466. }
  1467. }
  1468. pxDirEntry->ulDirCluster = FF_FindDir( pxIOManager, pcPath, PathLen - xIndex, &xError );
  1469. if( FF_isERR( xError ) == pdFALSE )
  1470. {
  1471. if( pxDirEntry->ulDirCluster != 0 )
  1472. {
  1473. /* Valid Dir found, copy the wildCard to filename! */
  1474. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  1475. wcsncpy( pxDirEntry->pcWildCard, ++pcWildCard, ffconfigMAX_FILENAME );
  1476. #else
  1477. strncpy( pxDirEntry->pcWildCard, ++pcWildCard, ffconfigMAX_FILENAME );
  1478. #endif
  1479. if( pxDirEntry->pcWildCard[ xIndex - 1 ] == ':' )
  1480. {
  1481. pxDirEntry->xInvertWildCard = pdTRUE;
  1482. pxDirEntry->pcWildCard[ xIndex - 1 ] = '\0';
  1483. }
  1484. }
  1485. }
  1486. }
  1487. #else /* ffconfigFINDAPI_ALLOW_WILDCARDS */
  1488. {
  1489. /* Get the directory cluster, if it exists. */
  1490. pxDirEntry->ulDirCluster = FF_FindDir( pxIOManager, pcPath, PathLen, &xError );
  1491. }
  1492. #endif /* ffconfigFINDAPI_ALLOW_WILDCARDS */
  1493. if( FF_isERR( xError ) == pdFALSE )
  1494. {
  1495. if( pxDirEntry->ulDirCluster == 0 )
  1496. {
  1497. xError = ( FF_Error_t ) ( FF_ERR_DIR_INVALID_PATH | FF_FINDFIRST );
  1498. }
  1499. else
  1500. {
  1501. /* Initialise the Fetch Context. */
  1502. xError = FF_InitEntryFetch( pxIOManager, pxDirEntry->ulDirCluster, &( pxDirEntry->xFetchContext ) );
  1503. if( FF_isERR( xError ) == pdFALSE )
  1504. {
  1505. pxDirEntry->usCurrentItem = 0;
  1506. xError = FF_FindNext( pxIOManager, pxDirEntry );
  1507. }
  1508. }
  1509. }
  1510. }
  1511. return xError;
  1512. } /* FF_FindFirst() */
  1513. /*-----------------------------------------------------------*/
  1514. /**
  1515. * @public
  1516. * @brief Get's the next Entry based on the data recorded in the FF_DirEnt_t object.
  1517. *
  1518. * All values recorded in pxDirEntry must be preserved to and between calls to
  1519. * FF_FindNext( ). Please see @see FF_FindFirst( ) for find initialisation.
  1520. *
  1521. * @param pxIOManager FF_IOManager_t object that was created by FF_CreateIOManger( ).
  1522. * @param pxDirEntry FF_DirEnt_t object to store the entry information. ( As initialised by FF_FindFirst( )).
  1523. *
  1524. * @Return FF_ERR_DEVICE_DRIVER_FAILED is device access failed.
  1525. *
  1526. **/
  1527. FF_Error_t FF_FindNext( FF_IOManager_t * pxIOManager,
  1528. FF_DirEnt_t * pxDirEntry )
  1529. {
  1530. FF_Error_t xError;
  1531. BaseType_t xLFNCount;
  1532. const uint8_t * pucEntryBuffer = NULL;
  1533. #if ( ffconfigFINDAPI_ALLOW_WILDCARDS != 0 )
  1534. BaseType_t b;
  1535. #endif
  1536. if( pxIOManager == NULL )
  1537. {
  1538. xError = ( FF_Error_t ) ( FF_ERR_NULL_POINTER | FF_FINDNEXT );
  1539. }
  1540. #if ( ffconfigREMOVABLE_MEDIA != 0 )
  1541. else if( ( pxIOManager->ucFlags & FF_IOMAN_DEVICE_IS_EXTRACTED ) != 0 )
  1542. {
  1543. xError = ( FF_Error_t ) ( FF_ERR_IOMAN_DRIVER_NOMEDIUM | FF_FINDNEXT );
  1544. }
  1545. #endif /* ffconfigREMOVABLE_MEDIA */
  1546. else
  1547. {
  1548. xError = FF_ERR_NONE;
  1549. for( ; pxDirEntry->usCurrentItem < FF_MAX_ENTRIES_PER_DIRECTORY; pxDirEntry->usCurrentItem++ )
  1550. {
  1551. if( ( pucEntryBuffer == NULL ) ||
  1552. ( pucEntryBuffer >= ( pxDirEntry->xFetchContext.pxBuffer->pucBuffer + ( pxIOManager->usSectorSize - FF_SIZEOF_DIRECTORY_ENTRY ) ) ) )
  1553. {
  1554. xError = FF_FetchEntryWithContext( pxIOManager, pxDirEntry->usCurrentItem, &( pxDirEntry->xFetchContext ), NULL );
  1555. if( FF_isERR( xError ) )
  1556. {
  1557. break;
  1558. }
  1559. if( pucEntryBuffer == NULL )
  1560. {
  1561. pucEntryBuffer = pxDirEntry->xFetchContext.pxBuffer->pucBuffer +
  1562. ( FF_SIZEOF_DIRECTORY_ENTRY * ( pxDirEntry->usCurrentItem % ( pxIOManager->usSectorSize / FF_SIZEOF_DIRECTORY_ENTRY ) ) );
  1563. }
  1564. else
  1565. {
  1566. pucEntryBuffer = pxDirEntry->xFetchContext.pxBuffer->pucBuffer;
  1567. }
  1568. }
  1569. else
  1570. {
  1571. pucEntryBuffer += FF_SIZEOF_DIRECTORY_ENTRY;
  1572. }
  1573. if( FF_isDeleted( pucEntryBuffer ) != pdFALSE )
  1574. {
  1575. /* The entry is not in use or deleted. */
  1576. continue;
  1577. }
  1578. if( FF_isEndOfDir( pucEntryBuffer ) )
  1579. {
  1580. /* End of directory, generate a pseudo error 'DIR_END_OF_DIR'. */
  1581. xError = ( FF_Error_t ) ( FF_ERR_DIR_END_OF_DIR | FF_FINDNEXT );
  1582. break;
  1583. }
  1584. pxDirEntry->ucAttrib = FF_getChar( pucEntryBuffer, ( uint16_t ) ( FF_FAT_DIRENT_ATTRIB ) );
  1585. if( ( pxDirEntry->ucAttrib & FF_FAT_ATTR_LFN ) == FF_FAT_ATTR_LFN )
  1586. {
  1587. /* LFN Processing. */
  1588. xLFNCount = ( BaseType_t ) ( pucEntryBuffer[ 0 ] & ~0x40 );
  1589. /* Get the shortname and check if it is marked deleted. */
  1590. #if ( ffconfigLFN_SUPPORT != 0 )
  1591. {
  1592. /* Reserve 32 bytes to hold one directory entry. */
  1593. uint8_t Buffer[ FF_SIZEOF_DIRECTORY_ENTRY ];
  1594. /* Fetch the shortname, and get it's checksum, or for a deleted item with
  1595. * orphaned LFN entries. */
  1596. xError = FF_FetchEntryWithContext( pxIOManager, ( uint32_t ) ( pxDirEntry->usCurrentItem + xLFNCount ), &pxDirEntry->xFetchContext, Buffer );
  1597. if( FF_isERR( xError ) )
  1598. {
  1599. break;
  1600. }
  1601. if( FF_isDeleted( Buffer ) == pdFALSE )
  1602. {
  1603. xError = FF_PopulateLongDirent( pxIOManager, pxDirEntry, pxDirEntry->usCurrentItem, &pxDirEntry->xFetchContext );
  1604. if( FF_isERR( xError ) )
  1605. {
  1606. break;
  1607. }
  1608. #if ( ffconfigINCLUDE_SHORT_NAME != 0 )
  1609. {
  1610. pxDirEntry->ucAttrib |= FF_FAT_ATTR_IS_LFN;
  1611. }
  1612. #endif
  1613. #if ( ffconfigFINDAPI_ALLOW_WILDCARDS != 0 )
  1614. {
  1615. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  1616. if( wcscmp( pxDirEntry->pcWildCard, L"" ) )
  1617. #else
  1618. if( pxDirEntry->pcWildCard[ 0 ] )
  1619. #endif
  1620. {
  1621. b = FF_wildcompare( pxDirEntry->pcWildCard, pxDirEntry->pcFileName );
  1622. if( pxDirEntry->xInvertWildCard != pdFALSE )
  1623. {
  1624. b = !b;
  1625. }
  1626. if( b != 0 )
  1627. {
  1628. break;
  1629. }
  1630. /* 'usCurrentItem' has already incremented by FF_PopulateLongDirent(),
  1631. * this loop will incremente it again. */
  1632. pxDirEntry->usCurrentItem -= 1;
  1633. /* xFetchContext/usCurrentItem have changed. Update
  1634. * 'pucEntryBuffer' to point to the current buffer position. */
  1635. pucEntryBuffer = pxDirEntry->xFetchContext.pxBuffer->pucBuffer +
  1636. ( FF_SIZEOF_DIRECTORY_ENTRY * ( pxDirEntry->usCurrentItem % ( pxIOManager->usSectorSize / FF_SIZEOF_DIRECTORY_ENTRY ) ) );
  1637. }
  1638. else
  1639. {
  1640. break;
  1641. }
  1642. }
  1643. #else /* ffconfigFINDAPI_ALLOW_WILDCARDS == 0 */
  1644. {
  1645. /* usCurrentItem has been incremented by FF_PopulateLongDirent().
  1646. * Entry will be returned. */
  1647. break;
  1648. }
  1649. #endif /* if ( ffconfigFINDAPI_ALLOW_WILDCARDS != 0 ) */
  1650. }
  1651. }
  1652. #else /* ffconfigLFN_SUPPORT */
  1653. {
  1654. /* Increment 'usCurrentItem' with (xLFNCount-1),
  1655. * the loop will do an extra increment. */
  1656. pxDirEntry->usCurrentItem += ( xLFNCount - 1 );
  1657. }
  1658. #endif /* ffconfigLFN_SUPPORT */
  1659. } /* ( ( pxDirEntry->ucAttrib & FF_FAT_ATTR_LFN ) == FF_FAT_ATTR_LFN ) */
  1660. else if( ( pxDirEntry->ucAttrib & FF_FAT_ATTR_VOLID ) != FF_FAT_ATTR_VOLID )
  1661. {
  1662. /* If it's not a LFN entry, neither a Volume ID, it is a normal short name entry. */
  1663. FF_PopulateShortDirent( pxIOManager, pxDirEntry, pucEntryBuffer );
  1664. #if ( ffconfigSHORTNAME_CASE != 0 )
  1665. {
  1666. /* Apply NT/XP+ bits to get correct case. */
  1667. FF_CaseShortName( pxDirEntry->pcFileName, FF_getChar( pucEntryBuffer, FF_FAT_CASE_OFFS ) );
  1668. }
  1669. #endif
  1670. #if ( ffconfigFINDAPI_ALLOW_WILDCARDS != 0 )
  1671. {
  1672. if( pxDirEntry->pcWildCard[ 0 ] )
  1673. {
  1674. b = FF_wildcompare( pxDirEntry->pcWildCard, pxDirEntry->pcFileName );
  1675. if( pxDirEntry->xInvertWildCard != pdFALSE )
  1676. {
  1677. b = !b;
  1678. }
  1679. if( b != 0 )
  1680. {
  1681. pxDirEntry->usCurrentItem += 1;
  1682. break;
  1683. }
  1684. }
  1685. else
  1686. {
  1687. pxDirEntry->usCurrentItem += 1;
  1688. break;
  1689. }
  1690. }
  1691. #else /* ffconfigFINDAPI_ALLOW_WILDCARDS */
  1692. {
  1693. pxDirEntry->usCurrentItem += 1;
  1694. break;
  1695. }
  1696. #endif /* if ( ffconfigFINDAPI_ALLOW_WILDCARDS != 0 ) */
  1697. }
  1698. } /* for ( ; pxDirEntry->usCurrentItem < FF_MAX_ENTRIES_PER_DIRECTORY; pxDirEntry->usCurrentItem++ ) */
  1699. if( pxDirEntry->usCurrentItem == FF_MAX_ENTRIES_PER_DIRECTORY )
  1700. {
  1701. xError = ( FF_Error_t ) ( FF_ERR_DIR_END_OF_DIR | FF_FINDNEXT );
  1702. }
  1703. {
  1704. FF_Error_t xTempError;
  1705. xTempError = FF_CleanupEntryFetch( pxIOManager, &pxDirEntry->xFetchContext );
  1706. if( FF_isERR( xError ) == pdFALSE )
  1707. {
  1708. xError = xTempError;
  1709. }
  1710. }
  1711. }
  1712. return xError;
  1713. } /* FF_FindNext() */
  1714. /*-----------------------------------------------------------*/
  1715. /*
  1716. * Returns >= 0 for a free dirent entry.
  1717. * Returns < 0 with and xError code if anything goes wrong.
  1718. */
  1719. static int32_t FF_FindFreeDirent( FF_IOManager_t * pxIOManager,
  1720. FF_FindParams_t * pxFindParams,
  1721. uint16_t usSequential )
  1722. {
  1723. const uint8_t * pucEntryBuffer = NULL;
  1724. uint16_t freeCount = 0;
  1725. UBaseType_t uxEntry = 0;
  1726. BaseType_t xEntryFound = pdFALSE;
  1727. FF_Error_t xError;
  1728. uint32_t DirLength;
  1729. FF_FetchContext_t xFetchContext;
  1730. uint32_t ulDirCluster = pxFindParams->ulDirCluster;
  1731. xError = FF_InitEntryFetch( pxIOManager, ulDirCluster, &xFetchContext );
  1732. if( FF_isERR( xError ) == pdFALSE )
  1733. {
  1734. uxEntry = pxFindParams->lFreeEntry >= 0 ? pxFindParams->lFreeEntry : 0;
  1735. for( ; uxEntry < FF_MAX_ENTRIES_PER_DIRECTORY; uxEntry++ )
  1736. {
  1737. if( ( pucEntryBuffer == NULL ) ||
  1738. ( pucEntryBuffer >= xFetchContext.pxBuffer->pucBuffer + ( pxIOManager->usSectorSize - FF_SIZEOF_DIRECTORY_ENTRY ) ) )
  1739. {
  1740. xError = FF_FetchEntryWithContext( pxIOManager, uxEntry, &xFetchContext, NULL );
  1741. if( FF_GETERROR( xError ) == FF_ERR_DIR_END_OF_DIR )
  1742. {
  1743. xError = FF_ExtendDirectory( pxIOManager, ulDirCluster );
  1744. /* The value of xEntryFound will be ignored in case there was an error. */
  1745. xEntryFound = pdTRUE;
  1746. break;
  1747. }
  1748. else if( FF_isERR( xError ) )
  1749. {
  1750. break;
  1751. }
  1752. if( pucEntryBuffer == NULL )
  1753. {
  1754. pucEntryBuffer = xFetchContext.pxBuffer->pucBuffer +
  1755. ( FF_SIZEOF_DIRECTORY_ENTRY * ( uxEntry % ( pxIOManager->usSectorSize / FF_SIZEOF_DIRECTORY_ENTRY ) ) );
  1756. }
  1757. else
  1758. {
  1759. pucEntryBuffer = xFetchContext.pxBuffer->pucBuffer;
  1760. }
  1761. }
  1762. else
  1763. {
  1764. /* Advance 32 bytes to point to the next directory entry. */
  1765. pucEntryBuffer += FF_SIZEOF_DIRECTORY_ENTRY;
  1766. }
  1767. if( FF_isEndOfDir( pucEntryBuffer ) ) /* If its the end of the Dir, then FreeDirents from here. */
  1768. {
  1769. /* Check if the directory has enough space */
  1770. DirLength = xFetchContext.ulChainLength;
  1771. if( ( uxEntry + usSequential ) >
  1772. ( ( DirLength * ( ( UBaseType_t ) pxIOManager->xPartition.ulSectorsPerCluster * pxIOManager->xPartition.usBlkSize ) ) / FF_SIZEOF_DIRECTORY_ENTRY ) )
  1773. {
  1774. xError = FF_ExtendDirectory( pxIOManager, ulDirCluster );
  1775. }
  1776. xEntryFound = pdTRUE;
  1777. break;
  1778. }
  1779. if( FF_isDeleted( pucEntryBuffer ) )
  1780. {
  1781. if( ++freeCount == usSequential )
  1782. {
  1783. xError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext );
  1784. xEntryFound = pdTRUE;
  1785. uxEntry = ( uxEntry - ( usSequential - 1 ) ); /* Return the beginning entry in the sequential sequence. */
  1786. break;
  1787. }
  1788. }
  1789. else
  1790. {
  1791. freeCount = 0;
  1792. }
  1793. } /* for ( uxEntry = 0; uxEntry < FF_MAX_ENTRIES_PER_DIRECTORY; uxEntry++ ) */
  1794. {
  1795. FF_Error_t xTempError;
  1796. xTempError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext );
  1797. if( FF_isERR( xError ) == pdFALSE )
  1798. {
  1799. xError = xTempError;
  1800. }
  1801. }
  1802. }
  1803. if( FF_isERR( xError ) == pdFALSE )
  1804. {
  1805. if( xEntryFound != pdFALSE )
  1806. {
  1807. /* No error has occurred and a free directory entry has been found. */
  1808. xError = uxEntry;
  1809. }
  1810. else
  1811. {
  1812. xError = ( FF_Error_t ) ( FF_ERR_DIR_DIRECTORY_FULL | FF_FINDFREEDIRENT );
  1813. }
  1814. }
  1815. return xError;
  1816. } /* FF_FindFreeDirent() */
  1817. /*-----------------------------------------------------------*/
  1818. /* _HT_ Now FF_PutEntry has a new optional parameter *pucContents */
  1819. /* _HT_ so it can be used FF_MkDir( ) to save some code when adding . and .. entries */
  1820. FF_Error_t FF_PutEntry( FF_IOManager_t * pxIOManager,
  1821. uint16_t usEntry,
  1822. uint32_t ulDirCluster,
  1823. FF_DirEnt_t * pxDirEntry,
  1824. uint8_t * pucContents )
  1825. {
  1826. FF_Error_t xError;
  1827. /* Reserve 32 bytes to hold one directory entry. */
  1828. uint8_t pucEntryBuffer[ FF_SIZEOF_DIRECTORY_ENTRY ];
  1829. FF_FetchContext_t xFetchContext;
  1830. /* HT: use the standard access routine to get the same logic for root dirs. */
  1831. xError = FF_InitEntryFetch( pxIOManager, ulDirCluster, &xFetchContext );
  1832. if( FF_isERR( xError ) == pdFALSE )
  1833. {
  1834. xError = FF_FetchEntryWithContext( pxIOManager, usEntry, &xFetchContext, pucEntryBuffer );
  1835. if( FF_isERR( xError ) == pdFALSE )
  1836. {
  1837. /* Cleanup probably not necessary here?
  1838. * FF_PushEntryWithContext checks for R/W flag. */
  1839. xError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext );
  1840. if( FF_isERR( xError ) == pdFALSE )
  1841. {
  1842. if( pucContents != NULL )
  1843. {
  1844. memcpy( pucEntryBuffer, pucContents, sizeof( pucEntryBuffer ) );
  1845. }
  1846. FF_putChar( pucEntryBuffer, FF_FAT_DIRENT_ATTRIB, ( uint32_t ) pxDirEntry->ucAttrib );
  1847. FF_putShort( pucEntryBuffer, FF_FAT_DIRENT_CLUS_HIGH, ( uint32_t ) ( pxDirEntry->ulObjectCluster >> 16 ) );
  1848. FF_putShort( pucEntryBuffer, FF_FAT_DIRENT_CLUS_LOW, ( uint32_t ) ( pxDirEntry->ulObjectCluster ) );
  1849. FF_putLong( pucEntryBuffer, FF_FAT_DIRENT_FILESIZE, pxDirEntry->ulFileSize );
  1850. #if ( ffconfigTIME_SUPPORT != 0 )
  1851. {
  1852. FF_GetSystemTime( &pxDirEntry->xAccessedTime ); /*/< Date of Last Access. */
  1853. FF_PlaceTime( pucEntryBuffer, FF_FAT_DIRENT_LASTACC_DATE, &pxDirEntry->xAccessedTime );
  1854. FF_PlaceDate( pucEntryBuffer, FF_FAT_DIRENT_LASTACC_DATE, &pxDirEntry->xAccessedTime ); /* Last accessed date. */
  1855. FF_PlaceTime( pucEntryBuffer, FF_FAT_DIRENT_CREATE_TIME, &pxDirEntry->xCreateTime );
  1856. FF_PlaceDate( pucEntryBuffer, FF_FAT_DIRENT_CREATE_DATE, &pxDirEntry->xCreateTime );
  1857. FF_PlaceTime( pucEntryBuffer, FF_FAT_DIRENT_LASTMOD_TIME, &pxDirEntry->xModifiedTime );
  1858. FF_PlaceDate( pucEntryBuffer, FF_FAT_DIRENT_LASTMOD_DATE, &pxDirEntry->xModifiedTime );
  1859. }
  1860. #endif /* ffconfigTIME_SUPPORT */
  1861. xError = FF_PushEntryWithContext( pxIOManager, usEntry, &xFetchContext, pucEntryBuffer );
  1862. }
  1863. }
  1864. }
  1865. FF_CleanupEntryFetch( pxIOManager, &xFetchContext );
  1866. return xError;
  1867. } /* FF_PutEntry() */
  1868. /*-----------------------------------------------------------*/
  1869. static BaseType_t FF_ValidShortChar( char cChar )
  1870. {
  1871. return ( cChar >= 'A' && cChar <= 'Z' ) ||
  1872. ( cChar >= 'a' && cChar <= 'z' ) || /* lower-case can be stored using NT/XP attribute. */
  1873. ( cChar >= '0' && cChar <= '9' ) ||
  1874. strchr( "$%-_@~`!(){}^#&", cChar ) != NULL;
  1875. } /* FF_ValidShortChar() */
  1876. /*-----------------------------------------------------------*/
  1877. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  1878. void FF_CreateShortName( FF_FindParams_t * pxFindParams,
  1879. const FF_T_WCHAR * pcLongName )
  1880. #else
  1881. void FF_CreateShortName( FF_FindParams_t * pxFindParams,
  1882. const char * pcLongName )
  1883. #endif
  1884. {
  1885. BaseType_t xIndex, xPosition, xLastDot;
  1886. uint16_t NameLen;
  1887. #if ( ffconfigSHORTNAME_CASE != 0 )
  1888. uint8_t testAttrib = FF_FAT_CASE_ATTR_BASE;
  1889. #endif
  1890. /* Examples:
  1891. * "readme.TXT" will get the attribute FF_FAT_CASE_ATTR_BASE
  1892. * "README.txt" will get the attribute FF_FAT_CASE_ATTR_EXT
  1893. * "Readme.txt" can not be store as a short name */
  1894. pxFindParams->ucCaseAttrib = 0; /* May get the value FF_FAT_CASE_ATTR_BASE or FF_FAT_CASE_ATTR_EXT */
  1895. pxFindParams->ucFirstTilde = 6; /* The numerical position of the ~ */
  1896. pxFindParams->ulFlags |= FIND_FLAG_SHORTNAME_SET | FIND_FLAG_FITS_SHORT | FIND_FLAG_SIZE_OK;
  1897. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  1898. {
  1899. NameLen = ( uint16_t ) wcslen( pcLongName );
  1900. }
  1901. #else
  1902. {
  1903. NameLen = ( uint16_t ) strlen( pcLongName );
  1904. }
  1905. #endif
  1906. /* Does pcLongName fit a shortname? */
  1907. for( xIndex = 0, xPosition = 0, xLastDot = NameLen; xIndex < NameLen; xIndex++ )
  1908. {
  1909. if( pcLongName[ xIndex ] != '.' )
  1910. {
  1911. xPosition++;
  1912. }
  1913. else
  1914. {
  1915. xLastDot = xIndex;
  1916. }
  1917. }
  1918. /* For example:
  1919. * "FILENAME.EXT": NameLen = 12, xLastDot = 8, xPosition = 11
  1920. * ".cproject" : NameLen = 9, xLastDot = 0, xPosition = 8
  1921. */
  1922. if( ( NameLen > 12 ) || /* If name is longer than 12 characters (8.3). */
  1923. ( NameLen - xPosition > 1 ) || /* If it contains more than 1 dot. */
  1924. ( NameLen - xLastDot > 4 ) || /* If the file name extension is longer than 3 characters. */
  1925. ( xLastDot > 8 ) ) /* If the file name base is too long. */
  1926. {
  1927. pxFindParams->ulFlags &= ~FIND_FLAG_SIZE_OK;
  1928. }
  1929. for( xIndex = 0, xPosition = 0; xIndex < 11; xPosition++ )
  1930. {
  1931. char ch = pcLongName[ xPosition ];
  1932. if( !ch )
  1933. {
  1934. break;
  1935. }
  1936. if( ( xIndex == 0 ) && ( ch == '.' ) )
  1937. {
  1938. pxFindParams->ulFlags &= ~FIND_FLAG_FITS_SHORT;
  1939. continue;
  1940. }
  1941. if( xPosition == xLastDot )
  1942. {
  1943. /* Remember where we put the first space. */
  1944. if( pxFindParams->ucFirstTilde > xIndex )
  1945. {
  1946. pxFindParams->ucFirstTilde = xIndex;
  1947. }
  1948. while( xIndex < 8 )
  1949. {
  1950. pxFindParams->pcEntryBuffer[ xIndex++ ] = 0x20;
  1951. }
  1952. #if ( ffconfigSHORTNAME_CASE != 0 )
  1953. {
  1954. testAttrib = FF_FAT_CASE_ATTR_EXT;
  1955. }
  1956. #endif
  1957. }
  1958. else
  1959. {
  1960. if( xIndex == 8 )
  1961. {
  1962. if( xPosition <= xLastDot )
  1963. {
  1964. xPosition = xLastDot;
  1965. ch = ( int8_t ) pcLongName[ xPosition ];
  1966. if( ch == '\0' )
  1967. {
  1968. break;
  1969. }
  1970. ch = ( int8_t ) pcLongName[ ++xPosition ];
  1971. #if ( ffconfigSHORTNAME_CASE != 0 )
  1972. {
  1973. testAttrib = FF_FAT_CASE_ATTR_EXT;
  1974. }
  1975. #endif
  1976. }
  1977. }
  1978. if( !FF_ValidShortChar( ch ) )
  1979. {
  1980. pxFindParams->ulFlags &= ~FIND_FLAG_FITS_SHORT;
  1981. continue;
  1982. }
  1983. #if ( ffconfigSHORTNAME_CASE != 0 )
  1984. {
  1985. if( ( ch >= 'a' ) && ( ch <= 'z' ) )
  1986. {
  1987. ch -= 0x20;
  1988. if( testAttrib )
  1989. {
  1990. pxFindParams->ucCaseAttrib |= testAttrib;
  1991. }
  1992. else
  1993. {
  1994. pxFindParams->ulFlags &= ~FIND_FLAG_FITS_SHORT; /* We had capital: does not fit. */
  1995. }
  1996. }
  1997. else if( ( ch >= 'A' ) && ( ch <= 'Z' ) )
  1998. {
  1999. if( ( pxFindParams->ucCaseAttrib & testAttrib ) != 0 )
  2000. {
  2001. pxFindParams->ulFlags &= ~FIND_FLAG_FITS_SHORT; /* We had lower-case: does not fit. */
  2002. }
  2003. testAttrib = 0;
  2004. }
  2005. }
  2006. #else /* if ( ffconfigSHORTNAME_CASE != 0 ) */
  2007. {
  2008. if( ( ch >= 'a' ) && ( ch <= 'z' ) )
  2009. {
  2010. ch -= 0x20;
  2011. }
  2012. }
  2013. #endif /* ffconfigSHORTNAME_CASE */
  2014. pxFindParams->pcEntryBuffer[ xIndex++ ] = ch;
  2015. }
  2016. }
  2017. if( ( xLastDot == 0 ) && ( xIndex < 6 ) )
  2018. {
  2019. /* This is a file name like ".info" or ".root" */
  2020. pxFindParams->ucFirstTilde = xIndex;
  2021. }
  2022. while( xIndex < 11 )
  2023. {
  2024. pxFindParams->pcEntryBuffer[ xIndex++ ] = 0x20;
  2025. }
  2026. if( ( xLastDot < pxFindParams->ucFirstTilde ) && ( xLastDot > 0 ) )
  2027. {
  2028. pxFindParams->ucFirstTilde = xLastDot;
  2029. }
  2030. if( NameLen < pxFindParams->ucFirstTilde ) /* Names like "Abc" will become "~Abc". */
  2031. {
  2032. pxFindParams->ucFirstTilde = ( uint8_t ) NameLen;
  2033. }
  2034. } /* FF_CreateShortName() */
  2035. /*-----------------------------------------------------------*/
  2036. int32_t FF_FindShortName( FF_IOManager_t * pxIOManager,
  2037. FF_FindParams_t * pxFindParams )
  2038. {
  2039. char pcMyShortName[ 13 ];
  2040. FF_DirEnt_t xMyDirectory;
  2041. FF_Error_t xResult = 0;
  2042. BaseType_t xIndex, x, y;
  2043. uint16_t NameLen;
  2044. char pcNumberBuf[ 12 ];
  2045. uint32_t ulCluster;
  2046. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  2047. FF_T_WCHAR pcFileName[ 13 ];
  2048. #else
  2049. char * pcFileName = pcMyShortName;
  2050. #endif /* ffconfigUNICODE_UTF16_SUPPORT */
  2051. #if ( ipconfigQUICK_SHORT_FILENAME_CREATION != 0 )
  2052. uint16_t usShortHash;
  2053. uint32_t ulRand = 0ul;
  2054. #endif
  2055. memcpy( pcMyShortName, pxFindParams->pcEntryBuffer, 11 );
  2056. FF_ProcessShortName( pcMyShortName );
  2057. if( ( pxFindParams->ulFlags & FIND_FLAG_FITS_SHORT_OK ) == FIND_FLAG_FITS_SHORT_OK )
  2058. {
  2059. /* This entry will not get a LFN entry because it fits
  2060. * perfectly into a host name */
  2061. if( ( pxFindParams->ulFlags & FIND_FLAG_SHORTNAME_CHECKED ) != 0 )
  2062. {
  2063. if( ( pxFindParams->ulFlags & FIND_FLAG_SHORTNAME_FOUND ) != 0 )
  2064. {
  2065. xResult = ( FF_Error_t ) ( FF_ERR_DIR_OBJECT_EXISTS | FF_CREATESHORTNAME );
  2066. }
  2067. else
  2068. {
  2069. xResult = pxFindParams->ucCaseAttrib | 0x01;
  2070. }
  2071. }
  2072. else
  2073. {
  2074. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  2075. {
  2076. memcpy( pcFileName, pcMyShortName, sizeof( pcMyShortName ) );
  2077. FF_ShortNameExpand( pcFileName );
  2078. }
  2079. #endif
  2080. ulCluster = FF_FindEntryInDir( pxIOManager, pxFindParams, pcFileName, 0x00, &xMyDirectory, &xResult );
  2081. /* END_OF_DIR is not a fatal error, it only means that the entry was not found. */
  2082. if( ( FF_isERR( xResult ) == pdFALSE ) || ( FF_GETERROR( xResult ) == FF_ERR_DIR_END_OF_DIR ) )
  2083. {
  2084. if( ulCluster == 0UL )
  2085. {
  2086. xResult = pxFindParams->ucCaseAttrib | 0x01;
  2087. }
  2088. else
  2089. {
  2090. xResult = ( FF_Error_t ) ( FF_ERR_DIR_OBJECT_EXISTS | FF_CREATESHORTNAME );
  2091. }
  2092. }
  2093. else
  2094. {
  2095. /* There was an error, which will be returned. */
  2096. }
  2097. }
  2098. }
  2099. else
  2100. {
  2101. for( xIndex = ( ( pxFindParams->ulFlags & FIND_FLAG_SIZE_OK ) ? 0 : 1 ); ; xIndex++ )
  2102. {
  2103. if( xIndex != 0 )
  2104. {
  2105. #if ( ipconfigQUICK_SHORT_FILENAME_CREATION != 0 )
  2106. {
  2107. /* In the first round, check if the original name can be used
  2108. * Makefile will be stored as "makefile" and not as "makefi~1". */
  2109. /* This method saves a lot of time when creating directories with
  2110. * many similar file names: when the short name version of a LFN already
  2111. * exists, try at most 3 entries with a tilde:
  2112. * README~1.TXT
  2113. * README~2.TXT
  2114. * README~3.TXT
  2115. * After that create entries with pseudo-random 4-digit hex digits:
  2116. * REA~E7BB.TXT
  2117. * REA~BA32.TXT
  2118. * REA~D394.TXT
  2119. */
  2120. if( xIndex <= 4 )
  2121. {
  2122. snprintf( pcNumberBuf, sizeof( pcNumberBuf ), "%d", ( int ) xIndex );
  2123. }
  2124. else
  2125. {
  2126. if( ulRand == 0ul )
  2127. {
  2128. ulRand = pxIOManager->xPartition.ulLastFreeCluster;
  2129. usShortHash = FF_GetCRC16( ( uint8_t * ) &ulRand, sizeof( ulRand ) );
  2130. }
  2131. else
  2132. {
  2133. usShortHash = FF_GetCRC16( ( uint8_t * ) &usShortHash, sizeof( usShortHash ) );
  2134. }
  2135. snprintf( pcNumberBuf, sizeof( pcNumberBuf ), "%04X", ( int ) usShortHash );
  2136. }
  2137. }
  2138. #else /* if ( ipconfigQUICK_SHORT_FILENAME_CREATION != 0 ) */
  2139. {
  2140. snprintf( pcNumberBuf, sizeof( pcNumberBuf ), "%d", ( int ) xIndex );
  2141. }
  2142. #endif /* if ( ipconfigQUICK_SHORT_FILENAME_CREATION != 0 ) */
  2143. NameLen = ( uint16_t ) strlen( pcNumberBuf );
  2144. x = 7 - NameLen;
  2145. if( x > pxFindParams->ucFirstTilde )
  2146. {
  2147. x = pxFindParams->ucFirstTilde;
  2148. }
  2149. pxFindParams->pcEntryBuffer[ x++ ] = '~';
  2150. for( y = 0; y < NameLen; y++ )
  2151. {
  2152. pxFindParams->pcEntryBuffer[ x + y ] = pcNumberBuf[ y ];
  2153. }
  2154. }
  2155. memcpy( pcMyShortName, pxFindParams->pcEntryBuffer, 11 );
  2156. FF_ProcessShortName( pcMyShortName );
  2157. if( FF_ShortNameExists( pxIOManager, pxFindParams->ulDirCluster, pcMyShortName, &xResult ) == pdFALSE )
  2158. {
  2159. break;
  2160. }
  2161. if( xIndex >= FF_MAX_ENTRIES_PER_DIRECTORY )
  2162. {
  2163. xResult = ( FF_Error_t ) ( FF_ERR_DIR_DIRECTORY_FULL | FF_CREATESHORTNAME );
  2164. break;
  2165. }
  2166. }
  2167. /* Add a tail and special number until we're happy :D. */
  2168. }
  2169. return xResult;
  2170. } /* FF_FindShortName () */
  2171. /*-----------------------------------------------------------*/
  2172. #if ( ffconfigLFN_SUPPORT != 0 )
  2173. static int8_t FF_CreateLFNEntry( uint8_t * pucEntryBuffer,
  2174. uint8_t * pcName,
  2175. UBaseType_t uxNameLength,
  2176. UBaseType_t uxLFN,
  2177. uint8_t ucCheckSum )
  2178. {
  2179. /*
  2180. * HT for JW:
  2181. * Changed *pcName from 16- to of 8-bits
  2182. * The caller of this function doesn't need an expensive
  2183. * uint16_t usUtf16Name[ffconfigMAX_FILENAME + 1];
  2184. * in case UNICODE isn't used
  2185. * Also did quite a bit of optimisation here
  2186. * and tested well
  2187. */
  2188. UBaseType_t uxIndex, x;
  2189. memset( pucEntryBuffer, 0, FF_SIZEOF_DIRECTORY_ENTRY );
  2190. FF_putChar( pucEntryBuffer, FF_FAT_LFN_ORD, ( uint8_t ) ( ( uxLFN & ~0x40 ) ) );
  2191. FF_putChar( pucEntryBuffer, FF_FAT_DIRENT_ATTRIB, ( uint8_t ) FF_FAT_ATTR_LFN );
  2192. FF_putChar( pucEntryBuffer, FF_FAT_LFN_CHECKSUM, ( uint8_t ) ucCheckSum );
  2193. /* Name_1. */
  2194. uxIndex = 0;
  2195. for( x = FF_FAT_LFN_NAME_1; uxIndex < 5u; uxIndex++, x += 2 )
  2196. {
  2197. if( uxIndex < uxNameLength )
  2198. {
  2199. pucEntryBuffer[ x ] = *( pcName++ );
  2200. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 ) || ( ffconfigUNICODE_UTF8_SUPPORT != 0 )
  2201. {
  2202. pucEntryBuffer[ x + 1 ] = *( pcName++ );
  2203. }
  2204. #endif
  2205. }
  2206. else if( uxIndex > uxNameLength )
  2207. {
  2208. pucEntryBuffer[ x ] = 0xFF;
  2209. pucEntryBuffer[ x + 1 ] = 0xFF;
  2210. }
  2211. }
  2212. /* Name_2. */
  2213. for( x = FF_FAT_LFN_NAME_2; uxIndex < 11u; uxIndex++, x += 2 )
  2214. {
  2215. if( uxIndex < uxNameLength )
  2216. {
  2217. pucEntryBuffer[ x ] = *( pcName++ );
  2218. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 ) || ( ffconfigUNICODE_UTF8_SUPPORT != 0 )
  2219. {
  2220. pucEntryBuffer[ x + 1 ] = *( pcName++ );
  2221. }
  2222. #endif
  2223. }
  2224. else if( uxIndex > uxNameLength )
  2225. {
  2226. pucEntryBuffer[ x ] = 0xFF;
  2227. pucEntryBuffer[ x + 1 ] = 0xFF;
  2228. }
  2229. }
  2230. /* Name_3. */
  2231. for( x = FF_FAT_LFN_NAME_3; uxIndex < 13u; uxIndex++, x += 2 )
  2232. {
  2233. if( uxIndex < uxNameLength )
  2234. {
  2235. pucEntryBuffer[ x ] = *( pcName++ );
  2236. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 ) || ( ffconfigUNICODE_UTF8_SUPPORT != 0 )
  2237. {
  2238. pucEntryBuffer[ x + 1 ] = *( pcName++ );
  2239. }
  2240. #endif
  2241. }
  2242. else if( uxIndex > uxNameLength )
  2243. {
  2244. pucEntryBuffer[ x ] = 0xFF;
  2245. pucEntryBuffer[ x + 1 ] = 0xFF;
  2246. }
  2247. }
  2248. return FF_ERR_NONE;
  2249. } /* FF_CreateLFNEntry() */
  2250. #endif /* ffconfigLFN_SUPPORT */
  2251. /*-----------------------------------------------------------*/
  2252. #if ( ffconfigLFN_SUPPORT != 0 )
  2253. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  2254. static FF_Error_t FF_CreateLFNs( FF_IOManager_t * pxIOManager,
  2255. uint32_t ulDirCluster,
  2256. FF_T_WCHAR * pcName,
  2257. uint8_t ucCheckSum,
  2258. uint16_t usEntry )
  2259. #else
  2260. static FF_Error_t FF_CreateLFNs( FF_IOManager_t * pxIOManager,
  2261. uint32_t ulDirCluster,
  2262. char * pcName,
  2263. uint8_t ucCheckSum,
  2264. uint16_t usEntry )
  2265. #endif /* if ( ffconfigUNICODE_UTF16_SUPPORT != 0 ) */
  2266. {
  2267. FF_Error_t xError = FF_ERR_NONE;
  2268. BaseType_t xNumLFNs;
  2269. BaseType_t xEndPos;
  2270. BaseType_t xIndex, y;
  2271. FF_FetchContext_t xFetchContext;
  2272. uint8_t pucEntryBuffer[ FF_SIZEOF_DIRECTORY_ENTRY ];
  2273. #if ( ffconfigUNICODE_UTF8_SUPPORT != 0 )
  2274. int32_t slRetVal;
  2275. #endif
  2276. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 ) || ( ffconfigUNICODE_UTF8_SUPPORT != 0 )
  2277. uint16_t usUtf16Name[ ffconfigMAX_FILENAME + 1 ];
  2278. #endif
  2279. #if ( ffconfigUNICODE_UTF16_SUPPORT == 0 )
  2280. char * NamePtr;
  2281. #else
  2282. int16_t * NamePtr;
  2283. #endif
  2284. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  2285. {
  2286. #if WCHAR_MAX <= 0xFFFF
  2287. {
  2288. y = wcslen( pcName );
  2289. if( y > ffconfigMAX_FILENAME )
  2290. {
  2291. xError = ( FF_Error_t ) ( FF_ERR_DIR_NAME_TOO_LONG | FF_CREATELFNS );
  2292. }
  2293. else
  2294. {
  2295. wcsncpy( usUtf16Name, pcName, ffconfigMAX_FILENAME );
  2296. }
  2297. }
  2298. #else /* if WCHAR_MAX <= 0xFFFF */
  2299. {
  2300. xIndex = 0;
  2301. y = 0;
  2302. while( pcName[ xIndex ] )
  2303. {
  2304. FF_Utf32ctoUtf16c( &usUtf16Name[ y ], ( uint32_t ) pcName[ xIndex ], ffconfigMAX_FILENAME - xIndex );
  2305. y += FF_GetUtf16SequenceLen( usUtf16Name[ y ] );
  2306. xIndex++;
  2307. if( y > ffconfigMAX_FILENAME )
  2308. {
  2309. xError = ( FF_Error_t ) ( FF_ERR_DIR_NAME_TOO_LONG | FF_CREATELFNS );
  2310. break;
  2311. }
  2312. }
  2313. }
  2314. #endif /* if WCHAR_MAX <= 0xFFFF */
  2315. }
  2316. #endif /* ffconfigUNICODE_UTF16_SUPPORT */
  2317. /* Convert the name into UTF-16 format. */
  2318. #if ( ffconfigUNICODE_UTF8_SUPPORT != 0 )
  2319. {
  2320. /* Simply convert the UTF8 to UTF16 and be done with it. */
  2321. xIndex = 0;
  2322. y = 0;
  2323. while( pcName[ xIndex ] != 0 )
  2324. {
  2325. slRetVal = FF_Utf8ctoUtf16c( &( usUtf16Name[ y ] ), ( uint8_t * ) &( pcName[ xIndex ] ), ffconfigMAX_FILENAME - xIndex );
  2326. if( slRetVal > 0 )
  2327. {
  2328. xIndex += slRetVal;
  2329. }
  2330. else
  2331. {
  2332. break; /* No more space in the UTF-16 buffer, simply truncate for safety. */
  2333. }
  2334. y += FF_GetUtf16SequenceLen( usUtf16Name[ y ] );
  2335. if( y > ffconfigMAX_FILENAME )
  2336. {
  2337. xError = ( FF_Error_t ) ( FF_ERR_DIR_NAME_TOO_LONG | FF_CREATELFNS );
  2338. break;
  2339. }
  2340. }
  2341. }
  2342. #elif ( ffconfigUNICODE_UTF16_SUPPORT == 0 )
  2343. {
  2344. /* Just check the length. */
  2345. y = strlen( pcName );
  2346. if( y > ffconfigMAX_FILENAME )
  2347. {
  2348. xError = ( FF_Error_t ) ( FF_ERR_DIR_NAME_TOO_LONG | FF_CREATELFNS );
  2349. }
  2350. }
  2351. #endif /* if ( ffconfigUNICODE_UTF8_SUPPORT != 0 ) */
  2352. /* Whole name is now in a valid UTF-16 format. Lets go make thos LFN's.
  2353. * At this point, it should a be the length of the name. */
  2354. if( FF_isERR( xError ) == pdFALSE )
  2355. {
  2356. xNumLFNs = y / 13; /* Number of LFNs is the total number of UTF-16 units, divided by 13 ( 13 units per LFN ). */
  2357. xEndPos = y % 13; /* The ending position in an LFN, of the last LFN UTF-16 character. */
  2358. if( xEndPos )
  2359. {
  2360. xNumLFNs++;
  2361. }
  2362. else
  2363. {
  2364. xEndPos = 13;
  2365. }
  2366. xError = FF_InitEntryFetch( pxIOManager, ulDirCluster, &xFetchContext );
  2367. if( FF_isERR( xError ) == pdFALSE )
  2368. {
  2369. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  2370. {
  2371. NamePtr = ( int16_t * ) ( usUtf16Name + 13 * ( xNumLFNs - 1 ) );
  2372. }
  2373. #elif ( ffconfigUNICODE_UTF8_SUPPORT != 0 )
  2374. {
  2375. NamePtr = ( char * ) ( usUtf16Name + 13 * ( xNumLFNs - 1 ) );
  2376. }
  2377. #else
  2378. {
  2379. NamePtr = pcName + 13 * ( xNumLFNs - 1 );
  2380. }
  2381. #endif /* if ( ffconfigUNICODE_UTF16_SUPPORT != 0 ) */
  2382. /* After this point, xIndex is no longer the length of the Filename in UTF-16 units. */
  2383. for( xIndex = xNumLFNs; xIndex > 0; xIndex-- )
  2384. {
  2385. if( xIndex == xNumLFNs )
  2386. {
  2387. FF_CreateLFNEntry( pucEntryBuffer, ( uint8_t * ) NamePtr, ( UBaseType_t ) xEndPos, ( UBaseType_t ) xIndex, ucCheckSum );
  2388. pucEntryBuffer[ 0 ] |= 0x40;
  2389. }
  2390. else
  2391. {
  2392. FF_CreateLFNEntry( pucEntryBuffer, ( uint8_t * ) NamePtr, ( UBaseType_t ) 13u, ( UBaseType_t ) xIndex, ucCheckSum );
  2393. }
  2394. NamePtr -= 13;
  2395. xError = FF_PushEntryWithContext( pxIOManager, ( uint32_t ) ( usEntry + ( xNumLFNs - xIndex ) ), &xFetchContext, pucEntryBuffer );
  2396. if( FF_isERR( xError ) )
  2397. {
  2398. break;
  2399. }
  2400. }
  2401. {
  2402. FF_Error_t xTempError;
  2403. /* Release any buffers that were used. */
  2404. xTempError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext );
  2405. if( FF_isERR( xTempError ) == pdFALSE )
  2406. {
  2407. xError = xTempError;
  2408. }
  2409. }
  2410. }
  2411. }
  2412. return xError;
  2413. } /* FF_CreateLFNs() */
  2414. #endif /* ffconfigLFN_SUPPORT */
  2415. /*-----------------------------------------------------------*/
  2416. FF_Error_t FF_ExtendDirectory( FF_IOManager_t * pxIOManager,
  2417. uint32_t ulDirCluster )
  2418. {
  2419. uint32_t xCurrentCluster;
  2420. uint32_t xNextCluster = 0UL;
  2421. FF_Error_t xError = FF_ERR_NONE;
  2422. FF_FATBuffers_t xFATBuffers;
  2423. if( ( ulDirCluster == pxIOManager->xPartition.ulRootDirCluster ) &&
  2424. ( pxIOManager->xPartition.ucType != FF_T_FAT32 ) )
  2425. {
  2426. /* root directories on FAT12 and FAT16 can not be extended. */
  2427. xError = ( FF_Error_t ) ( FF_ERR_DIR_CANT_EXTEND_ROOT_DIR | FF_EXTENDDIRECTORY );
  2428. }
  2429. else if( pxIOManager->xPartition.ulFreeClusterCount == 0UL )
  2430. {
  2431. /* The number of free clusters was not yet calculated or equal to zero. */
  2432. pxIOManager->xPartition.ulFreeClusterCount = FF_CountFreeClusters( pxIOManager, &xError );
  2433. }
  2434. if( FF_isERR( xError ) == pdFALSE )
  2435. {
  2436. if( pxIOManager->xPartition.ulFreeClusterCount == 0UL )
  2437. {
  2438. xError = ( FF_Error_t ) ( FF_ERR_FAT_NO_FREE_CLUSTERS | FF_EXTENDDIRECTORY );
  2439. }
  2440. else
  2441. {
  2442. FF_LockFAT( pxIOManager );
  2443. {
  2444. xCurrentCluster = FF_FindEndOfChain( pxIOManager, ulDirCluster, &xError );
  2445. if( FF_isERR( xError ) == pdFALSE )
  2446. {
  2447. xNextCluster = FF_FindFreeCluster( pxIOManager, &xError, pdTRUE );
  2448. if( FF_isERR( xError ) == pdFALSE )
  2449. {
  2450. FF_InitFATBuffers( &xFATBuffers, FF_MODE_WRITE );
  2451. /* xNextCluster already has been set to 0xFFFFFFFF,
  2452. * now let xCurrentCluster point to xNextCluster. */
  2453. xError = FF_putFATEntry( pxIOManager, xCurrentCluster, xNextCluster, &xFATBuffers );
  2454. {
  2455. FF_Error_t xTempError;
  2456. xTempError = FF_ReleaseFATBuffers( pxIOManager, &xFATBuffers );
  2457. if( FF_isERR( xError ) == pdFALSE )
  2458. {
  2459. xError = xTempError;
  2460. }
  2461. xTempError = FF_DecreaseFreeClusters( pxIOManager, 1 );
  2462. if( FF_isERR( xError ) == pdFALSE )
  2463. {
  2464. xError = xTempError;
  2465. }
  2466. }
  2467. }
  2468. }
  2469. }
  2470. FF_UnlockFAT( pxIOManager );
  2471. if( FF_isERR( xError ) == pdFALSE )
  2472. {
  2473. /* The entire cluster will be filled with zero's,
  2474. * because it will contain directory data. */
  2475. xError = FF_ClearCluster( pxIOManager, xNextCluster );
  2476. }
  2477. }
  2478. }
  2479. return xError;
  2480. } /* FF_ExtendDirectory() */
  2481. /*-----------------------------------------------------------*/
  2482. static const uint8_t forbiddenChrs[] =
  2483. {
  2484. /* Windows says: don't use these characters: '\/:*?"<>|'
  2485. * " * / : < > ? '\' ? | */
  2486. 0x22, 0x2A, 0x2F, 0x3A, 0x3C, 0x3E, 0x3F, 0x5C, 0x7F, 0x7C
  2487. };
  2488. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  2489. static void FF_MakeNameCompliant( FF_T_WCHAR * pcName )
  2490. #else
  2491. static void FF_MakeNameCompliant( char * pcName )
  2492. #endif
  2493. {
  2494. BaseType_t index;
  2495. if( ( uint8_t ) pcName[ 0 ] == FF_FAT_DELETED ) /* Support Japanese KANJI symbol0xE5. */
  2496. {
  2497. pcName[ 0 ] = 0x05;
  2498. }
  2499. for( ; *pcName; pcName++ )
  2500. {
  2501. for( index = 0; index < ( BaseType_t ) sizeof( forbiddenChrs ); index++ )
  2502. {
  2503. if( *pcName == forbiddenChrs[ index ] )
  2504. {
  2505. *pcName = '_';
  2506. break;
  2507. }
  2508. }
  2509. }
  2510. } /* FF_MakeNameCompliant() */
  2511. /*-----------------------------------------------------------*/
  2512. FF_Error_t FF_CreateDirent( FF_IOManager_t * pxIOManager,
  2513. FF_FindParams_t * pxFindParams,
  2514. FF_DirEnt_t * pxDirEntry )
  2515. {
  2516. uint8_t pucEntryBuffer[ FF_SIZEOF_DIRECTORY_ENTRY ];
  2517. BaseType_t xLFNCount;
  2518. int32_t lFreeEntry = 0L;
  2519. FF_Error_t xReturn = FF_ERR_NONE;
  2520. BaseType_t xEntryCount;
  2521. FF_FetchContext_t xFetchContext;
  2522. uint32_t ulDirCluster = pxFindParams->ulDirCluster;
  2523. int32_t lFitShort;
  2524. #if ( ffconfigHASH_CACHE != 0 )
  2525. char pcShortName[ 13 ];
  2526. #endif
  2527. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  2528. uint16_t NameLen = ( uint16_t ) wcslen( pxDirEntry->pcFileName );
  2529. #else
  2530. uint16_t NameLen = ( uint16_t ) strlen( pxDirEntry->pcFileName );
  2531. #endif
  2532. #if ( ffconfigLFN_SUPPORT != 0 )
  2533. uint8_t ucCheckSum;
  2534. #endif
  2535. /* Round-up the number of LFN's needed: */
  2536. xLFNCount = ( BaseType_t ) ( ( NameLen + 12 ) / 13 );
  2537. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  2538. {
  2539. FF_MakeNameCompliant( pxDirEntry->pcFileName ); /* Ensure we don't break the Dir tables. */
  2540. }
  2541. #else
  2542. {
  2543. FF_MakeNameCompliant( pxDirEntry->pcFileName ); /* Ensure we don't break the Dir tables. */
  2544. }
  2545. #endif
  2546. memset( pucEntryBuffer, 0, sizeof( pucEntryBuffer ) );
  2547. #if ( ffconfigLFN_SUPPORT != 0 )
  2548. {
  2549. /* Create and push the LFN's. */
  2550. /* Find enough places for the LFNs and the ShortName. */
  2551. xEntryCount = xLFNCount + 1;
  2552. }
  2553. #else
  2554. {
  2555. xEntryCount = 1;
  2556. }
  2557. #endif
  2558. /* Create the ShortName. */
  2559. FF_LockDirectory( pxIOManager );
  2560. do
  2561. {
  2562. /* Open a do {} while( pdFALSE ) loop to allow the use of break statements. */
  2563. /* As FF_FindShortName( ) can fail, it should be called before finding a free directory entry. */
  2564. if( ( pxFindParams->ulFlags & FIND_FLAG_SHORTNAME_SET ) == 0 )
  2565. {
  2566. FF_CreateShortName( pxFindParams, pxDirEntry->pcFileName );
  2567. }
  2568. lFitShort = FF_FindShortName( pxIOManager, pxFindParams );
  2569. memcpy( pucEntryBuffer, pxFindParams->pcEntryBuffer, sizeof( pucEntryBuffer ) );
  2570. if( FF_isERR( lFitShort ) )
  2571. {
  2572. xReturn = lFitShort;
  2573. break;
  2574. }
  2575. if( lFitShort != 0 )
  2576. {
  2577. /* There is no need to create a LFN entry because the file name
  2578. * fits into a normal 32-byte entry.. */
  2579. xLFNCount = 0;
  2580. xEntryCount = 1;
  2581. }
  2582. lFreeEntry = FF_FindFreeDirent( pxIOManager, pxFindParams, ( uint16_t ) xEntryCount );
  2583. if( FF_isERR( lFreeEntry ) )
  2584. {
  2585. xReturn = lFreeEntry;
  2586. break;
  2587. }
  2588. #if ( ffconfigLFN_SUPPORT != 0 )
  2589. {
  2590. if( xLFNCount > 0 )
  2591. {
  2592. ucCheckSum = FF_CreateChkSum( pucEntryBuffer );
  2593. xReturn = FF_CreateLFNs( pxIOManager, ulDirCluster, pxDirEntry->pcFileName, ucCheckSum, ( uint16_t ) lFreeEntry );
  2594. }
  2595. }
  2596. #else
  2597. {
  2598. xLFNCount = 0;
  2599. }
  2600. #endif /* ffconfigLFN_SUPPORT */
  2601. if( FF_isERR( xReturn ) == pdFALSE )
  2602. {
  2603. #if ( ffconfigTIME_SUPPORT != 0 )
  2604. {
  2605. FF_GetSystemTime( &pxDirEntry->xCreateTime ); /* Date and Time Created. */
  2606. pxDirEntry->xModifiedTime = pxDirEntry->xCreateTime; /* Date and Time Modified. */
  2607. pxDirEntry->xAccessedTime = pxDirEntry->xCreateTime; /* Date of Last Access. */
  2608. FF_PlaceTime( pucEntryBuffer, FF_FAT_DIRENT_CREATE_TIME, &pxDirEntry->xCreateTime );
  2609. FF_PlaceDate( pucEntryBuffer, FF_FAT_DIRENT_CREATE_DATE, &pxDirEntry->xCreateTime );
  2610. FF_PlaceTime( pucEntryBuffer, FF_FAT_DIRENT_LASTMOD_TIME, &pxDirEntry->xModifiedTime );
  2611. FF_PlaceDate( pucEntryBuffer, FF_FAT_DIRENT_LASTMOD_DATE, &pxDirEntry->xModifiedTime );
  2612. }
  2613. #endif /* ffconfigTIME_SUPPORT */
  2614. FF_putChar( pucEntryBuffer, FF_FAT_DIRENT_ATTRIB, pxDirEntry->ucAttrib );
  2615. #if ( ffconfigSHORTNAME_CASE != 0 )
  2616. FF_putChar( pucEntryBuffer, FF_FAT_CASE_OFFS, ( uint32_t ) lFitShort & ( FF_FAT_CASE_ATTR_BASE | FF_FAT_CASE_ATTR_EXT ) );
  2617. #endif
  2618. FF_putShort( pucEntryBuffer, FF_FAT_DIRENT_CLUS_HIGH, ( uint16_t ) ( pxDirEntry->ulObjectCluster >> 16 ) );
  2619. FF_putShort( pucEntryBuffer, FF_FAT_DIRENT_CLUS_LOW, ( uint16_t ) ( pxDirEntry->ulObjectCluster ) );
  2620. FF_putLong( pucEntryBuffer, FF_FAT_DIRENT_FILESIZE, pxDirEntry->ulFileSize );
  2621. xReturn = FF_InitEntryFetch( pxIOManager, ulDirCluster, &xFetchContext );
  2622. if( FF_isERR( xReturn ) )
  2623. {
  2624. break;
  2625. }
  2626. xReturn = FF_PushEntryWithContext( pxIOManager, ( uint16_t ) ( lFreeEntry + xLFNCount ), &xFetchContext, pucEntryBuffer );
  2627. {
  2628. FF_Error_t xTempError;
  2629. xTempError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext );
  2630. if( FF_isERR( xReturn ) == pdFALSE )
  2631. {
  2632. xReturn = xTempError;
  2633. }
  2634. }
  2635. if( FF_isERR( xReturn ) )
  2636. {
  2637. break;
  2638. }
  2639. #if ( ffconfigHASH_CACHE != 0 )
  2640. {
  2641. if( FF_DirHashed( pxIOManager, ulDirCluster ) == pdFALSE )
  2642. {
  2643. /* Hash the directory. */
  2644. FF_HashDir( pxIOManager, ulDirCluster );
  2645. }
  2646. memcpy( pcShortName, pucEntryBuffer, 11 );
  2647. FF_ProcessShortName( pcShortName ); /* Format the shortname to 8.3. */
  2648. #if ( ffconfigHASH_FUNCTION == CRC16 )
  2649. {
  2650. FF_AddDirentHash( pxIOManager, ulDirCluster, ( uint32_t ) FF_GetCRC16( ( uint8_t * ) pcShortName, strlen( pcShortName ) ) );
  2651. }
  2652. #elif ( ffconfigHASH_FUNCTION == CRC8 )
  2653. {
  2654. FF_AddDirentHash( pxIOManager, ulDirCluster, ( uint32_t ) FF_GetCRC8( ( uint8_t * ) pcShortName, strlen( pcShortName ) ) );
  2655. }
  2656. #endif /* ffconfigHASH_FUNCTION */
  2657. }
  2658. #endif /* ffconfigHASH_CACHE*/
  2659. }
  2660. }
  2661. while( pdFALSE );
  2662. FF_UnlockDirectory( pxIOManager );
  2663. if( FF_isERR( xReturn ) == pdFALSE )
  2664. {
  2665. if( pxDirEntry != NULL )
  2666. {
  2667. pxDirEntry->usCurrentItem = ( uint16_t ) ( lFreeEntry + xLFNCount );
  2668. }
  2669. }
  2670. return xReturn;
  2671. } /* FF_CreateDirent() */
  2672. /*-----------------------------------------------------------*/
  2673. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  2674. uint32_t FF_CreateFile( FF_IOManager_t * pxIOManager,
  2675. FF_FindParams_t * pxFindParams,
  2676. FF_T_WCHAR * pcFileName,
  2677. FF_DirEnt_t * pxDirEntry,
  2678. FF_Error_t * pxError )
  2679. #else
  2680. uint32_t FF_CreateFile( FF_IOManager_t * pxIOManager,
  2681. FF_FindParams_t * pxFindParams,
  2682. char * pcFileName,
  2683. FF_DirEnt_t * pxDirEntry,
  2684. FF_Error_t * pxError )
  2685. #endif /* if ( ffconfigUNICODE_UTF16_SUPPORT != 0 ) */
  2686. {
  2687. FF_DirEnt_t xMyFile;
  2688. FF_Error_t xTempError, xError = FF_ERR_NONE;
  2689. uint32_t ulResult;
  2690. memset( &xMyFile, '\0', sizeof( xMyFile ) );
  2691. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  2692. {
  2693. wcsncpy( xMyFile.pcFileName, pcFileName, ffconfigMAX_FILENAME );
  2694. }
  2695. #else
  2696. {
  2697. strncpy( xMyFile.pcFileName, pcFileName, ffconfigMAX_FILENAME );
  2698. }
  2699. #endif
  2700. xMyFile.ulObjectCluster = FF_CreateClusterChain( pxIOManager, &xError );
  2701. if( FF_isERR( xError ) == pdFALSE )
  2702. {
  2703. xError = FF_CreateDirent( pxIOManager, pxFindParams, &xMyFile );
  2704. if( FF_isERR( xError ) == pdFALSE )
  2705. {
  2706. /* The new file now has a cluster chain and it has an entry
  2707. * in its directory. Copy data to a pointer provided by caller: */
  2708. if( pxDirEntry != NULL )
  2709. {
  2710. memcpy( pxDirEntry, &xMyFile, sizeof( FF_DirEnt_t ) );
  2711. }
  2712. }
  2713. else
  2714. {
  2715. /* An error occurred in FF_CreateDirent().
  2716. * Unlink the file's cluster chain: */
  2717. FF_LockFAT( pxIOManager );
  2718. {
  2719. FF_UnlinkClusterChain( pxIOManager, xMyFile.ulObjectCluster, 0 );
  2720. xMyFile.ulObjectCluster = 0ul;
  2721. }
  2722. FF_UnlockFAT( pxIOManager );
  2723. }
  2724. /* Now flush all buffers to disk. */
  2725. xTempError = FF_FlushCache( pxIOManager );
  2726. if( FF_isERR( xError ) == pdFALSE )
  2727. {
  2728. xError = xTempError;
  2729. }
  2730. }
  2731. *pxError = xError;
  2732. if( FF_isERR( xError ) == pdFALSE )
  2733. {
  2734. ulResult = xMyFile.ulObjectCluster;
  2735. }
  2736. else
  2737. {
  2738. ulResult = 0;
  2739. }
  2740. return ulResult;
  2741. } /* FF_CreateFile() */
  2742. /*-----------------------------------------------------------*/
  2743. /**
  2744. * @brief Creates a Directory of the specified path.
  2745. *
  2746. * @param pxIOManager Pointer to the FF_IOManager_t object.
  2747. * @param pcPath Path of the directory to create.
  2748. *
  2749. * @Return FF_ERR_NULL_POINTER if pxIOManager was NULL.
  2750. * @Return FF_ERR_DIR_OBJECT_EXISTS if the object specified by path already exists.
  2751. * @Return FF_ERR_DIR_INVALID_PATH
  2752. * @Return FF_ERR_NONE on success.
  2753. **/
  2754. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  2755. FF_Error_t FF_MkDir( FF_IOManager_t * pxIOManager,
  2756. const FF_T_WCHAR * pcPath )
  2757. #else
  2758. FF_Error_t FF_MkDir( FF_IOManager_t * pxIOManager,
  2759. const char * pcPath )
  2760. #endif
  2761. {
  2762. FF_DirEnt_t xMyDirectory;
  2763. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  2764. const FF_T_WCHAR * pcDirName;
  2765. #else
  2766. const char * pcDirName;
  2767. #endif
  2768. uint8_t pucEntryBuffer[ FF_SIZEOF_DIRECTORY_ENTRY ];
  2769. uint32_t ulObjectCluster;
  2770. BaseType_t xIndex;
  2771. FF_Error_t xError = FF_ERR_NONE;
  2772. FF_FindParams_t xFindParams;
  2773. memset( &xFindParams, '\0', sizeof( xFindParams ) );
  2774. /* Inform the functions that the entry will be created if not found */
  2775. xFindParams.ulFlags |= FIND_FLAG_CREATE_FLAG;
  2776. /* Open a do {} while ( pdFALSE ) loop */
  2777. do
  2778. {
  2779. if( pxIOManager == NULL )
  2780. {
  2781. xError = ( FF_Error_t ) ( FF_ERR_NULL_POINTER | FF_MKDIR );
  2782. break;
  2783. }
  2784. #if ( ffconfigREMOVABLE_MEDIA != 0 )
  2785. if( ( pxIOManager->ucFlags & FF_IOMAN_DEVICE_IS_EXTRACTED ) != 0 )
  2786. {
  2787. xError = ( FF_Error_t ) ( FF_ERR_IOMAN_DRIVER_NOMEDIUM | FF_MKDIR );
  2788. break;
  2789. }
  2790. #endif /* ffconfigREMOVABLE_MEDIA */
  2791. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  2792. {
  2793. xIndex = ( BaseType_t ) wcslen( pcPath );
  2794. }
  2795. #else
  2796. {
  2797. xIndex = ( BaseType_t ) strlen( pcPath );
  2798. }
  2799. #endif
  2800. /* Find the last slash in the path. */
  2801. while( xIndex != 0 )
  2802. {
  2803. if( ( pcPath[ xIndex ] == '\\' ) || ( pcPath[ xIndex ] == '/' ) )
  2804. {
  2805. break;
  2806. }
  2807. xIndex--;
  2808. }
  2809. pcDirName = pcPath + xIndex + 1;
  2810. if( xIndex == 0 )
  2811. {
  2812. xIndex = 1;
  2813. }
  2814. if( pcDirName[ 0 ] == '\0' )
  2815. {
  2816. xError = ( FF_ERR_DIR_OBJECT_EXISTS | FF_MKDIR );
  2817. break;
  2818. }
  2819. xFindParams.ulDirCluster = FF_FindDir( pxIOManager, pcPath, ( uint16_t ) xIndex, &xError );
  2820. if( FF_isERR( xError ) )
  2821. {
  2822. break;
  2823. }
  2824. if( xFindParams.ulDirCluster == 0UL )
  2825. {
  2826. xError = ( FF_Error_t ) ( FF_ERR_DIR_INVALID_PATH | FF_MKDIR );
  2827. break;
  2828. }
  2829. memset( &xMyDirectory, '\0', sizeof( xMyDirectory ) );
  2830. /* Will set flags FIND_FLAG_FITS_SHORT and FIND_FLAG_SIZE_OK */
  2831. FF_CreateShortName( &xFindParams, pcDirName );
  2832. if( FF_FindEntryInDir( pxIOManager, &xFindParams, pcDirName, 0x00, &xMyDirectory, &xError ) )
  2833. {
  2834. if( FF_isERR( xError ) == pdFALSE )
  2835. {
  2836. xError = ( FF_Error_t ) ( FF_ERR_DIR_OBJECT_EXISTS | FF_MKDIR );
  2837. }
  2838. break;
  2839. }
  2840. if( ( FF_isERR( xError ) ) && ( FF_GETERROR( xError ) != FF_ERR_DIR_END_OF_DIR ) )
  2841. {
  2842. break;
  2843. }
  2844. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  2845. {
  2846. wcsncpy( xMyDirectory.pcFileName, pcDirName, ffconfigMAX_FILENAME );
  2847. }
  2848. #else
  2849. {
  2850. strncpy( xMyDirectory.pcFileName, pcDirName, ffconfigMAX_FILENAME );
  2851. }
  2852. #endif
  2853. xMyDirectory.ulFileSize = 0;
  2854. xMyDirectory.ucAttrib = FF_FAT_ATTR_DIR;
  2855. xMyDirectory.ulObjectCluster = FF_CreateClusterChain( pxIOManager, &xError );
  2856. /* Give all entries a proper time stamp, looks nicer than 1 Jan 1970 */
  2857. #if ( ffconfigTIME_SUPPORT != 0 )
  2858. {
  2859. FF_GetSystemTime( &xMyDirectory.xCreateTime );
  2860. FF_GetSystemTime( &xMyDirectory.xModifiedTime );
  2861. }
  2862. #endif
  2863. if( FF_isERR( xError ) )
  2864. {
  2865. break;
  2866. }
  2867. if( xMyDirectory.ulObjectCluster == 0UL )
  2868. {
  2869. /* Couldn't allocate any space for the dir! */
  2870. xError = ( FF_Error_t ) ( FF_ERR_DIR_EXTEND_FAILED | FF_MKDIR );
  2871. break;
  2872. }
  2873. xError = FF_ClearCluster( pxIOManager, xMyDirectory.ulObjectCluster );
  2874. if( FF_isERR( xError ) == pdFALSE )
  2875. {
  2876. xError = FF_CreateDirent( pxIOManager, &xFindParams, &xMyDirectory );
  2877. }
  2878. if( FF_isERR( xError ) )
  2879. {
  2880. FF_LockFAT( pxIOManager );
  2881. {
  2882. FF_UnlinkClusterChain( pxIOManager, xMyDirectory.ulObjectCluster, 0 );
  2883. }
  2884. FF_UnlockFAT( pxIOManager );
  2885. FF_FlushCache( pxIOManager ); /* Don't override error. */
  2886. break;
  2887. }
  2888. /* Write 8.3 entry "." */
  2889. pucEntryBuffer[ 0 ] = '.';
  2890. /* folowed by 10 spaces: */
  2891. memset( pucEntryBuffer + 1, ' ', 10 );
  2892. /* Clear the rest of the structure. */
  2893. memset( pucEntryBuffer + 11, 0, FF_SIZEOF_DIRECTORY_ENTRY - 11 );
  2894. ulObjectCluster = xMyDirectory.ulObjectCluster;
  2895. xError = FF_PutEntry( pxIOManager, ( uint16_t ) 0u, ulObjectCluster, &xMyDirectory, pucEntryBuffer );
  2896. if( FF_isERR( xError ) == pdFALSE )
  2897. {
  2898. pucEntryBuffer[ 1 ] = '.';
  2899. if( xFindParams.ulDirCluster == pxIOManager->xPartition.ulRootDirCluster )
  2900. {
  2901. xMyDirectory.ulObjectCluster = 0;
  2902. }
  2903. else
  2904. {
  2905. xMyDirectory.ulObjectCluster = xFindParams.ulDirCluster;
  2906. }
  2907. xError = FF_PutEntry( pxIOManager, 1u, ulObjectCluster, &xMyDirectory, pucEntryBuffer );
  2908. xMyDirectory.ulObjectCluster = ulObjectCluster;
  2909. }
  2910. if( FF_isERR( xError ) )
  2911. {
  2912. FF_LockFAT( pxIOManager );
  2913. {
  2914. FF_UnlinkClusterChain( pxIOManager, xMyDirectory.ulObjectCluster, 0 );
  2915. }
  2916. FF_UnlockFAT( pxIOManager );
  2917. }
  2918. FF_FlushCache( pxIOManager );
  2919. }
  2920. while( pdFALSE );
  2921. return xError;
  2922. } /* FF_MkDir() */
  2923. /*-----------------------------------------------------------*/
  2924. FF_Error_t FF_RmLFNs( FF_IOManager_t * pxIOManager,
  2925. uint16_t usDirEntry,
  2926. FF_FetchContext_t * pxContext )
  2927. {
  2928. FF_Error_t xError = FF_ERR_NONE;
  2929. uint8_t pucEntryBuffer[ FF_SIZEOF_DIRECTORY_ENTRY ];
  2930. if( usDirEntry != 0 )
  2931. {
  2932. usDirEntry--;
  2933. do
  2934. {
  2935. xError = FF_FetchEntryWithContext( pxIOManager, usDirEntry, pxContext, pucEntryBuffer );
  2936. if( FF_isERR( xError ) )
  2937. {
  2938. break;
  2939. }
  2940. if( FF_getChar( pucEntryBuffer, ( uint16_t ) ( FF_FAT_DIRENT_ATTRIB ) ) == FF_FAT_ATTR_LFN )
  2941. {
  2942. FF_putChar( pucEntryBuffer, ( uint16_t ) 0, ( uint8_t ) FF_FAT_DELETED );
  2943. xError = FF_PushEntryWithContext( pxIOManager, usDirEntry, pxContext, pucEntryBuffer );
  2944. if( FF_isERR( xError ) )
  2945. {
  2946. break;
  2947. }
  2948. }
  2949. if( usDirEntry == 0 )
  2950. {
  2951. break;
  2952. }
  2953. usDirEntry--;
  2954. } while( FF_getChar( pucEntryBuffer, ( uint16_t ) ( FF_FAT_DIRENT_ATTRIB ) ) == FF_FAT_ATTR_LFN );
  2955. }
  2956. return xError;
  2957. } /* FF_RmLFNs() */
  2958. /*-----------------------------------------------------------*/
  2959. #if ( ffconfigHASH_CACHE != 0 )
  2960. FF_Error_t FF_HashDir( FF_IOManager_t * pxIOManager,
  2961. uint32_t ulDirCluster )
  2962. {
  2963. /* Find most suitable Hash Table to replace! */
  2964. BaseType_t xIndex;
  2965. FF_HashTable_t * pxHashCache = NULL;
  2966. FF_FetchContext_t xFetchContext;
  2967. const uint8_t * pucEntryBuffer = NULL;
  2968. uint8_t ucAttrib;
  2969. uint32_t ulHash;
  2970. FF_Error_t xError;
  2971. for( xIndex = 0; xIndex < ffconfigHASH_CACHE_DEPTH; xIndex++ )
  2972. {
  2973. if( pxIOManager->xHashCache[ xIndex ].ulNumHandles == 0 )
  2974. {
  2975. if( pxHashCache == NULL )
  2976. {
  2977. pxHashCache = &pxIOManager->xHashCache[ xIndex ];
  2978. }
  2979. else
  2980. {
  2981. if( ( pxIOManager->xHashCache[ xIndex ].ulMisses > pxHashCache->ulMisses ) )
  2982. {
  2983. pxHashCache = &pxIOManager->xHashCache[ xIndex ];
  2984. }
  2985. }
  2986. }
  2987. }
  2988. if( pxHashCache != NULL )
  2989. {
  2990. #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
  2991. FF_T_WCHAR pcMyShortName[ 13 ];
  2992. #else
  2993. char pcMyShortName[ 13 ];
  2994. #endif
  2995. /* Clear the hash table! */
  2996. memset( pxHashCache, '\0', sizeof( *pxHashCache ) );
  2997. pxHashCache->ulDirCluster = ulDirCluster;
  2998. pxHashCache->ulMisses = 0;
  2999. /* Hash the directory! */
  3000. xError = FF_InitEntryFetch( pxIOManager, ulDirCluster, &xFetchContext );
  3001. if( FF_isERR( xError ) == pdFALSE )
  3002. {
  3003. for( xIndex = 0; xIndex < FF_MAX_ENTRIES_PER_DIRECTORY; xIndex++ )
  3004. {
  3005. if( ( pucEntryBuffer == NULL ) ||
  3006. ( pucEntryBuffer >= xFetchContext.pxBuffer->pucBuffer + ( pxIOManager->usSectorSize - FF_SIZEOF_DIRECTORY_ENTRY ) ) )
  3007. {
  3008. xError = FF_FetchEntryWithContext( pxIOManager, ( uint32_t ) xIndex, &xFetchContext, NULL );
  3009. if( FF_isERR( xError ) )
  3010. {
  3011. break;
  3012. }
  3013. pucEntryBuffer = xFetchContext.pxBuffer->pucBuffer;
  3014. }
  3015. else
  3016. {
  3017. /* Advance the pointer 32 bytes to the next directory entry. */
  3018. pucEntryBuffer += FF_SIZEOF_DIRECTORY_ENTRY;
  3019. }
  3020. if( FF_isDeleted( pucEntryBuffer ) == pdFALSE )
  3021. {
  3022. ucAttrib = FF_getChar( pucEntryBuffer, FF_FAT_DIRENT_ATTRIB );
  3023. if( ( ( ucAttrib & FF_FAT_ATTR_LFN ) != FF_FAT_ATTR_LFN ) &&
  3024. ( ( ucAttrib & FF_FAT_ATTR_VOLID ) != FF_FAT_ATTR_VOLID ) )
  3025. {
  3026. memcpy( pcMyShortName, pucEntryBuffer, 11 );
  3027. FF_ProcessShortName( pcMyShortName );
  3028. if( FF_isEndOfDir( pucEntryBuffer ) )
  3029. {
  3030. break;
  3031. }
  3032. /* Generate the Hash. */
  3033. #if ( ffconfigHASH_FUNCTION == CRC16 )
  3034. {
  3035. ulHash = FF_GetCRC16( ( uint8_t * ) pcMyShortName, strlen( pcMyShortName ) );
  3036. }
  3037. #else /* ffconfigHASH_FUNCTION == CRC8 */
  3038. {
  3039. ulHash = FF_GetCRC8( pcMyShortName, strlen( pcMyShortName ) );
  3040. }
  3041. #endif
  3042. FF_SetHash( pxHashCache, ulHash );
  3043. }
  3044. }
  3045. } /* for( xIndex = 0; xIndex < FF_MAX_ENTRIES_PER_DIRECTORY; xIndex++ ) */
  3046. {
  3047. FF_Error_t xTempError;
  3048. xTempError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext );
  3049. if( FF_isERR( xError ) == pdFALSE )
  3050. {
  3051. xError = xTempError;
  3052. }
  3053. }
  3054. }
  3055. } /* if( pxHashCache != NULL ) */
  3056. else
  3057. {
  3058. xError = -1;
  3059. }
  3060. return xError;
  3061. } /* FF_HashDir() */
  3062. #endif /* ffconfigHASH_CACHE != 0 */
  3063. /*-----------------------------------------------------------*/
  3064. #if ( ffconfigHASH_CACHE != 0 )
  3065. /* FF_UnHashDir() : invalidate the hash tables of a given directory.
  3066. * It is called when a file or sub-directory is removed or when the
  3067. * directory itself is removed. */
  3068. void FF_UnHashDir( FF_IOManager_t * pxIOManager,
  3069. uint32_t ulDirCluster )
  3070. {
  3071. FF_HashTable_t * pxHash = pxIOManager->xHashCache;
  3072. FF_HashTable_t * pxLast = pxIOManager->xHashCache + ffconfigHASH_CACHE_DEPTH;
  3073. for( ; pxHash < pxLast; pxHash++ )
  3074. {
  3075. if( pxHash->ulDirCluster == ulDirCluster )
  3076. {
  3077. pxHash->ulDirCluster = 0;
  3078. break;
  3079. }
  3080. }
  3081. } /* FF_UnHashDir() */
  3082. #endif /* ffconfigHASH_CACHE */
  3083. /*-----------------------------------------------------------*/
  3084. #if ( ffconfigHASH_CACHE != 0 )
  3085. /**
  3086. *
  3087. *
  3088. **/
  3089. void FF_SetHash( FF_HashTable_t * pxHash,
  3090. uint32_t ulHash )
  3091. {
  3092. uint32_t tblIndex = ( ulHash / 32 ) % FF_HASH_TABLE_ENTRY_COUNT;
  3093. uint32_t tblBit = ulHash % 32;
  3094. pxHash->ulBitTable[ tblIndex ] |= ( 0x80000000ul >> tblBit );
  3095. } /* FF_SetHash() */
  3096. #endif /* ffconfigHASH_CACHE */
  3097. /*-----------------------------------------------------------*/
  3098. #if ( ffconfigHASH_CACHE != 0 )
  3099. void FF_ClearHash( FF_HashTable_t * pxHash,
  3100. uint32_t ulHash )
  3101. {
  3102. if( pxHash != NULL )
  3103. {
  3104. uint32_t tblIndex = ( ulHash / 32 ) % FF_HASH_TABLE_ENTRY_COUNT;
  3105. uint32_t tblBit = ulHash % 32;
  3106. pxHash->ulBitTable[ tblIndex ] &= ~( 0x80000000ul >> tblBit );
  3107. }
  3108. } /* FF_ClearHash() */
  3109. #endif /* ffconfigHASH_CACHE */
  3110. /*-----------------------------------------------------------*/
  3111. #if ( ffconfigHASH_CACHE != 0 )
  3112. BaseType_t FF_isHashSet( FF_HashTable_t * pxHash,
  3113. uint32_t ulHash )
  3114. {
  3115. FF_Error_t xResult;
  3116. xResult = pdFALSE;
  3117. if( pxHash != NULL )
  3118. {
  3119. uint32_t tblIndex = ( ulHash / 32 ) % FF_HASH_TABLE_ENTRY_COUNT;
  3120. uint32_t tblBit = ulHash % 32;
  3121. if( pxHash->ulBitTable[ tblIndex ] & ( 0x80000000ul >> tblBit ) )
  3122. {
  3123. xResult = pdTRUE;
  3124. }
  3125. }
  3126. return xResult;
  3127. } /* FF_isHashSet() */
  3128. #endif /* ffconfigHASH_CACHE */
  3129. /*-----------------------------------------------------------*/
  3130. #if ( ffconfigHASH_CACHE != 0 )
  3131. void FF_AddDirentHash( FF_IOManager_t * pxIOManager,
  3132. uint32_t ulDirCluster,
  3133. uint32_t ulHash )
  3134. {
  3135. FF_HashTable_t * pxHash = pxIOManager->xHashCache;
  3136. FF_HashTable_t * pxLast = pxIOManager->xHashCache + ffconfigHASH_CACHE_DEPTH;
  3137. for( ; pxHash < pxLast; pxHash++ )
  3138. {
  3139. if( pxHash->ulDirCluster == ulDirCluster )
  3140. {
  3141. FF_SetHash( pxHash, ulHash );
  3142. break;
  3143. }
  3144. }
  3145. } /* FF_AddDirentHash() */
  3146. #endif /* ffconfigHASH_CACHE*/
  3147. /*-----------------------------------------------------------*/
  3148. #if ( ffconfigHASH_CACHE != 0 )
  3149. BaseType_t FF_CheckDirentHash( FF_IOManager_t * pxIOManager,
  3150. uint32_t ulDirCluster,
  3151. uint32_t ulHash )
  3152. {
  3153. FF_HashTable_t * pxHash = pxIOManager->xHashCache;
  3154. FF_HashTable_t * pxLast = pxIOManager->xHashCache + ffconfigHASH_CACHE_DEPTH;
  3155. BaseType_t xResult;
  3156. for( ; ; )
  3157. {
  3158. if( pxHash->ulDirCluster == ulDirCluster )
  3159. {
  3160. xResult = FF_isHashSet( pxHash, ulHash );
  3161. break;
  3162. }
  3163. pxHash++;
  3164. if( pxHash >= pxLast )
  3165. {
  3166. xResult = -1;
  3167. break;
  3168. }
  3169. }
  3170. return xResult;
  3171. } /* FF_CheckDirentHash() */
  3172. #endif /* ffconfigHASH_CACHE */
  3173. /*-----------------------------------------------------------*/
  3174. #if ( ffconfigHASH_CACHE != 0 )
  3175. BaseType_t FF_DirHashed( FF_IOManager_t * pxIOManager,
  3176. uint32_t ulDirCluster )
  3177. {
  3178. FF_HashTable_t * pxHash = pxIOManager->xHashCache;
  3179. FF_HashTable_t * pxLast = pxIOManager->xHashCache + ffconfigHASH_CACHE_DEPTH;
  3180. BaseType_t xResult;
  3181. for( ; ; )
  3182. {
  3183. if( pxHash->ulDirCluster == ulDirCluster )
  3184. {
  3185. xResult = pdTRUE;
  3186. break;
  3187. }
  3188. pxHash++;
  3189. if( pxHash >= pxLast )
  3190. {
  3191. xResult = pdFALSE;
  3192. break;
  3193. }
  3194. }
  3195. return xResult;
  3196. } /* FF_DirHashed() */
  3197. #endif /* ffconfigHASH_CACHE */
  3198. /*-----------------------------------------------------------*/