| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694 |
- /*
- * FreeRTOS+FAT V2.3.3
- * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- * https://www.FreeRTOS.org
- * https://github.com/FreeRTOS
- *
- */
- /**
- * @file ff_fat.c
- * @ingroup FAT
- *
- * @defgroup FAT Fat File-System
- * @brief Handles FAT access and traversal.
- *
- * Provides file-system interfaces for the FAT file-system.
- **/
- #include "ff_headers.h"
- #include <string.h>
- #if ffconfigFAT_USES_STAT
- /* This module make use of a buffer caching called 'FF_FATBuffers_t'.
- * The struct below may gather statistics about its usage: hits/misses.
- */
- struct SFatStat fatStat;
- #endif /* ffconfigFAT_USES_STAT */
- /* prvGetFromFATBuffers() will see if the FF_Buffer_t pointed to by ppxBuffer contains the
- * buffer that is needed, i.e. opened for the same sector and with the correct R/W mode.
- * If ppxBuffer is NULL or if it can not be used, a new buffer will be created.
- * The buffer pointed to by ppxBuffer will either be released or its pointer will be returned.
- */
- FF_Buffer_t * prvGetFromFATBuffers( FF_IOManager_t * pxIOManager,
- FF_FATBuffers_t * pxFATBuffers,
- BaseType_t xBufferIndex,
- uint32_t ulFATSector,
- FF_Error_t * pxError,
- uint8_t ucMode );
- #if ( ffconfigFAT12_SUPPORT != 0 )
- /* A very special case for FAT12: an entry is stored in two sectors.
- * Read the two sectors and merge the two values found.
- */
- static uint32_t prvGetFAT12Entry( FF_IOManager_t * pxIOManager,
- FF_Error_t * pxError,
- FF_FATBuffers_t * pxFATBuffers,
- uint32_t ulFATSector );
- #endif
- #if ( ffconfigFAT12_SUPPORT != 0 )
- /* Same as above: put a FAT12 entry that is spread-out over two sectors.
- * Read the current value first to preserve and merge the earlier 4 bits
- * of an adjacent FAT12 entry.
- */
- static FF_Error_t prvPutFAT12Entry( FF_IOManager_t * pxIOManager,
- uint32_t ulCluster,
- uint32_t ulValue,
- FF_FATBuffers_t * pxFATBuffers,
- uint32_t ulFATSector );
- #endif
- #if ( ffconfigFAT12_SUPPORT != 0 )
- /* A generic less-optimised way of finding the first free cluster.
- * Used for FAT12 only.
- */
- static uint32_t prvFindFreeClusterSimple( FF_IOManager_t * pxIOManager,
- FF_Error_t * pxError );
- #endif /* ffconfigFAT12_SUPPORT */
- #if ( ffconfigFAT12_SUPPORT != 0 )
- /* A generic less-optimised way of counting free clusters.
- * Used for FAT12 only.
- */
- static uint32_t prvCountFreeClustersSimple( FF_IOManager_t * pxIOManager,
- FF_Error_t * pxError );
- #endif /* ffconfigFAT12_SUPPORT */
- /* Have a cluster number and translate it to an LBA (Logical Block Address).
- * 'ulSectorsPerCluster' should be seen as 'blocks per cluster', where the length of one
- * block is defined in the PBR (Partition Boot Record) at FF_FAT_BYTES_PER_SECTOR (offset 0x0B).
- */
- uint32_t FF_Cluster2LBA( FF_IOManager_t * pxIOManager,
- uint32_t ulCluster )
- {
- uint32_t ulLBA = 0;
- FF_Partition_t * pxPartition;
- if( pxIOManager != NULL )
- {
- pxPartition = &( pxIOManager->xPartition );
- if( ulCluster >= 2 )
- {
- ulLBA = ( ( ulCluster - 2 ) * pxPartition->ulSectorsPerCluster ) + pxPartition->ulFirstDataSector;
- }
- else
- {
- ulLBA = pxPartition->ulClusterBeginLBA;
- }
- }
- return ulLBA;
- }
- /*-----------------------------------------------------------*/
- /*
- * Major and Minor sectors/blocks:
- *
- * A cluster is defined as N "sectors". Those sectors in fact are "major blocks"
- * whose size is defined in a field called 'FF_FAT_BYTES_PER_SECTOR' in the PBR.
- *
- * I/O to the disk takes place in "minor block" of usually 512 byte and the addressing
- * is also based on "minor block" sector numbers.
- *
- * In most cases, Major == Minor == 512 bytes.
- *
- * Here below some translations are done for 'entries', which can be 1-byte entries
- * as well as the 32-byte directory entries.
- *
- */
- /* Translate an 'entry number' (ulEntry) to a relative cluster number,
- * where e.g. 'ulEntry' may be a sequence number of a directory entry for
- * which ulEntrySize = 32 bytes.
- */
- uint32_t FF_getClusterChainNumber( FF_IOManager_t * pxIOManager,
- uint32_t ulEntry,
- uint32_t ulEntrySize )
- {
- uint32_t ulBytesPerCluster = pxIOManager->xPartition.usBlkSize * pxIOManager->xPartition.ulSectorsPerCluster;
- uint32_t ulEntriesPerCluster = ( ulBytesPerCluster / ulEntrySize );
- /* E.g. ulBytesPerCluster = 16384, ulEntrySize = 32: 16384 / 32 = 512 entries per cluster. */
- return ulEntry / ulEntriesPerCluster;
- }
- /*-----------------------------------------------------------*/
- /* If the above function returns a cluster number, this function
- * returns a BYTE position within that cluster. */
- uint32_t FF_getClusterPosition( FF_IOManager_t * pxIOManager,
- uint32_t ulEntry,
- uint32_t ulEntrySize )
- {
- uint32_t ulBytesPerCluster = pxIOManager->xPartition.usBlkSize * pxIOManager->xPartition.ulSectorsPerCluster;
- uint32_t ulEntriesPerCluster = ( ulBytesPerCluster / ulEntrySize );
- /* Return the block offset within the current cluster: */
- return ( ulEntry % ulEntriesPerCluster ) * ulEntrySize;
- }
- /*-----------------------------------------------------------*/
- /* Return the block offset (= number of major blocks) within the current cluster: */
- uint32_t FF_getMajorBlockNumber( FF_IOManager_t * pxIOManager,
- uint32_t ulEntry,
- uint32_t ulEntrySize )
- {
- uint32_t ulBytesPerCluster = pxIOManager->xPartition.usBlkSize * pxIOManager->xPartition.ulSectorsPerCluster;
- uint32_t ulEntriesPerCluster = ( ulBytesPerCluster / ulEntrySize );
- uint32_t ulRelClusterEntry;
- /* Calculate the entry number within a cluster: */
- ulRelClusterEntry = ulEntry % ulEntriesPerCluster;
- /* Return the block offset within the current cluster: */
- return ulRelClusterEntry / ( pxIOManager->xPartition.usBlkSize / ulEntrySize );
- }
- /*-----------------------------------------------------------*/
- /* Return the minor block number within the current major block */
- uint32_t FF_getMinorBlockNumber( FF_IOManager_t * pxIOManager,
- uint32_t ulEntry,
- uint32_t ulEntrySize )
- {
- uint32_t ulBytesPerCluster = pxIOManager->xPartition.usBlkSize * pxIOManager->xPartition.ulSectorsPerCluster;
- uint32_t ulEntriesPerCluster = ( ulBytesPerCluster / ulEntrySize );
- uint32_t ulRelClusterEntry;
- uint32_t ulRelMajorBlockEntry;
- /* Calculate the entry number within a cluster: */
- ulRelClusterEntry = ulEntry % ulEntriesPerCluster;
- ulRelMajorBlockEntry = ulRelClusterEntry % ( pxIOManager->xPartition.usBlkSize / ulEntrySize );
- return ulRelMajorBlockEntry / ( pxIOManager->usSectorSize / ulEntrySize );
- }
- /*-----------------------------------------------------------*/
- /* Get the entry number within the minor block */
- uint32_t FF_getMinorBlockEntry( FF_IOManager_t * pxIOManager,
- uint32_t ulEntry,
- uint32_t ulEntrySize )
- {
- uint32_t ulBytesPerCluster = pxIOManager->xPartition.usBlkSize * pxIOManager->xPartition.ulSectorsPerCluster;
- uint32_t ulEntriesPerCluster = ( ulBytesPerCluster / ulEntrySize );
- uint32_t ulRelClusterEntry;
- uint32_t ulRelMajorBlockEntry;
- /* Calculate the entry number within a cluster: */
- ulRelClusterEntry = ulEntry % ulEntriesPerCluster;
- ulRelMajorBlockEntry = ulRelClusterEntry % ( pxIOManager->xPartition.usBlkSize / ulEntrySize );
- return ulRelMajorBlockEntry % ( pxIOManager->usSectorSize / ulEntrySize );
- }
- /*-----------------------------------------------------------*/
- FF_Error_t FF_ReleaseFATBuffers( FF_IOManager_t * pxIOManager,
- FF_FATBuffers_t * pxFATBuffers )
- {
- BaseType_t xIndex;
- FF_Error_t xError = FF_ERR_NONE;
- FF_Buffer_t * pxBuffer;
- #if ffconfigBUF_STORE_COUNT != 2
- #warning Only maintaining one FAT table
- #endif
- /* 'ffconfigBUF_STORE_COUNT' equals to the number of FAT tables. */
- for( xIndex = 0; xIndex < ffconfigBUF_STORE_COUNT; xIndex++ )
- {
- pxBuffer = pxFATBuffers->pxBuffers[ xIndex ];
- if( pxBuffer != NULL )
- {
- FF_Error_t xTempError = FF_ERR_NONE;
- pxFATBuffers->pxBuffers[ xIndex ] = NULL;
- xTempError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
- if( FF_isERR( xError ) == pdFALSE )
- {
- /* as everywhere, this function will return
- * the first error that occurred, if any. */
- xError = xTempError;
- }
- }
- }
- #if ffconfigFAT_USES_STAT
- {
- fatStat.clearCount++;
- }
- #endif /* ffconfigFAT_USES_STAT */
- return xError;
- }
- /*-----------------------------------------------------------*/
- FF_Buffer_t * prvGetFromFATBuffers( FF_IOManager_t * pxIOManager,
- FF_FATBuffers_t * pxFATBuffers,
- BaseType_t xBufferIndex,
- uint32_t ulFATSector,
- FF_Error_t * pxError,
- uint8_t ucMode )
- {
- FF_Error_t xError = FF_ERR_NONE;
- FF_Buffer_t * pxBuffer = NULL;
- if( pxFATBuffers != NULL )
- {
- /* See if the same buffer can be reused. */
- pxBuffer = pxFATBuffers->pxBuffers[ xBufferIndex ];
- if( pxBuffer != NULL )
- {
- /* Now the buffer is either owned by pxBuffer,
- * or it has been released, so put it to NULL. */
- pxFATBuffers->pxBuffers[ xBufferIndex ] = NULL;
- if(
- ( pxBuffer->ulSector == ulFATSector ) &&
- ( ( ( ucMode & FF_MODE_WRITE ) == 0 ) ||
- ( ( pxBuffer->ucMode & FF_MODE_WRITE ) != 0 ) )
- )
- {
- /* Same sector, AND
- * write-permission is not required OR the buffer has write permission:
- * it can be reused. */
- #if ffconfigFAT_USES_STAT
- {
- fatStat.reuseCount[ ( ucMode & FF_MODE_WRITE ) ? 1 : 0 ]++;
- }
- #endif /* ffconfigFAT_USES_STAT */
- }
- else
- {
- xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
- pxBuffer = NULL;
- #if ffconfigFAT_USES_STAT
- {
- fatStat.missCount[ ( ucMode & FF_MODE_WRITE ) ? 1 : 0 ]++;
- }
- #endif /* ffconfigFAT_USES_STAT */
- }
- }
- else
- {
- #if ffconfigFAT_USES_STAT
- {
- fatStat.getCount[ ( ucMode & FF_MODE_WRITE ) ? 1 : 0 ]++;
- }
- #endif /* ffconfigFAT_USES_STAT */
- }
- }
- if( ( pxBuffer == NULL ) && ( FF_isERR( xError ) == pdFALSE ) )
- {
- pxBuffer = FF_GetBuffer( pxIOManager, ulFATSector, ucMode );
- if( pxBuffer == NULL )
- {
- /* Setting an error code without the Module/Function,
- * will be filled-in by the caller. */
- xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_ERRFLAG );
- }
- }
- *pxError = xError;
- return pxBuffer;
- }
- #if ( ffconfigFAT12_SUPPORT != 0 )
- /* A very special case for FAT12: an entry is stored in two sectors.
- * Read the two sectors and merge the two values found. */
- static uint32_t prvGetFAT12Entry( FF_IOManager_t * pxIOManager,
- FF_Error_t * pxError,
- FF_FATBuffers_t * pxFATBuffers,
- uint32_t ulFATSector )
- {
- FF_Error_t xError = FF_ERR_NONE;
- FF_Buffer_t * pxBuffer = NULL;
- /* preferred buffer access mode, user might want to update this entry
- * and set it to FF_MODE_WRITE. */
- uint8_t ucMode = pxFATBuffers ? pxFATBuffers->ucMode : FF_MODE_READ;
- /* Collect the two bytes in an array. */
- uint8_t ucBytes[ 2 ];
- /* The function return value. */
- uint32_t ulFATEntry = 0UL;
- pxBuffer = prvGetFromFATBuffers( pxIOManager, pxFATBuffers, 0, ulFATSector, &xError, ucMode );
- if( FF_isERR( xError ) )
- {
- xError = FF_GETERROR( xError ) | FF_GETFATENTRY;
- }
- else
- {
- /* Fetch the very last byte of this segment. */
- ucBytes[ 0 ] = FF_getChar( pxBuffer->pucBuffer, ( uint16_t ) ( pxIOManager->usSectorSize - 1 ) );
- xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
- /* release the other buffer as well. */
- if( ( FF_isERR( xError ) == pdFALSE ) && ( pxFATBuffers != NULL ) )
- {
- xError = FF_ReleaseFATBuffers( pxIOManager, pxFATBuffers );
- }
- if( FF_isERR( xError ) == pdFALSE )
- {
- /* Second Buffer get the first Byte in buffer (second byte of out address)! */
- pxBuffer = FF_GetBuffer( pxIOManager, ulFATSector + 1, ucMode );
- if( pxBuffer == NULL )
- {
- xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_GETFATENTRY );
- }
- else
- {
- /* Read the first byte from the subsequent sector. */
- ucBytes[ 1 ] = FF_getChar( pxBuffer->pucBuffer, 0 );
- /* And release that buffer. */
- xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
- if( FF_isERR( xError ) == pdFALSE )
- {
- /* Join the two bytes: */
- ulFATEntry = ( uint32_t ) FF_getShort( ( uint8_t * ) ucBytes, 0 );
- }
- }
- }
- }
- *pxError = xError;
- return ( int32_t ) ulFATEntry;
- }
- #endif /* ffconfigFAT12_SUPPORT */
- /*-----------------------------------------------------------*/
- /* Get a FAT entry, which is nothing more than a number referring to a sector. */
- uint32_t FF_getFATEntry( FF_IOManager_t * pxIOManager,
- uint32_t ulCluster,
- FF_Error_t * pxError,
- FF_FATBuffers_t * pxFATBuffers )
- {
- FF_Buffer_t * pxBuffer = NULL;
- uint32_t ulFATOffset;
- uint32_t ulFATSector = 0;
- uint32_t ulFATSectorEntry;
- /* The function result. */
- uint32_t ulFATEntry = 0;
- uint32_t ulLBAAdjust;
- uint32_t ulRelClusterEntry = 0;
- FF_Error_t xError = FF_ERR_NONE;
- /* preferred mode, user might want to update this entry. */
- uint8_t ucMode = pxFATBuffers ? pxFATBuffers->ucMode : FF_MODE_READ;
- FF_Assert_Lock( pxIOManager, FF_FAT_LOCK );
- if( ulCluster >= pxIOManager->xPartition.ulNumClusters )
- {
- /* _HT_ find a more specific error code.
- * Probably not really important as this is a function internal to the library. */
- xError = ( FF_Error_t ) ( FF_ERR_IOMAN_NOT_ENOUGH_FREE_SPACE | FF_GETFATENTRY );
- }
- else
- {
- if( pxIOManager->xPartition.ucType == FF_T_FAT32 )
- {
- ulFATOffset = ulCluster * 4;
- }
- else if( pxIOManager->xPartition.ucType == FF_T_FAT16 )
- {
- ulFATOffset = ulCluster * 2;
- }
- else /* pxIOManager->xPartition.ucType == FF_T_FAT12 */
- {
- ulFATOffset = ulCluster + ( ulCluster / 2 );
- }
- ulFATSector = pxIOManager->xPartition.ulFATBeginLBA + ( ulFATOffset / pxIOManager->xPartition.usBlkSize );
- ulFATSectorEntry = ulFATOffset % pxIOManager->xPartition.usBlkSize;
- ulLBAAdjust = ulFATSectorEntry / ( ( uint32_t ) pxIOManager->usSectorSize );
- ulRelClusterEntry = ulFATSectorEntry % pxIOManager->usSectorSize;
- ulFATSector = FF_getRealLBA( pxIOManager, ulFATSector );
- ulFATSector += ulLBAAdjust;
- }
- #if ( ffconfigFAT12_SUPPORT != 0 )
- if( ( pxIOManager->xPartition.ucType == FF_T_FAT12 ) &&
- ( FF_isERR( xError ) == pdFALSE ) &&
- ( ulRelClusterEntry == ( uint32_t ) ( ( pxIOManager->usSectorSize - 1 ) ) ) )
- {
- /* Fat Entry SPANS a Sector!
- * It has 4 bits on one sector and 8 bits on the other sector.
- * Handle this in a separate function prvGetFAT12Entry(). */
- ulFATEntry = prvGetFAT12Entry( pxIOManager, &xError, pxFATBuffers, ulFATSector );
- if( ( ulCluster & 0x0001 ) != 0 )
- {
- /* For odd clusters, shift the address 4 bits to the right: */
- ulFATEntry = ( ulFATEntry & 0xfff0 ) >> 4;
- }
- else
- {
- /* For even clusters, take the lower 12 bits: */
- ulFATEntry = ( ulFATEntry & 0x0fff );
- }
- /* Return ulFATEntry, unless xError contains an error. */
- }
- else
- #endif /* ffconfigFAT12_SUPPORT */
- if( FF_isERR( xError ) == pdFALSE )
- {
- /* Handle FAT16, FAT32, and FAT12 (in case the entry lies on a single sector). */
- pxBuffer = prvGetFromFATBuffers( pxIOManager, pxFATBuffers, 0, ulFATSector, &xError, ucMode );
- if( FF_isERR( xError ) )
- {
- xError = FF_GETERROR( xError ) | FF_GETFATENTRY;
- }
- else
- {
- switch( pxIOManager->xPartition.ucType )
- {
- case FF_T_FAT32:
- ulFATEntry = FF_getLong( pxBuffer->pucBuffer, ulRelClusterEntry );
- /* Clear the top 4 bits. */
- ulFATEntry &= 0x0fffffff;
- break;
- case FF_T_FAT16:
- ulFATEntry = ( uint32_t ) FF_getShort( pxBuffer->pucBuffer, ulRelClusterEntry );
- break;
- #if ( ffconfigFAT12_SUPPORT != 0 )
- case FF_T_FAT12:
- ulFATEntry = ( uint32_t ) FF_getShort( pxBuffer->pucBuffer, ulRelClusterEntry );
- /* Entries are either stored as 4 + 8 bits or as 8 + 4 bits,
- * depending on the cluster being odd or even. */
- if( ( ulCluster & 0x0001 ) != 0 )
- {
- /* For odd clusters, shift the address 4 bits to the right: */
- ulFATEntry = ( ulFATEntry & 0xfff0 ) >> 4;
- }
- else
- {
- /* For even clusters, take the lower 12 bits: */
- ulFATEntry = ( ulFATEntry & 0x0fff );
- }
- break;
- #endif /* if ( ffconfigFAT12_SUPPORT != 0 ) */
- default:
- ulFATEntry = 0;
- break;
- }
- if( pxFATBuffers != NULL )
- {
- /* Store the buffer. */
- pxFATBuffers->pxBuffers[ 0 ] = pxBuffer;
- }
- else
- {
- /* Or release it. */
- xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
- }
- } /* if( FF_isERR( xError ) == pdFALSE ) */
- } /* else Handle FAT16, FAT32, and FAT12 (in case the entry lies on a single sector). */
- if( FF_isERR( xError ) )
- {
- /* The sector address 0 is not meaningful and here it is used as the 'error value'. */
- ulFATEntry = 0UL;
- }
- if( pxError != NULL )
- {
- *pxError = xError;
- }
- return ( int32_t ) ulFATEntry;
- } /* FF_getFATEntry() */
- /*-----------------------------------------------------------*/
- /* Write all zero's to all sectors of a given cluster. */
- FF_Error_t FF_ClearCluster( FF_IOManager_t * pxIOManager,
- uint32_t ulCluster )
- {
- FF_Error_t xError = FF_ERR_NONE;
- FF_Buffer_t * pxBuffer = NULL;
- BaseType_t xIndex;
- uint32_t ulBaseLBA;
- /* Calculate from cluster number to a real block address. */
- ulBaseLBA = FF_Cluster2LBA( pxIOManager, ulCluster );
- ulBaseLBA = FF_getRealLBA( pxIOManager, ulBaseLBA );
- for( xIndex = 0; xIndex < ( BaseType_t ) pxIOManager->xPartition.ulSectorsPerCluster; xIndex++ )
- {
- if( xIndex == 0 )
- {
- /* When using the FF_MODE_WR_ONLY flag, the data will not be read from disk.
- * Only in the first round a buffer will be claimed. */
- pxBuffer = FF_GetBuffer( pxIOManager, ulBaseLBA, FF_MODE_WR_ONLY );
- if( pxBuffer == NULL )
- {
- xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_CLEARCLUSTER );
- break;
- }
- memset( pxBuffer->pucBuffer, 0x00, pxIOManager->usSectorSize );
- }
- xError = FF_BlockWrite( pxIOManager, ulBaseLBA + xIndex, 1, pxBuffer->pucBuffer, pdFALSE );
- if( FF_isERR( xError ) )
- {
- break;
- }
- }
- if( pxBuffer != NULL )
- {
- FF_Error_t xTempError;
- /* The contents of the buffer (all zero's) has been written explicitly to disk
- * by calling FF_BlockWrite(). Therefore, the bModified should be cleared. */
- pxBuffer->bModified = pdFALSE;
- /* Releasing the handle will not write anything */
- xTempError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
- if( FF_isERR( xError ) == pdFALSE )
- {
- xError = xTempError;
- }
- }
- return xError;
- }
- /*-----------------------------------------------------------*/
- /**
- * @private
- * @brief Returns the Cluster address of the Cluster number from the beginning of a chain.
- *
- * @param pxIOManager FF_IOManager_t Object
- * @param ulStart Cluster address of the first cluster in the chain.
- * @param ulCount Number of Cluster in the chain,
- *
- *
- *
- **/
- uint32_t FF_TraverseFAT( FF_IOManager_t * pxIOManager,
- uint32_t ulStart,
- uint32_t ulCount,
- FF_Error_t * pxError )
- {
- FF_Error_t xError = FF_ERR_NONE;
- uint32_t ulIndex;
- uint32_t ulFatEntry = ulStart;
- uint32_t ulCurrentCluster = ulStart;
- FF_FATBuffers_t xFATBuffers;
- BaseType_t xTakeLock = FF_Has_Lock( pxIOManager, FF_FAT_LOCK ) == pdFALSE;
- /* xFATBuffers is nothing more than an array of FF_Buffer_t's.
- * One buffer for each FAT copy on disk. */
- FF_InitFATBuffers( &xFATBuffers, FF_MODE_READ );
- if( xTakeLock )
- {
- FF_LockFAT( pxIOManager );
- }
- for( ulIndex = 0; ulIndex < ulCount; ulIndex++ )
- {
- ulFatEntry = FF_getFATEntry( pxIOManager, ulCurrentCluster, &xError, &xFATBuffers );
- if( FF_isERR( xError ) )
- {
- ulFatEntry = 0;
- break;
- }
- if( FF_isEndOfChain( pxIOManager, ulFatEntry ) )
- {
- ulFatEntry = ulCurrentCluster;
- break;
- }
- ulCurrentCluster = ulFatEntry;
- }
- if( xTakeLock )
- {
- FF_UnlockFAT( pxIOManager );
- }
- {
- FF_Error_t xTempError;
- xTempError = FF_ReleaseFATBuffers( pxIOManager, &xFATBuffers );
- if( FF_isERR( xError ) == pdFALSE )
- {
- xError = xTempError;
- }
- }
- *pxError = xError;
- return ulFatEntry;
- }
- /*-----------------------------------------------------------*/
- uint32_t FF_FindEndOfChain( FF_IOManager_t * pxIOManager,
- uint32_t ulStart,
- FF_Error_t * pxError )
- {
- uint32_t ulFatEntry = ulStart;
- FF_Error_t xError;
- if( FF_isEndOfChain( pxIOManager, ulStart ) == pdFALSE )
- {
- /* Traverse FAT for (2^32-1) items/clusters,
- * or until end-of-chain is encountered. */
- ulFatEntry = FF_TraverseFAT( pxIOManager, ulStart, ~0UL, &xError );
- }
- else
- {
- xError = FF_ERR_NONE;
- }
- *pxError = xError;
- return ulFatEntry;
- }
- /*-----------------------------------------------------------*/
- /**
- * @private
- * @brief Tests if the ulFATEntry is an End of Chain Marker.
- *
- * @param pxIOManager FF_IOManager_t Object
- * @param ulFATEntry The fat entry from the FAT table to be checked.
- *
- * @return pdTRUE if it is an end of chain, otherwise pdFALSE.
- *
- **/
- BaseType_t FF_isEndOfChain( FF_IOManager_t * pxIOManager,
- uint32_t ulFATEntry )
- {
- BaseType_t xResult = pdFALSE;
- if( pxIOManager->xPartition.ucType == FF_T_FAT32 )
- {
- if( ( ulFATEntry & 0x0fffffff ) >= 0x0ffffff8 )
- {
- xResult = pdTRUE;
- }
- }
- else if( pxIOManager->xPartition.ucType == FF_T_FAT16 )
- {
- if( ulFATEntry >= 0x0000fff8 )
- {
- xResult = pdTRUE;
- }
- }
- else
- {
- if( ulFATEntry >= 0x00000ff8 )
- {
- xResult = pdTRUE;
- }
- }
- if( ulFATEntry == 0x00000000 )
- {
- xResult = pdTRUE; /* Perhaps trying to read a deleted file! */
- }
- return xResult;
- }
- /*-----------------------------------------------------------*/
- #if ( ffconfigFAT12_SUPPORT != 0 )
- static FF_Error_t prvPutFAT12Entry( FF_IOManager_t * pxIOManager,
- uint32_t ulCluster,
- uint32_t ulValue,
- FF_FATBuffers_t * pxFATBuffers,
- uint32_t ulFATSector )
- {
- FF_Buffer_t * pxBuffer = NULL;
- /* For FAT12 FAT Table Across sector boundary traversal. */
- uint8_t ucBytes[ 2 ];
- /* The function result value. */
- uint32_t ulFATEntry;
- FF_Error_t xError = FF_ERR_NONE;
- BaseType_t xIndex;
- #if ( ffconfigWRITE_BOTH_FATS != 0 )
- const BaseType_t xNumFATs = pxIOManager->xPartition.ucNumFATS;
- #else
- const BaseType_t xNumFATs = 1;
- #endif
- /* This routine will only change 12 out of 16 bits.
- * Get the current 16-bit value, 4 bits shall be preserved. */
- ulFATEntry = prvGetFAT12Entry( pxIOManager, &xError, pxFATBuffers, ulFATSector );
- if( FF_isERR( xError ) == pdFALSE )
- {
- if( ( ulCluster & 0x0001 ) != 0 )
- {
- ulFATEntry &= 0x000F;
- ulValue = ( ulValue << 4 );
- ulValue &= 0xFFF0;
- }
- else
- {
- ulFATEntry &= 0xF000;
- ulValue &= 0x0FFF;
- }
- ulFATEntry |= ulValue;
- /* Write at offset 0 in the array ucBytes. */
- FF_putShort( ucBytes, 0, ( uint16_t ) ulFATEntry );
- for( xIndex = 0;
- xIndex < xNumFATs;
- xIndex++, ulFATSector += pxIOManager->xPartition.ulSectorsPerFAT )
- {
- /* Write the last byte in the first sector. */
- pxBuffer = FF_GetBuffer( pxIOManager, ulFATSector, FF_MODE_WRITE );
- {
- if( pxBuffer == NULL )
- {
- xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_PUTFATENTRY );
- break;
- }
- FF_putChar( pxBuffer->pucBuffer, ( uint16_t ) ( pxIOManager->usSectorSize - 1 ), ucBytes[ 0 ] );
- }
- xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
- if( FF_isERR( xError ) )
- {
- break;
- }
- /* Write the first byte in the subsequent sector. */
- pxBuffer = FF_GetBuffer( pxIOManager, ulFATSector + 1, FF_MODE_WRITE );
- {
- if( pxBuffer == NULL )
- {
- xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_PUTFATENTRY );
- break;
- }
- FF_putChar( pxBuffer->pucBuffer, 0x0000, ucBytes[ 1 ] );
- }
- xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
- if( FF_isERR( xError ) )
- {
- break;
- }
- } /* for ( xIndex = 0; xIndex < xNumFATs; xIndex++ ) */
- }
- return xError;
- }
- #endif /* if ( ffconfigFAT12_SUPPORT != 0 ) */
- /**
- * @private
- * @brief Writes a new Entry to the FAT Tables.
- *
- * @param pxIOManager IOMAN object.
- * @param ulCluster Cluster Number to be modified.
- * @param ulValue The value to store.
- **/
- FF_Error_t FF_putFATEntry( FF_IOManager_t * pxIOManager,
- uint32_t ulCluster,
- uint32_t ulValue,
- FF_FATBuffers_t * pxFATBuffers )
- {
- FF_Buffer_t * pxBuffer;
- uint32_t ulFATOffset;
- uint32_t ulFATSector = 0;
- uint32_t ulFATSectorEntry;
- uint32_t ulFATEntry;
- uint32_t ulLBAAdjust;
- uint32_t ulRelClusterEntry = 0;
- BaseType_t xIndex;
- FF_Error_t xError = FF_ERR_NONE;
- #if ( ffconfigWRITE_BOTH_FATS != 0 )
- const BaseType_t xNumFATs = pxIOManager->xPartition.ucNumFATS;
- #else
- const BaseType_t xNumFATs = 1;
- #endif
- FF_Assert_Lock( pxIOManager, FF_FAT_LOCK );
- /* Avoid corrupting the disk. */
- if( ( ulCluster == 0ul ) || ( ulCluster >= pxIOManager->xPartition.ulNumClusters ) )
- {
- /* find a more specific error code. */
- xError = ( FF_Error_t ) ( FF_ERR_IOMAN_NOT_ENOUGH_FREE_SPACE | FF_PUTFATENTRY );
- }
- else
- {
- if( pxIOManager->xPartition.ucType == FF_T_FAT32 )
- {
- ulFATOffset = ulCluster * 4;
- }
- else if( pxIOManager->xPartition.ucType == FF_T_FAT16 )
- {
- ulFATOffset = ulCluster * 2;
- }
- else /* pxIOManager->xPartition.ucType == FF_T_FAT12 */
- {
- ulFATOffset = ulCluster + ( ulCluster / 2 );
- }
- ulFATSector = pxIOManager->xPartition.ulFATBeginLBA + ( ulFATOffset / pxIOManager->xPartition.usBlkSize );
- ulFATSectorEntry = ulFATOffset % pxIOManager->xPartition.usBlkSize;
- ulLBAAdjust = ulFATSectorEntry / ( ( uint32_t ) pxIOManager->usSectorSize );
- ulRelClusterEntry = ulFATSectorEntry % pxIOManager->usSectorSize;
- ulFATSector = FF_getRealLBA( pxIOManager, ulFATSector );
- ulFATSector += ulLBAAdjust;
- }
- #if ( ffconfigFAT12_SUPPORT != 0 )
- if( ( pxIOManager->xPartition.ucType == FF_T_FAT12 ) &&
- ( FF_isERR( xError ) == pdFALSE ) &&
- ( ulRelClusterEntry == ( uint32_t ) ( ( pxIOManager->usSectorSize - 1 ) ) ) )
- {
- /* The special case in which one FAT12 entries is divided over 2 sectors.
- * Treat this in a separate function. */
- xError = prvPutFAT12Entry( pxIOManager, ulCluster, ulValue, pxFATBuffers, ulFATSector );
- /* Return xError. */
- }
- else
- #endif /* ffconfigFAT12_SUPPORT */
- if( FF_isERR( xError ) == pdFALSE )
- {
- /* Handle FAT16, FAT32, and FAT12 (in case the entry lies on a single sector). */
- for( xIndex = 0;
- xIndex < xNumFATs;
- xIndex++, ulFATSector += pxIOManager->xPartition.ulSectorsPerFAT )
- {
- pxBuffer = prvGetFromFATBuffers( pxIOManager, pxFATBuffers, xIndex, ulFATSector, &xError, FF_MODE_WRITE );
- if( FF_isERR( xError ) )
- {
- xError = FF_GETERROR( xError ) | FF_PUTFATENTRY;
- break;
- }
- if( pxIOManager->xPartition.ucType == FF_T_FAT32 )
- {
- /* Clear the top 4 bits. */
- ulValue &= 0x0fffffff;
- FF_putLong( pxBuffer->pucBuffer, ulRelClusterEntry, ulValue );
- }
- else if( pxIOManager->xPartition.ucType == FF_T_FAT16 )
- {
- FF_putShort( pxBuffer->pucBuffer, ulRelClusterEntry, ( uint16_t ) ulValue );
- }
- else
- {
- ulFATEntry = ( uint32_t ) FF_getShort( pxBuffer->pucBuffer, ulRelClusterEntry );
- if( ( ulCluster & 0x0001 ) != 0 )
- {
- ulFATEntry &= 0x000F;
- ulValue = ( ulValue << 4 );
- ulValue &= 0xFFF0;
- }
- else
- {
- ulFATEntry &= 0xF000;
- ulValue &= 0x0FFF;
- }
- FF_putShort( pxBuffer->pucBuffer, ulRelClusterEntry, ( uint16_t ) ( ulFATEntry | ulValue ) );
- }
- if( ( xIndex < ffconfigBUF_STORE_COUNT ) && ( pxFATBuffers != NULL ) )
- {
- /* Store it for later use. */
- pxFATBuffers->pxBuffers[ xIndex ] = pxBuffer;
- pxFATBuffers->ucMode = FF_MODE_WRITE;
- }
- else
- {
- xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
- if( FF_isERR( xError ) )
- {
- break;
- }
- }
- }
- }
- /* FF_putFATEntry() returns just an error code, not an address. */
- return xError;
- } /* FF_putFATEntry() */
- /*-----------------------------------------------------------*/
- /**
- * @private
- * @brief Finds a Free Cluster and returns its number.
- *
- * @param pxIOManager IOMAN Object.
- *
- * @return The number of the cluster found to be free.
- * @return 0 on error.
- **/
- #if ( ffconfigFAT12_SUPPORT != 0 )
- static uint32_t prvFindFreeClusterSimple( FF_IOManager_t * pxIOManager,
- FF_Error_t * pxError )
- {
- FF_Error_t xError = FF_ERR_NONE;
- uint32_t ulCluster = 0;
- uint32_t ulFATEntry;
- FF_FATBuffers_t xFATBuffers;
- FF_InitFATBuffers( &xFATBuffers, FF_MODE_READ );
- for( ulCluster = pxIOManager->xPartition.ulLastFreeCluster;
- ulCluster < pxIOManager->xPartition.ulNumClusters;
- ulCluster++ )
- {
- ulFATEntry = FF_getFATEntry( pxIOManager, ulCluster, &xError, &xFATBuffers );
- if( FF_isERR( xError ) )
- {
- break;
- }
- if( ulFATEntry == 0 )
- {
- pxIOManager->xPartition.ulLastFreeCluster = ulCluster;
- break;
- }
- }
- {
- FF_Error_t xTempError;
- xTempError = FF_ReleaseFATBuffers( pxIOManager, &xFATBuffers );
- if( FF_isERR( xError ) == pdFALSE )
- {
- xError = xTempError;
- }
- }
- if( ( FF_isERR( xError ) == pdFALSE ) &&
- ( ulCluster == pxIOManager->xPartition.ulNumClusters ) )
- {
- /* There is no free cluster any more. */
- ulCluster = 0;
- xError = FF_FINDFREECLUSTER | FF_ERR_IOMAN_NOT_ENOUGH_FREE_SPACE;
- }
- *pxError = xError;
- return ulCluster;
- }
- #endif /* if ( ffconfigFAT12_SUPPORT != 0 ) */
- /*-----------------------------------------------------------*/
- uint32_t FF_FindFreeCluster( FF_IOManager_t * pxIOManager,
- FF_Error_t * pxError,
- BaseType_t xDoClaim )
- {
- FF_Error_t xError = FF_ERR_NONE;
- FF_Buffer_t * pxBuffer = NULL;
- uint32_t x, ulCluster;
- uint32_t ulFATSectorEntry;
- uint32_t ulEntriesPerSector;
- uint32_t ulFATEntry = 1;
- const BaseType_t xEntrySize = ( pxIOManager->xPartition.ucType == FF_T_FAT32 ) ? 4 : 2;
- const uint32_t uNumClusters = pxIOManager->xPartition.ulNumClusters;
- BaseType_t xTakeLock = FF_Has_Lock( pxIOManager, FF_FAT_LOCK ) == pdFALSE;
- if( xTakeLock )
- {
- FF_LockFAT( pxIOManager );
- }
- ulCluster = pxIOManager->xPartition.ulLastFreeCluster;
- #if ( ffconfigFAT12_SUPPORT != 0 )
- /* FAT12 tables are too small to optimise, and would make it very complicated! */
- if( pxIOManager->xPartition.ucType == FF_T_FAT12 )
- {
- ulCluster = prvFindFreeClusterSimple( pxIOManager, &xError );
- }
- else
- #endif
- {
- #if ( ffconfigFSINFO_TRUSTED != 0 )
- {
- /* If 'ffconfigFSINFO_TRUSTED', the contents of the field 'ulLastFreeCluster' is trusted.
- * Only ready it in case of FAT32 and only during the very first time, i.e. when
- * ulLastFreeCluster is still zero. */
- if( ( pxIOManager->xPartition.ucType == FF_T_FAT32 ) && ( pxIOManager->xPartition.ulLastFreeCluster == 0ul ) )
- {
- pxBuffer = FF_GetBuffer( pxIOManager, pxIOManager->xPartition.ulFSInfoLBA, FF_MODE_READ );
- if( pxBuffer == NULL )
- {
- xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_FINDFREECLUSTER );
- }
- else
- {
- if( ( FF_getLong( pxBuffer->pucBuffer, 0 ) == 0x41615252 ) &&
- ( FF_getLong( pxBuffer->pucBuffer, 484 ) == 0x61417272 ) )
- {
- ulCluster = FF_getLong( pxBuffer->pucBuffer, 492 );
- }
- xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
- pxBuffer = NULL;
- }
- }
- }
- #endif /* if ( ffconfigFSINFO_TRUSTED != 0 ) */
- if( FF_isERR( xError ) == pdFALSE )
- {
- uint32_t ulFATSector;
- uint32_t ulFATOffset;
- ulEntriesPerSector = pxIOManager->usSectorSize / xEntrySize;
- ulFATOffset = ulCluster * xEntrySize;
- /* Start from a sector where the first free entry is expected,
- * and iterate through every FAT sector. */
- for( ulFATSector = ( ulFATOffset / pxIOManager->xPartition.usBlkSize );
- ulFATSector < pxIOManager->xPartition.ulSectorsPerFAT;
- ulFATSector++ )
- {
- pxBuffer = FF_GetBuffer( pxIOManager, pxIOManager->xPartition.ulFATBeginLBA + ulFATSector, FF_MODE_READ );
- if( pxBuffer == NULL )
- {
- xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_FINDFREECLUSTER );
- break;
- }
- for( x = ( ulCluster % ulEntriesPerSector ); x < ulEntriesPerSector; x++ )
- {
- /* Double-check: don't use non-existing clusters */
- if( ulCluster >= uNumClusters )
- {
- xError = ( FF_Error_t ) ( FF_ERR_IOMAN_NOT_ENOUGH_FREE_SPACE | FF_FINDFREECLUSTER );
- break;
- }
- ulFATSectorEntry = ulFATOffset % pxIOManager->xPartition.usBlkSize;
- if( pxIOManager->xPartition.ucType == FF_T_FAT32 )
- {
- ulFATEntry = FF_getLong( pxBuffer->pucBuffer, ulFATSectorEntry );
- /* Clear the top 4 bits. */
- ulFATEntry &= 0x0fffffff;
- }
- else
- {
- ulFATEntry = ( uint32_t ) FF_getShort( pxBuffer->pucBuffer, ulFATSectorEntry );
- }
- if( ulFATEntry == 0x00000000 )
- {
- /* Break and return 'ulCluster' */
- break;
- }
- ulFATOffset += xEntrySize;
- ulCluster++;
- }
- xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
- pxBuffer = NULL;
- if( FF_isERR( xError ) )
- {
- break;
- }
- if( ulFATEntry == 0x00000000 )
- {
- /* And break from the outer loop. */
- break;
- }
- }
- if( ( FF_isERR( xError ) == pdFALSE ) &&
- ( ulFATSector == pxIOManager->xPartition.ulSectorsPerFAT ) )
- {
- xError = ( FF_Error_t ) ( FF_ERR_IOMAN_NOT_ENOUGH_FREE_SPACE | FF_FINDFREECLUSTER );
- }
- } /* if( FF_isERR( xError ) == pdFALSE ) */
- } /* if( pxIOManager->xPartition.ucType != FF_T_FAT12 ) */
- if( FF_isERR( xError ) )
- {
- ulCluster = 0UL;
- }
- if( ( ulCluster != 0UL ) && ( xDoClaim != pdFALSE ) )
- {
- FF_Error_t xTempError;
- /* Found a free cluster! */
- pxIOManager->xPartition.ulLastFreeCluster = ulCluster + 1;
- xTempError = FF_putFATEntry( pxIOManager, ulCluster, 0xFFFFFFFF, NULL );
- if( FF_isERR( xError ) == pdFALSE )
- {
- xError = xTempError;
- }
- if( FF_isERR( xError ) )
- {
- ulCluster = 0UL;
- }
- }
- if( xTakeLock )
- {
- FF_UnlockFAT( pxIOManager );
- }
- *pxError = xError;
- return ulCluster;
- } /* FF_FindFreeCluster */
- /*-----------------------------------------------------------*/
- /**
- * @private
- * @brief Creates a Cluster Chain
- * @return > 0 New created cluster
- * @return = 0 See pxError
- **/
- uint32_t FF_CreateClusterChain( FF_IOManager_t * pxIOManager,
- FF_Error_t * pxError )
- {
- uint32_t ulStartCluster;
- FF_Error_t xError = FF_ERR_NONE;
- FF_LockFAT( pxIOManager );
- {
- ulStartCluster = FF_FindFreeCluster( pxIOManager, &xError, pdTRUE );
- }
- FF_UnlockFAT( pxIOManager );
- if( ulStartCluster != 0L )
- {
- xError = FF_DecreaseFreeClusters( pxIOManager, 1 );
- }
- *pxError = xError;
- return ulStartCluster;
- }
- /*-----------------------------------------------------------*/
- uint32_t FF_GetChainLength( FF_IOManager_t * pxIOManager,
- uint32_t ulStartCluster,
- uint32_t * pulEndOfChain,
- FF_Error_t * pxError )
- {
- uint32_t ulLength = 0;
- FF_FATBuffers_t xFATBuffers;
- FF_Error_t xError = FF_ERR_NONE;
- FF_InitFATBuffers( &xFATBuffers, FF_MODE_READ );
- FF_LockFAT( pxIOManager );
- {
- while( FF_isEndOfChain( pxIOManager, ulStartCluster ) == pdFALSE )
- {
- ulStartCluster = FF_getFATEntry( pxIOManager, ulStartCluster, &xError, &xFATBuffers );
- if( FF_isERR( xError ) )
- {
- ulLength = 0;
- break;
- }
- ulLength++;
- }
- if( pulEndOfChain != NULL )
- {
- /* _HT_
- * ulStartCluster has just been tested as an end-of-chain token.
- * Not sure if the caller expects this. */
- *pulEndOfChain = ulStartCluster;
- }
- xError = FF_ReleaseFATBuffers( pxIOManager, &xFATBuffers );
- }
- FF_UnlockFAT( pxIOManager );
- *pxError = xError;
- return ulLength;
- }
- /*-----------------------------------------------------------*/
- /**
- * @private
- * @brief Free's Disk space by freeing unused links on Cluster Chains
- *
- * @param pxIOManager, IOMAN object.
- * @param ulStartCluster Cluster Number that starts the chain.
- * @param ulCount Number of Clusters from the end of the chain to unlink.
- * @param ulCount 0 Means Free the entire chain (delete file).
- * @param ulCount 1 Means mark the start cluster with EOF.
- *
- * @return 0 On Success.
- * @return -1 If the device driver failed to provide access.
- *
- **/
- FF_Error_t FF_UnlinkClusterChain( FF_IOManager_t * pxIOManager,
- uint32_t ulStartCluster,
- BaseType_t xDoTruncate )
- {
- uint32_t ulFATEntry;
- uint32_t ulCurrentCluster;
- uint32_t ulLength = 0;
- uint32_t ulLastFree = ulStartCluster;
- FF_Error_t xTempError;
- FF_Error_t xError = FF_ERR_NONE;
- FF_FATBuffers_t xFATBuffers;
- BaseType_t xTakeLock = FF_Has_Lock( pxIOManager, FF_FAT_LOCK ) == pdFALSE;
- if( xTakeLock )
- {
- FF_LockFAT( pxIOManager );
- }
- FF_InitFATBuffers( &xFATBuffers, FF_MODE_WRITE );
- ulFATEntry = ulStartCluster;
- /* Free all clusters in the chain! */
- ulCurrentCluster = ulStartCluster;
- ulFATEntry = ulCurrentCluster;
- do
- {
- /* Sector will now be fetched in write-mode. */
- ulFATEntry = FF_getFATEntry( pxIOManager, ulFATEntry, &xError, &xFATBuffers );
- if( FF_isERR( xError ) )
- {
- break;
- }
- if( ( xDoTruncate != pdFALSE ) && ( ulCurrentCluster == ulStartCluster ) )
- {
- xError = FF_putFATEntry( pxIOManager, ulCurrentCluster, 0xFFFFFFFF, &xFATBuffers );
- }
- else
- {
- xError = FF_putFATEntry( pxIOManager, ulCurrentCluster, 0x00000000, &xFATBuffers );
- ulLength++;
- }
- if( FF_isERR( xError ) )
- {
- break;
- }
- if( ulLastFree > ulCurrentCluster )
- {
- ulLastFree = ulCurrentCluster;
- }
- ulCurrentCluster = ulFATEntry;
- } while( FF_isEndOfChain( pxIOManager, ulFATEntry ) == pdFALSE );
- if( FF_isERR( xError ) == pdFALSE )
- {
- if( pxIOManager->xPartition.ulLastFreeCluster > ulLastFree )
- {
- pxIOManager->xPartition.ulLastFreeCluster = ulLastFree;
- }
- }
- xTempError = FF_ReleaseFATBuffers( pxIOManager, &xFATBuffers );
- if( FF_isERR( xError ) == pdFALSE )
- {
- xError = xTempError;
- }
- if( xTakeLock )
- {
- FF_UnlockFAT( pxIOManager );
- }
- if( ulLength != 0 )
- {
- xTempError = FF_IncreaseFreeClusters( pxIOManager, ulLength );
- if( FF_isERR( xError ) == pdFALSE )
- {
- xError = xTempError;
- }
- }
- return xError;
- }
- /*-----------------------------------------------------------*/
- #if ( ffconfigFAT12_SUPPORT != 0 )
- static uint32_t prvCountFreeClustersSimple( FF_IOManager_t * pxIOManager,
- FF_Error_t * pxError )
- {
- FF_Error_t xError = FF_ERR_NONE;
- uint32_t ulIndex;
- uint32_t ulFATEntry;
- uint32_t ulFreeClusters = 0;
- const uint32_t xTotalClusters =
- pxIOManager->xPartition.ulDataSectors / pxIOManager->xPartition.ulSectorsPerCluster;
- for( ulIndex = 0; ulIndex < xTotalClusters; ulIndex++ )
- {
- ulFATEntry = FF_getFATEntry( pxIOManager, ulIndex, &xError, NULL );
- if( FF_isERR( xError ) )
- {
- break;
- }
- if( ulFATEntry == 0UL )
- {
- ulFreeClusters++;
- }
- }
- *pxError = xError;
- return ulFreeClusters;
- }
- #endif /* if ( ffconfigFAT12_SUPPORT != 0 ) */
- /*-----------------------------------------------------------*/
- uint32_t FF_CountFreeClusters( FF_IOManager_t * pxIOManager,
- FF_Error_t * pxError )
- {
- FF_Error_t xError = FF_ERR_NONE;
- FF_Buffer_t * pxBuffer;
- uint32_t ulIndex, x;
- uint32_t ulFATEntry;
- uint32_t ulEntriesPerSector;
- uint32_t ulFreeClusters = 0;
- uint32_t ClusterNum = 0;
- BaseType_t xInfoKnown = pdFALSE;
- BaseType_t xTakeLock = FF_Has_Lock( pxIOManager, FF_FAT_LOCK ) == pdFALSE;
- if( xTakeLock )
- {
- FF_LockFAT( pxIOManager );
- }
- #if ( ffconfigFAT12_SUPPORT != 0 )
- /* FAT12 tables are too small to optimise, and would make it very complicated! */
- if( pxIOManager->xPartition.ucType == FF_T_FAT12 )
- {
- ulFreeClusters = prvCountFreeClustersSimple( pxIOManager, &xError );
- }
- else
- #endif
- {
- /* For FAT16 and FAT32 */
- #if ( ffconfigFSINFO_TRUSTED != 0 )
- {
- /* If 'ffconfigFSINFO_TRUSTED', the contents of the field 'ulFreeClusterCount' is trusted. */
- if( pxIOManager->xPartition.ucType == FF_T_FAT32 )
- {
- pxBuffer = FF_GetBuffer( pxIOManager, pxIOManager->xPartition.ulFSInfoLBA, FF_MODE_READ );
- if( pxBuffer == NULL )
- {
- xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_COUNTFREECLUSTERS );
- }
- else
- {
- if( ( FF_getLong( pxBuffer->pucBuffer, 0 ) == 0x41615252 ) &&
- ( FF_getLong( pxBuffer->pucBuffer, 484 ) == 0x61417272 ) )
- {
- ulFreeClusters = FF_getLong( pxBuffer->pucBuffer, 488 );
- if( ulFreeClusters != ~0ul )
- {
- xInfoKnown = pdTRUE;
- }
- else
- {
- ulFreeClusters = 0ul;
- }
- }
- xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
- pxBuffer = NULL;
- if( xInfoKnown != pdFALSE )
- {
- pxIOManager->xPartition.ulFreeClusterCount = ulFreeClusters;
- }
- }
- }
- }
- #endif /* if ( ffconfigFSINFO_TRUSTED != 0 ) */
- if( ( xInfoKnown == pdFALSE ) && ( pxIOManager->xPartition.usBlkSize != 0 ) )
- {
- if( pxIOManager->xPartition.ucType == FF_T_FAT32 )
- {
- ulEntriesPerSector = pxIOManager->usSectorSize / 4;
- }
- else
- {
- ulEntriesPerSector = pxIOManager->usSectorSize / 2;
- }
- for( ulIndex = 0; ulIndex < pxIOManager->xPartition.ulSectorsPerFAT; ulIndex++ )
- {
- pxBuffer = FF_GetBuffer( pxIOManager, pxIOManager->xPartition.ulFATBeginLBA + ulIndex, FF_MODE_READ );
- if( pxBuffer == NULL )
- {
- xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_COUNTFREECLUSTERS );
- break;
- }
- #if USE_SOFT_WDT
- {
- /* _HT_ : FF_CountFreeClusters was a little too busy, have it call the WDT and sleep */
- clearWDT();
- if( ( ( ulIndex + 1 ) % 32 ) == 0 )
- {
- FF_Sleep( 1 );
- }
- }
- #endif
- for( x = 0; x < ulEntriesPerSector; x++ )
- {
- if( pxIOManager->xPartition.ucType == FF_T_FAT32 )
- {
- /* Clearing the top 4 bits. */
- ulFATEntry = FF_getLong( pxBuffer->pucBuffer, x * 4 ) & 0x0fffffff;
- }
- else
- {
- ulFATEntry = ( uint32_t ) FF_getShort( pxBuffer->pucBuffer, x * 2 );
- }
- if( ulFATEntry == 0ul )
- {
- ulFreeClusters++;
- }
- /* FAT table might not be cluster aligned. */
- if( ClusterNum > pxIOManager->xPartition.ulNumClusters )
- {
- /* Stop counting if that's the case. */
- break;
- }
- ClusterNum++;
- }
- xError = FF_ReleaseBuffer( pxIOManager, pxBuffer );
- pxBuffer = NULL;
- if( FF_isERR( xError ) )
- {
- break;
- }
- if( ClusterNum > pxIOManager->xPartition.ulNumClusters )
- {
- /* Break out of 2nd loop too ^^ */
- break;
- }
- /* ulFreeClusters is -2 because the first 2 fat entries in the table are reserved. */
- if( ulFreeClusters > pxIOManager->xPartition.ulNumClusters )
- {
- ulFreeClusters = pxIOManager->xPartition.ulNumClusters;
- }
- } /* for( ulIndex = 0; ulIndex < pxIOManager->xPartition.ulSectorsPerFAT; ulIndex++ ) */
- }
- }
- if( xTakeLock )
- {
- FF_UnlockFAT( pxIOManager );
- }
- if( FF_isERR( xError ) )
- {
- ulFreeClusters = 0;
- }
- *pxError = xError;
- return ulFreeClusters;
- }
- /*-----------------------------------------------------------*/
- #if ( ffconfig64_NUM_SUPPORT != 0 )
- uint64_t FF_GetFreeSize( FF_IOManager_t * pxIOManager,
- FF_Error_t * pxError )
- {
- FF_Error_t xError = FF_ERR_NONE;
- uint32_t ulFreeClusters;
- uint64_t ulFreeSize = 0;
- if( pxIOManager != NULL )
- {
- if( pxIOManager->xPartition.ulFreeClusterCount == 0ul )
- {
- FF_LockFAT( pxIOManager );
- {
- pxIOManager->xPartition.ulFreeClusterCount = FF_CountFreeClusters( pxIOManager, &xError );
- }
- FF_UnlockFAT( pxIOManager );
- }
- ulFreeClusters = pxIOManager->xPartition.ulFreeClusterCount;
- ulFreeSize = ( uint64_t )
- ( ( uint64_t ) ulFreeClusters * ( uint64_t )
- ( ( uint64_t ) pxIOManager->xPartition.ulSectorsPerCluster *
- ( uint64_t ) pxIOManager->xPartition.usBlkSize ) );
- }
- if( pxError != NULL )
- {
- *pxError = xError;
- }
- return ulFreeSize;
- }
- #else /* if ( ffconfig64_NUM_SUPPORT != 0 ) */
- uint32_t FF_GetFreeSize( FF_IOManager_t * pxIOManager,
- FF_Error_t * pxError )
- {
- FF_Error_t xError = FF_ERR_NONE;
- uint32_t ulFreeClusters;
- uint32_t ulFreeSize = 0;
- if( pxIOManager != NULL )
- {
- if( pxIOManager->xPartition.ulFreeClusterCount == 0ul )
- {
- FF_LockFAT( pxIOManager );
- {
- pxIOManager->xPartition.ulFreeClusterCount = FF_CountFreeClusters( pxIOManager, &xError );
- }
- FF_UnlockFAT( pxIOManager );
- }
- ulFreeClusters = pxIOManager->xPartition.ulFreeClusterCount;
- ulFreeSize = ( uint32_t )
- ( ( uint32_t ) ulFreeClusters * ( uint32_t )
- ( ( uint32_t ) pxIOManager->xPartition.ulSectorsPerCluster *
- ( uint32_t ) pxIOManager->xPartition.usBlkSize ) );
- }
- if( pxError != NULL )
- {
- *pxError = xError;
- }
- return ulFreeSize;
- }
- #endif /* ffconfig64_NUM_SUPPORT */
- /*-----------------------------------------------------------*/
|