[FULLFAT]

- Update FullFat to the latest SVN code on James' recommendation.
- This release has many advantages over the previous, including full UTF-8 and UTF-16 support and the ability to modify attributes and timestamps. All of which are important for ros.
- It currently has a few warnings (in both gcc and msc), so I've had to turn allow warnings on.

svn path=/trunk/; revision=51229
This commit is contained in:
Ged Murphy 2011-04-02 16:31:43 +00:00
parent 888f3912cb
commit 271454653d
26 changed files with 3972 additions and 1458 deletions

View file

@ -34,108 +34,138 @@
Here you can change the configuration of FullFAT as appropriate to your Here you can change the configuration of FullFAT as appropriate to your
platform. platform.
*/ */
//---------- ENDIANESS //---------- ENDIANESS
#define FF_LITTLE_ENDIAN // Choosing the Byte-order of your system is important. #define FF_LITTLE_ENDIAN // Choosing the Byte-order of your system is important.
//#define FF_BIG_ENDIAN // You may be able to provide better Byte-order swapping routines to FullFAT. //#define FF_BIG_ENDIAN // You may be able to provide better Byte-order swapping routines to FullFAT.
// See ff_memory.c for more information. // See ff_memory.c for more information.
//---------- LFN (Long File-name) SUPPORT //---------- LFN (Long File-name) SUPPORT
#define FF_LFN_SUPPORT // Comment this out if you don't want to worry about Patent Issues. #define FF_LFN_SUPPORT // Comment this out if you don't want to worry about Patent Issues.
// FullFAT works great with LFNs and without. You choose, its your project! // FullFAT works great with LFNs and without. You choose, its your project!
//---------- LEGAL LFNS //#define FF_INCLUDE_SHORT_NAME // HT addition, in 'FF_DIRENT', beside FileName, ShortName will be filled as well
//#define FF_LEGAL_LFNS // Enabling this define causes FullFAT to not infringe on any of Microsoft's patents when making LFN names. // Useful for debugging, but also some situations its useful to know both.
// To do this, it will only create LFNs and no shortnames. Microsofts patents are only relevent when mapping //---------- SHORTNAMES CAN USE THE CASE BITS
// a shortname to a long name. This is the same way that Linux gets around the FAT legal issues: #define FF_SHORTNAME_CASE // Works for XP+ e.g. short.TXT or SHORT.txt.
// see http://lkml.org/lkml/2009/6/26/314
//
// Enabling this may break compatibility with devices that cannot read LFN filenames.
// Enabling this option causes no compatibility issues when reading any media.
//---------- TIME SUPPORT
#define FF_TIME_SUPPORT // Should FullFAT use time stamping. Only if you have provided the relevant time drivers in ff_time.c
// Note, by default ff_time.c is set-up for the Windows Demonstration. Please see ff_time.c to disable.
//---------- FILE SPACE ALLOCATION PERFORMANCE
// Uncomment the prefered method. (Can only choose a single method).
#define FF_ALLOC_DEFAULT // Only allocate as much as is needed. (Provides good performance, without wasting space).
//#define FF_ALLOC_DOUBLE // Doubles the size of a file each time allocation is required. (When high-performance writing is required).
//---------- Use Native STDIO.h
//#define FF_USE_NATIVE_STDIO // Makes FullFAT conform to values provided by your native STDIO.h file.
//---------- FREE SPACE CALCULATION
//#define FF_MOUNT_FIND_FREE // Uncomment this option to check for Freespace on a volume mount. (Performance Penalty while mounting).
// If not done in the mount, it will be done on the first call to FF_GetFreeSize() function.
//---------- PATH CACHE
#define FF_PATH_CACHE // Enables a simply Path Caching mechanism that increases performance of repeated operations
// within the same path. E.g. a copy \dir1\*.* \dir2\*.* command.
// This command requires FF_MAX_PATH number of bytes of memory. (Defined below, default 2600).
//---------- BLKDEV USES SEMAPHORE
#define FF_BLKDEV_USES_SEM // When defined, each call to fnReadBlocks and fnWriteBlocks will be done while semaphore is locked
// See also ff_safety.c
// (HT addition)
#define FF_PATH_CACHE_DEPTH 2 // The Number of PATH's to Cache. //---------- UNICODE SUPPORT
//#define FF_UNICODE_SUPPORT // If this is defined, then all of FullFAT's API's will expect to receive UTF-16 formatted strings.
// FF_FindFirst() and FF_FindNext() will also return Filenames in UTF-16 format.
// NOTE: This option may cause FullFAT to not "Clean-compile" when using GCC. This is because
// pedantically GCC refuses to accept C99 library functions, unless the -std=c99 flag is used.
// To use UNICODE (UTF-16, or UTF-32 depending on the size of wchar_t) you must have a C99 compliant
// compiler and library.
//---------- DON'T USE MALLOC //#define FF_UNICODE_UTF8_SUPPORT // If this is defined, then all of FullFAT's API's will expect to receive UTF-8 formatted strings.
//#define FF_NO_MALLOC // FF_FindFirst() and FF_FindNext() will also return Filenames in UTF-8 format.
#define FF_MALLOC(aSize) malloc(aSize) // Note the 2 UNICODE options are mutually exclusive. Only one can be enabled.
#define FF_FREE(apPtr) free(apPtr)
//#define FF_INLINE_MEMORY_ACCESS
//#define FF_INLINE static __forceinline // Keywords to inline functions (Windows)
#define FF_INLINE static inline // Standard for GCC
//---------- Hash Table Support
//#define FF_HASH_TABLE_SUPPORT // Enable HASH to speed up file creation.
#ifdef FF_HASH_TABLE_SUPPORT
#define FF_HASH_FUNCTION CRC16
//#define FF_HASH_FUNCTION CRC8
#endif
// Ensure that dirents are big enough to hold the maximum UTF-8 sequence.
//---------- FAT12 SUPPORT //---------- FAT12 SUPPORT
#define FF_FAT12_SUPPORT // Enable FAT12 Suppport. You can reduce the code-size by commenting this out. #define FF_FAT12_SUPPORT // Enable FAT12 Suppport. You can reduce the code-size by commenting this out.
// If you don't need FAT12 support, why have it. FAT12 is more complex to process, // If you don't need FAT12 support, why have it. FAT12 is more complex to process,
// therefore savings can be made by not having it. // therefore savings can be made by not having it.
//---------- TIME SUPPORT
#define FF_TIME_SUPPORT // Should FullFAT use time stamping. Only if you have provided the relevant time drivers in ff_time.c
// Note, by default ff_time.c is set-up for the Windows Demonstration. Please see ff_time.c to disable.
//---------- FILE SPACE ALLOCATION PERFORMANCE
// Uncomment the prefered method. (Can only choose a single method).
#define FF_ALLOC_DEFAULT // Only allocate as much as is needed. (Provides good performance, without wasting space).
//#define FF_ALLOC_DOUBLE // Doubles the size of a file each time allocation is required. (When high-performance writing is required).
//---------- Use Native STDIO.h
//#define FF_USE_NATIVE_STDIO // Makes FullFAT conform to values provided by your native STDIO.h file.
//---------- FREE SPACE CALCULATION
//#define FF_MOUNT_FIND_FREE // Uncomment this option to check for Freespace on a volume mount. (Performance Penalty while mounting).
// If not done in the mount, it will be done on the first call to FF_GetFreeSize() function.
//---------- FIND API WILD-CARD SUPPORT
#define FF_FINDAPI_ALLOW_WILDCARDS // Defined to enable Wild-cards in the API. Disabling this, makes the API consistent with 1.0.x series.
#define FF_WILDCARD_CASE_INSENSITIVE // Alter the case insensitivity of the Wild-card checking behaviour.
//---------- PATH CACHE ----------
#define FF_PATH_CACHE // Enables a simply Path Caching mechanism that increases performance of repeated operations
// within the same path. E.g. a copy \dir1\*.* \dir2\*.* command.
// This command requires FF_MAX_PATH number of bytes of memory. (Defined below, default 2600).
#define FF_PATH_CACHE_DEPTH 5 // The Number of PATH's to Cache. (Memory Requirement ~= FF_PATH_CACHE_DEPTH * FF_MAX_PATH).
//---------- HASH CACHE // Speed up File-creation with a HASH table. Provides up to 20x performance boost.
//#define FF_HASH_CACHE // Enable HASH to speed up file creation.
#define FF_HASH_CACHE_DEPTH 10 // Number of Directories to be Hashed. (For CRC16 memory is 8KB * DEPTH)
#define FF_HASH_FUNCTION CRC16 // Choose a 16-bit hash.
//#define FF_HASH_FUNCTION CRC8 // Choose an 8-bit hash.
//---------- BLKDEV USES SEMAPHORE
#define FF_BLKDEV_USES_SEM // When defined, each call to fnReadBlocks and fnWriteBlocks will be done while semaphore is locked
// See also ff_safety.c
// (HT addition) - Thanks to Hein Tibosch
//---------- MALLOC
// These should map on to platform specific memory allocators.
#define FF_MALLOC(aSize) malloc(aSize)
#define FF_FREE(apPtr) free(apPtr)
//---------- IN-LINE FUNCTIONS
//---------- INLINE KeyWord // Define FF_INLINE as your compiler's inline keyword. This is placed before the type qualifier.
#define FF_INLINE static __forceinline // Keywords to inline functions (Windows)
//#define FF_INLINE static inline // Standard for GCC
//---------- Inline Memory Independence Routines for better performance, but bigger codesize.
//#define FF_INLINE_MEMORY_ACCESS
//---------- Inline Block Calculation Routines for slightly better performance in critical sections.
//#define FF_INLINE_BLOCK_CALCULATIONS
//---------- 64-Bit Number Support //---------- 64-Bit Number Support
#define FF_64_NUM_SUPPORT // This helps to give information about the FreeSpace and VolumeSize of a partition or volume. #define FF_64_NUM_SUPPORT // This helps to give information about the FreeSpace and VolumeSize of a partition or volume.
// If you cannot support 64-bit integers, then FullFAT still works, its just that the functions: // If you cannot support 64-bit integers, then FullFAT still works, its just that the functions:
// FF_GetFreeSize() and FF_GetVolumeSize() don't make sense when reporting sizes > 4GB. // FF_GetFreeSize() and FF_GetVolumeSize() don't make sense when reporting sizes > 4GB.
//---------- Driver Sleep Time // How long FullFAT should sleep the thread for in ms, if FF_ERR_DRIVER_BUSY is recieved.
#define FF_DRIVER_BUSY_SLEEP 20
//---------- Debugging Features //---------- Driver Sleep Time
#define FF_DEBUG // Enable the Error Code string functions. const FF_T_INT8 *FF_GetErrMessage( FF_T_SINT32 iErrorCode); #define FF_DRIVER_BUSY_SLEEP 20 // How long FullFAT should sleep the thread for in ms, if FF_ERR_DRIVER_BUSY is recieved.
// Uncommenting this just stops FullFAT error strings being compiled.
//---------- Actively Determine if partition is FAT
#define FF_FAT_CHECK // This is experimental, so if FullFAT won't mount your volume, comment this out //---------- DEBUGGING FEATURES (HELPFUL ERROR MESSAGES)
// Also report the problem to james@worm.me.uk #define FF_DEBUG // Enable the Error Code string functions. const FF_T_INT8 *FF_GetErrMessage( FF_T_SINT32 iErrorCode);
// Uncommenting this just stops FullFAT error strings being compiled.
// Further calls to FF_GetErrMessage() are safe, and simply returns a pointer to a NULL string. ("").
// This should be disabled to reduce code-size dramatically.
//---------- AUTOMATIC SETTINGS DO NOT EDIT -- These configure your options from above, and check sanity! //---------- AUTOMATIC SETTINGS DO NOT EDIT -- These configure your options from above, and check sanity!
#ifdef FF_LFN_SUPPORT #ifdef FF_LFN_SUPPORT
#define FF_MAX_FILENAME (129) #define FF_MAX_FILENAME (260)
#else #else
#define FF_MAX_FILENAME 13 #define FF_MAX_FILENAME (13)
#endif #endif
#ifdef FF_USE_NATIVE_STDIO #ifdef FF_USE_NATIVE_STDIO
#ifdef MAX_PATH #ifdef MAX_PATH
#define FF_MAX_PATH MAX_PATH #define FF_MAX_PATH MAX_PATH
#elif PATH_MAX
#define FF_MAX_PATH PATH_MAX
#else #else
#define FF_MAX_PATH 2600 #define FF_MAX_PATH 2600
#endif #endif
@ -155,6 +185,16 @@
#endif #endif
#endif #endif
#ifdef FF_UNICODE_SUPPORT
#ifdef FF_UNICODE_UTF8_SUPPORT
#error FullFAT Invalid ff_config.h file: Must choose a single UNICODE support option. FF_UNICODE_SUPPORT for UTF-16, FF_UNICODE_UTF8_SUPPORT for UTF-8.
#endif
#endif
#ifndef FF_FAT_CHECK // FF_FAT_CHECK is now forced.
#define FF_FAT_CHECK
#endif
#ifndef FF_LITTLE_ENDIAN #ifndef FF_LITTLE_ENDIAN
#ifndef FF_BIG_ENDIAN #ifndef FF_BIG_ENDIAN
#error FullFAT Invalid ff_config.h file: An ENDIANESS must be defined for your platform. See ff_config.h file. #error FullFAT Invalid ff_config.h file: An ENDIANESS must be defined for your platform. See ff_config.h file.
@ -167,16 +207,18 @@
#endif #endif
#endif #endif
#ifdef FF_HASH_TABLE_SUPPORT #ifdef FF_HASH_CACHE
#if FF_HASH_FUNCTION == CRC16 #if FF_HASH_FUNCTION == CRC16
#define FF_HASH_TABLE_SIZE 8192 #define FF_HASH_TABLE_SIZE 8192
#elif FF_HASH_FUNCTION == CRC8 #elif FF_HASH_FUNCTION == CRC8
#define FF_HASH_TABLE_SIZE 32 #define FF_HASH_TABLE_SIZE 32
#else #else
#error Invalid Hashing function selected. CRC16 or CRC8! #error FullFAT Invalid ff_config.h file: Invalid Hashing function selected. CRC16 or CRC8!
#endif #endif
#endif #endif
#endif #endif
//---------- END-OF-CONFIGURATION

View file

@ -44,6 +44,7 @@
FF_T_UINT8 FF_GetCRC8 (FF_T_UINT8 *pbyData, FF_T_UINT32 stLength); FF_T_UINT8 FF_GetCRC8 (FF_T_UINT8 *pbyData, FF_T_UINT32 stLength);
FF_T_UINT16 FF_GetCRC16 (FF_T_UINT8 *pbyData, FF_T_UINT32 stLength); FF_T_UINT16 FF_GetCRC16 (FF_T_UINT8 *pbyData, FF_T_UINT32 stLength);
FF_T_UINT32 FF_GetCRC32 (FF_T_UINT8 *pbyData, FF_T_UINT32 stLength);
#endif #endif

View file

@ -52,54 +52,118 @@
#include <string.h> #include <string.h>
typedef struct { typedef struct {
FF_T_INT8 FileName[FF_MAX_FILENAME]; FF_T_UINT32 ulChainLength;
FF_T_UINT8 Attrib; FF_T_UINT32 ulDirCluster;
FF_T_UINT32 ulCurrentClusterLCN;
FF_T_UINT32 ulCurrentClusterNum;
FF_T_UINT32 ulCurrentEntry;
FF_BUFFER *pBuffer;
} FF_FETCH_CONTEXT;
typedef struct {
FF_T_UINT32 Filesize; FF_T_UINT32 Filesize;
FF_T_UINT32 ObjectCluster; FF_T_UINT32 ObjectCluster;
// Book Keeping
FF_T_UINT32 CurrentCluster;
FF_T_UINT32 AddrCurrentCluster;
FF_T_UINT32 DirCluster;
FF_T_UINT16 CurrentItem;
// End Book Keeping
#ifdef FF_TIME_SUPPORT #ifdef FF_TIME_SUPPORT
FF_SYSTEMTIME CreateTime; ///< Date and Time Created. FF_SYSTEMTIME CreateTime; ///< Date and Time Created.
FF_SYSTEMTIME ModifiedTime; ///< Date and Time Modified. FF_SYSTEMTIME ModifiedTime; ///< Date and Time Modified.
FF_SYSTEMTIME AccessedTime; ///< Date of Last Access. FF_SYSTEMTIME AccessedTime; ///< Date of Last Access.
#endif #endif
//---- Book Keeping for FF_Find Functions #ifdef FF_FINDAPI_ALLOW_WILDCARDS
FF_T_UINT16 CurrentItem; #ifdef FF_UNICODE_SUPPORT
FF_T_UINT32 DirCluster; FF_T_WCHAR szWildCard[FF_MAX_FILENAME];
FF_T_UINT32 CurrentCluster; #else
FF_T_UINT32 AddrCurrentCluster; FF_T_INT8 szWildCard[FF_MAX_FILENAME];
//FF_T_UINT8 NumLFNs; #endif
#endif
#ifdef FF_UNICODE_SUPPORT
FF_T_WCHAR FileName[FF_MAX_FILENAME];
#else
FF_T_INT8 FileName[FF_MAX_FILENAME];
#endif
#if defined(FF_LFN_SUPPORT) && defined(FF_INCLUDE_SHORT_NAME)
FF_T_INT8 ShortName[13];
#endif
FF_T_UINT8 Attrib;
FF_FETCH_CONTEXT FetchContext;
} FF_DIRENT; } FF_DIRENT;
FF_ERROR FF_GetEntry (FF_IOMAN *pIoman, FF_T_UINT16 nEntry, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent);
FF_T_SINT8 FF_PutEntry (FF_IOMAN *pIoman, FF_T_UINT16 Entry, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent);
FF_T_SINT8 FF_FindEntry (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *Name, FF_DIRENT *pDirent, FF_T_BOOL LFNs);
FF_ERROR FF_FindFirst (FF_IOMAN *pIoman, FF_DIRENT *pDirent, const FF_T_INT8 *path);
FF_ERROR FF_FindNext (FF_IOMAN *pIoman, FF_DIRENT *pDirent);
void FF_PopulateShortDirent(FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_T_UINT8 *EntryBuffer);
FF_T_SINT8 FF_PopulateLongDirent(FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_T_UINT32 DirCluster, FF_T_UINT16 nEntry);
FF_T_SINT8 FF_FetchEntry (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT16 nEntry, FF_T_UINT8 *buffer);
FF_T_SINT8 FF_PushEntry (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT16 nEntry, FF_T_UINT8 *buffer);
FF_T_BOOL FF_isEndOfDir (FF_T_UINT8 *EntryBuffer);
FF_T_SINT8 FF_FindNextInDir(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent);
FF_T_UINT32 FF_FindEntryInDir(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *name, FF_T_UINT8 pa_Attrib, FF_DIRENT *pDirent);
FF_T_SINT8 FF_CreateShortName(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *ShortName, FF_T_INT8 *LongName);
void FF_lockDIR (FF_IOMAN *pIoman);
void FF_unlockDIR (FF_IOMAN *pIoman);
FF_T_UINT32 FF_CreateFile(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *FileName, FF_DIRENT *pDirent);
FF_ERROR FF_MkDir(FF_IOMAN *pIoman, const FF_T_INT8 *Path);
FF_T_SINT8 FF_CreateDirent(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent);
FF_T_SINT8 FF_ExtendDirectory(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster);
FF_T_UINT32 FF_FindDir(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT16 pathLen);
FF_T_BOOL FF_CheckDirentHash(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT32 nHash); // PUBLIC API
FF_T_BOOL FF_DirHashed(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster); #ifdef FF_UNICODE_SUPPORT
FF_ERROR FF_AddDirentHash(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT32 nHash); FF_ERROR FF_FindFirst (FF_IOMAN *pIoman, FF_DIRENT *pDirent, const FF_T_WCHAR *path);
void FF_SetDirHashed(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster); FF_ERROR FF_MkDir (FF_IOMAN *pIoman, const FF_T_WCHAR *Path);
#else
FF_ERROR FF_FindFirst (FF_IOMAN *pIoman, FF_DIRENT *pDirent, const FF_T_INT8 *path);
FF_ERROR FF_MkDir (FF_IOMAN *pIoman, const FF_T_INT8 *Path);
#endif
void FF_RmLFNs(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT16 DirEntry); FF_ERROR FF_FindNext (FF_IOMAN *pIoman, FF_DIRENT *pDirent);
// INTERNAL API
FF_ERROR FF_GetEntry (FF_IOMAN *pIoman, FF_T_UINT16 nEntry, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent);
FF_ERROR FF_PutEntry (FF_IOMAN *pIoman, FF_T_UINT16 Entry, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent);
FF_T_SINT8 FF_FindEntry (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *Name, FF_DIRENT *pDirent, FF_T_BOOL LFNs);
void FF_PopulateShortDirent (FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_T_UINT8 *EntryBuffer);
FF_ERROR FF_PopulateLongDirent (FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_T_UINT16 nEntry, FF_FETCH_CONTEXT *pFetchContext);
FF_ERROR FF_InitEntryFetch (FF_IOMAN *pIoman, FF_T_UINT32 ulDirCluster, FF_FETCH_CONTEXT *pContext);
FF_ERROR FF_FetchEntryWithContext (FF_IOMAN *pIoman, FF_T_UINT32 ulEntry, FF_FETCH_CONTEXT *pContext, FF_T_UINT8 *pEntryBuffer);
FF_ERROR FF_PushEntryWithContext (FF_IOMAN *pIoman, FF_T_UINT32 ulEntry, FF_FETCH_CONTEXT *pContext, FF_T_UINT8 *pEntryBuffer);
void FF_CleanupEntryFetch (FF_IOMAN *pIoman, FF_FETCH_CONTEXT *pContext);
FF_T_SINT8 FF_PushEntry (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT16 nEntry, FF_T_UINT8 *buffer, void *pParam);
FF_T_BOOL FF_isEndOfDir (FF_T_UINT8 *EntryBuffer);
FF_ERROR FF_FindNextInDir (FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_FETCH_CONTEXT *pFetchContext);
#ifdef FF_UNICODE_SUPPORT
FF_T_UINT32 FF_FindEntryInDir (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, const FF_T_WCHAR *name, FF_T_UINT8 pa_Attrib, FF_DIRENT *pDirent, FF_ERROR *pError);
FF_T_SINT8 FF_CreateShortName (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_WCHAR *ShortName, FF_T_WCHAR *LongName);
#else
FF_T_UINT32 FF_FindEntryInDir (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, const FF_T_INT8 *name, FF_T_UINT8 pa_Attrib, FF_DIRENT *pDirent, FF_ERROR *pError);
FF_T_SINT8 FF_CreateShortName (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *ShortName, FF_T_INT8 *LongName);
#endif
void FF_lockDIR (FF_IOMAN *pIoman);
void FF_unlockDIR (FF_IOMAN *pIoman);
#ifdef FF_UNICODE_SUPPORT
FF_T_UINT32 FF_CreateFile(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_WCHAR *FileName, FF_DIRENT *pDirent, FF_ERROR *pError);
#else
FF_T_UINT32 FF_CreateFile(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *FileName, FF_DIRENT *pDirent, FF_ERROR *pError);
#endif
FF_ERROR FF_CreateDirent (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent);
FF_ERROR FF_ExtendDirectory (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster);
#ifdef FF_UNICODE_SUPPORT
FF_T_UINT32 FF_FindDir (FF_IOMAN *pIoman, const FF_T_WCHAR *path, FF_T_UINT16 pathLen, FF_ERROR *pError);
#else
FF_T_UINT32 FF_FindDir (FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT16 pathLen, FF_ERROR *pError);
#endif
#ifdef FF_HASH_CACHE
FF_T_BOOL FF_CheckDirentHash (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT32 nHash);
FF_T_BOOL FF_DirHashed (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster);
FF_ERROR FF_AddDirentHash (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT32 nHash);
FF_ERROR FF_HashDir (FF_IOMAN *pIoman, FF_T_UINT32 ulDirCluster);
#endif
FF_ERROR FF_RmLFNs(FF_IOMAN *pIoman, FF_T_UINT16 usDirEntry, FF_FETCH_CONTEXT *pContext);
#endif #endif

View file

@ -40,53 +40,111 @@
#include "ff_config.h" #include "ff_config.h"
#include "ff_types.h" #include "ff_types.h"
/**
Error codes are 32-bit numbers, and consist of three items:
8Bits 8bits 16bits
........ ........ ........ ........
[ModuleID][FunctionID][-- ERROR CODE --]
**/
#define FF_GETERROR(x) (x & 0x0000FFFF)
#define FF_MODULE_SHIFT 24
#define FF_FUNCTION_SHIFT 16
//----- FullFAT Module Identifiers
#define FF_MODULE_IOMAN (1 << FF_MODULE_SHIFT)
#define FF_MODULE_DIR (2 << FF_MODULE_SHIFT)
#define FF_MODULE_FILE (3 << FF_MODULE_SHIFT)
#define FF_MODULE_FAT (4 << FF_MODULE_SHIFT)
#define FF_MODULE_CRC (5 << FF_MODULE_SHIFT)
#define FF_MODULE_FORMAT (6 << FF_MODULE_SHIFT)
#define FF_MODULE_HASH (7 << FF_MODULE_SHIFT)
#define FF_MODULE_MEMORY (8 << FF_MODULE_SHIFT)
#define FF_MODULE_STRING (9 << FF_MODULE_SHIFT)
#define FF_MODULE_UNICODE (10 << FF_MODULE_SHIFT)
#define FF_MODULE_SAFETY (11 << FF_MODULE_SHIFT)
#define FF_MODULE_TIME (12 << FF_MODULE_SHIFT)
#define FF_MODULE_DRIVER (13 << FF_MODULE_SHIFT) // We can mark underlying platform error codes with this.
//----- FullFAT Function Identifiers (In Modular Order)
//----- FF_IOMAN - The FullFAT I/O Manager.
#define FF_CREATEIOMAN (1 << FF_FUNCTION_SHIFT) | FF_MODULE_IOMAN
#define FF_DESTROYIOMAN (2 << FF_FUNCTION_SHIFT) | FF_MODULE_IOMAN
#define FF_REGISTERBLKDEVICE (3 << FF_FUNCTION_SHIFT) | FF_MODULE_IOMAN
#define FF_UNREGISTERBLKDEVICE (4 << FF_FUNCTION_SHIFT) | FF_MODULE_IOMAN
#define FF_MOUNTPARTITION (5 << FF_FUNCTION_SHIFT) | FF_MODULE_IOMAN
#define FF_UNMOUNTPARTITION (6 << FF_FUNCTION_SHIFT) | FF_MODULE_IOMAN
#define FF_FLUSHCACHE (7 << FF_FUNCTION_SHIFT) | FF_MODULE_IOMAN
#define FF_GETPARTITIONBLOCKSIZE (8 << FF_FUNCTION_SHIFT) | FF_MODULE_IOMAN
#define FF_BLOCKREAD (9 << FF_FUNCTION_SHIFT) | FF_MODULE_IOMAN
#define FF_BLOCKWRITE (10 << FF_FUNCTION_SHIFT) | FF_MODULE_IOMAN
//----- FF_DIR - The FullFAT directory handling routines.
// -- COMPLETE THESE ERROR CODES TOMORROW :P
/* FullFAT defines different Error-Code spaces for each module. This ensures /* FullFAT defines different Error-Code spaces for each module. This ensures
that all error codes remain unique, and their meaning can be quickly identified. that all error codes remain unique, and their meaning can be quickly identified.
*/ */
// Global Error Codes // Global Error Codes
#define FF_ERR_NONE 0 ///< No Error #define FF_ERR_NONE 0 ///< No Error
#define FF_ERR_NULL_POINTER -2 ///< pIoman was NULL. //#define FF_ERR_GENERIC 1 ///< BAD NEVER USE THIS!
#define FF_ERR_NOT_ENOUGH_MEMORY -3 ///< malloc() failed! - Could not allocate handle memory. #define FF_ERR_NULL_POINTER 2 ///< pIoman was NULL.
#define FF_ERR_DEVICE_DRIVER_FAILED -4 ///< The Block Device driver reported a FATAL error, cannot continue. #define FF_ERR_NOT_ENOUGH_MEMORY 3 ///< malloc() failed! - Could not allocate handle memory.
#define FF_ERR_DEVICE_DRIVER_FAILED 4 ///< The Block Device driver reported a FATAL error, cannot continue.
// IOMAN Error Codes // IOMAN Error Codes
#define FF_ERR_IOMAN_BAD_BLKSIZE -11 ///< The provided blocksize was not a multiple of 512. #define FF_ERR_IOMAN_BAD_BLKSIZE 11 ///< The provided blocksize was not a multiple of 512.
#define FF_ERR_IOMAN_BAD_MEMSIZE -12 ///< The memory size was not a multiple of the blocksize. #define FF_ERR_IOMAN_BAD_MEMSIZE 12 ///< The memory size was not a multiple of the blocksize.
#define FF_ERR_IOMAN_DEV_ALREADY_REGD -13 ///< Device was already registered. Use FF_UnRegister() to re-use this IOMAN with another device. #define FF_ERR_IOMAN_DEV_ALREADY_REGD 13 ///< Device was already registered. Use FF_UnRegister() to re-use this IOMAN with another device.
#define FF_ERR_IOMAN_NO_MOUNTABLE_PARTITION -14 ///< A mountable partition could not be found on the device. #define FF_ERR_IOMAN_NO_MOUNTABLE_PARTITION 14 ///< A mountable partition could not be found on the device.
#define FF_ERR_IOMAN_INVALID_FORMAT -15 ///< The #define FF_ERR_IOMAN_INVALID_FORMAT 15 ///< The
#define FF_ERR_IOMAN_INVALID_PARTITION_NUM -16 ///< The partition number provided was out of range. #define FF_ERR_IOMAN_INVALID_PARTITION_NUM 16 ///< The partition number provided was out of range.
#define FF_ERR_IOMAN_NOT_FAT_FORMATTED -17 ///< The partition did not look like a FAT partition. #define FF_ERR_IOMAN_NOT_FAT_FORMATTED 17 ///< The partition did not look like a FAT partition.
#define FF_ERR_IOMAN_DEV_INVALID_BLKSIZE -18 ///< IOMAN object BlkSize is not compatible with the blocksize of this device driver. #define FF_ERR_IOMAN_DEV_INVALID_BLKSIZE 18 ///< IOMAN object BlkSize is not compatible with the blocksize of this device driver.
#define FF_ERR_IOMAN_PARTITION_MOUNTED -19 ///< Device is in use by an actively mounted partition. Unmount the partition first. #define FF_ERR_IOMAN_PARTITION_MOUNTED 19 ///< Device is in use by an actively mounted partition. Unmount the partition first.
#define FF_ERR_IOMAN_ACTIVE_HANDLES -20 ///< The partition cannot be unmounted until all active file handles are closed. (There may also be active handles on the cache). #define FF_ERR_IOMAN_ACTIVE_HANDLES 20 ///< The partition cannot be unmounted until all active file handles are closed. (There may also be active handles on the cache).
#define FF_ERR_IOMAN_GPT_HEADER_CORRUPT 21 ///< The GPT partition table appears to be corrupt, refusing to mount.
#define FF_ERR_IOMAN_NOT_ENOUGH_FREE_SPACE 22
#define FF_ERR_IOMAN_OUT_OF_BOUNDS_READ 23
#define FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE 24
// File Error Codes -30 + // File Error Codes 30 +
#define FF_ERR_FILE_ALREADY_OPEN -30 ///< File is in use. #define FF_ERR_FILE_ALREADY_OPEN 30 ///< File is in use.
#define FF_ERR_FILE_NOT_FOUND -31 ///< File was not found. #define FF_ERR_FILE_NOT_FOUND 31 ///< File was not found.
#define FF_ERR_FILE_OBJECT_IS_A_DIR -32 ///< Tried to FF_Open() a Directory. #define FF_ERR_FILE_OBJECT_IS_A_DIR 32 ///< Tried to FF_Open() a Directory.
#define FF_ERR_FILE_IS_READ_ONLY -33 ///< Tried to FF_Open() a file marked read only. #define FF_ERR_FILE_IS_READ_ONLY 33 ///< Tried to FF_Open() a file marked read only.
#define FF_ERR_FILE_INVALID_PATH -34 ///< The path of the file was not found. #define FF_ERR_FILE_INVALID_PATH 34 ///< The path of the file was not found.
#define FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE -35 #define FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE 35
#define FF_ERR_FILE_NOT_OPENED_IN_READ_MODE -36 #define FF_ERR_FILE_NOT_OPENED_IN_READ_MODE 36
#define FF_ERR_FILE_EXTEND_FAILED -37 ///< Could not extend the file. #define FF_ERR_FILE_EXTEND_FAILED 37 ///< Could not extend the file.
#define FF_ERR_FILE_DESTINATION_EXISTS -38 #define FF_ERR_FILE_DESTINATION_EXISTS 38
#define FF_ERR_FILE_SOURCE_NOT_FOUND -39 #define FF_ERR_FILE_SOURCE_NOT_FOUND 39
#define FF_ERR_FILE_DIR_NOT_FOUND -40 #define FF_ERR_FILE_DIR_NOT_FOUND 40
#define FF_ERR_FILE_COULD_NOT_CREATE_DIRENT -41 #define FF_ERR_FILE_COULD_NOT_CREATE_DIRENT 41
// Directory Error Codes -50 + // Directory Error Codes 50 +
#define FF_ERR_DIR_OBJECT_EXISTS -50 ///< A file or folder of the same name already exists in the current directory. #define FF_ERR_DIR_OBJECT_EXISTS 50 ///< A file or folder of the same name already exists in the current directory.
#define FF_ERR_DIR_DIRECTORY_FULL -51 ///< No more items could be added to the directory. #define FF_ERR_DIR_DIRECTORY_FULL 51 ///< No more items could be added to the directory.
#define FF_ERR_DIR_END_OF_DIR -52 /// #define FF_ERR_DIR_END_OF_DIR 52 ///
#define FF_ERR_DIR_NOT_EMPTY -53 ///< Cannot delete a directory that contains files or folders. #define FF_ERR_DIR_NOT_EMPTY 53 ///< Cannot delete a directory that contains files or folders.
#define FF_ERR_DIR_INVALID_PATH -54 ///< Could not find the directory specified by the path. #define FF_ERR_DIR_INVALID_PATH 54 ///< Could not find the directory specified by the path.
#define FF_ERR_DIR_CANT_EXTEND_ROOT_DIR -55 ///< Can't extend the root dir. #define FF_ERR_DIR_CANT_EXTEND_ROOT_DIR 55 ///< Can't extend the root dir.
#define FF_ERR_DIR_EXTEND_FAILED 56 ///< Not enough space to extend the directory.
#define FF_ERR_DIR_NAME_TOO_LONG 57 ///< Name exceeds the number of allowed charachters for a filename.
// Fat Error Codes -70 + // Fat Error Codes 70 +
#define FF_ERR_FAT_NO_FREE_CLUSTERS -70 ///< No more free space is available on the disk. #define FF_ERR_FAT_NO_FREE_CLUSTERS 70 ///< No more free space is available on the disk.
// UNICODE Error Codes 100 +
#define FF_ERR_UNICODE_INVALID_CODE 100 ///< An invalid Unicode charachter was provided!
#define FF_ERR_UNICODE_DEST_TOO_SMALL 101 ///< Not enough space in the UTF-16 buffer to encode the entire sequence as UTF-16.
#define FF_ERR_UNICODE_INVALID_SEQUENCE 102 ///< An invalid UTF-16 sequence was encountered.
#define FF_ERR_UNICODE_CONVERSION_EXCEEDED 103 ///< Filename exceeds MAX long-filename length when converted to UTF-16.
#ifdef FF_DEBUG #ifdef FF_DEBUG
const FF_T_INT8 *FF_GetErrMessage(FF_ERROR iErrorCode); const FF_T_INT8 *FF_GetErrMessage(FF_ERROR iErrorCode);

View file

@ -52,24 +52,23 @@
FF_T_UINT32 FF_getRealLBA (FF_IOMAN *pIoman, FF_T_UINT32 LBA); FF_T_UINT32 FF_getRealLBA (FF_IOMAN *pIoman, FF_T_UINT32 LBA);
FF_T_UINT32 FF_Cluster2LBA (FF_IOMAN *pIoman, FF_T_UINT32 Cluster); FF_T_UINT32 FF_Cluster2LBA (FF_IOMAN *pIoman, FF_T_UINT32 Cluster);
FF_T_UINT32 FF_LBA2Cluster (FF_IOMAN *pIoman, FF_T_UINT32 Address); FF_T_UINT32 FF_LBA2Cluster (FF_IOMAN *pIoman, FF_T_UINT32 Address);
FF_T_SINT32 FF_getFatEntry (FF_IOMAN *pIoman, FF_T_UINT32 nCluster); FF_T_UINT32 FF_getFatEntry (FF_IOMAN *pIoman, FF_T_UINT32 nCluster, FF_ERROR *pError);
FF_ERROR FF_putFatEntry (FF_IOMAN *pIoman, FF_T_UINT32 nCluster, FF_T_UINT32 Value);
FF_T_BOOL FF_isEndOfChain (FF_IOMAN *pIoman, FF_T_UINT32 fatEntry); FF_T_BOOL FF_isEndOfChain (FF_IOMAN *pIoman, FF_T_UINT32 fatEntry);
FF_T_SINT8 FF_putFatEntry (FF_IOMAN *pIoman, FF_T_UINT32 nCluster, FF_T_UINT32 Value); FF_T_UINT32 FF_FindFreeCluster (FF_IOMAN *pIoman, FF_ERROR *pError);
FF_T_UINT32 FF_FindFreeCluster (FF_IOMAN *pIoman);
FF_T_UINT32 FF_ExtendClusterChain (FF_IOMAN *pIoman, FF_T_UINT32 StartCluster, FF_T_UINT32 Count); FF_T_UINT32 FF_ExtendClusterChain (FF_IOMAN *pIoman, FF_T_UINT32 StartCluster, FF_T_UINT32 Count);
FF_T_SINT8 FF_UnlinkClusterChain (FF_IOMAN *pIoman, FF_T_UINT32 StartCluster, FF_T_UINT16 Count); FF_ERROR FF_UnlinkClusterChain (FF_IOMAN *pIoman, FF_T_UINT32 StartCluster, FF_T_UINT16 Count);
FF_T_UINT32 FF_TraverseFAT (FF_IOMAN *pIoman, FF_T_UINT32 Start, FF_T_UINT32 Count); FF_T_UINT32 FF_TraverseFAT (FF_IOMAN *pIoman, FF_T_UINT32 Start, FF_T_UINT32 Count, FF_ERROR *pError);
FF_T_UINT32 FF_CreateClusterChain (FF_IOMAN *pIoman); FF_T_UINT32 FF_CreateClusterChain (FF_IOMAN *pIoman, FF_ERROR *pError);
FF_T_UINT32 FF_GetChainLength (FF_IOMAN *pIoman, FF_T_UINT32 pa_nStartCluster, FF_T_UINT32 *piEndOfChain); FF_T_UINT32 FF_GetChainLength (FF_IOMAN *pIoman, FF_T_UINT32 pa_nStartCluster, FF_T_UINT32 *piEndOfChain, FF_ERROR *pError);
FF_T_UINT32 FF_FindEndOfChain (FF_IOMAN *pIoman, FF_T_UINT32 Start); FF_T_UINT32 FF_FindEndOfChain (FF_IOMAN *pIoman, FF_T_UINT32 Start, FF_ERROR *pError);
FF_T_SINT8 FF_ClearCluster (FF_IOMAN *pIoman, FF_T_UINT32 nCluster); FF_ERROR FF_ClearCluster (FF_IOMAN *pIoman, FF_T_UINT32 nCluster);
#ifdef FF_64_NUM_SUPPORT #ifdef FF_64_NUM_SUPPORT
FF_T_UINT64 FF_GetFreeSize (FF_IOMAN *pIoman); FF_T_UINT64 FF_GetFreeSize (FF_IOMAN *pIoman, FF_ERROR *pError);
#else #else
FF_T_UINT32 FF_GetFreeSize (FF_IOMAN *pIoman); FF_T_UINT32 FF_GetFreeSize (FF_IOMAN *pIoman, FF_ERROR *pError);
#endif #endif
FF_T_UINT32 FF_FindFreeCluster (FF_IOMAN *pIoman); FF_T_UINT32 FF_CountFreeClusters (FF_IOMAN *pIoman, FF_ERROR *pError); // WARNING: If this protoype changes, it must be updated in ff_ioman.c also!
FF_T_UINT32 FF_CountFreeClusters (FF_IOMAN *pIoman);
void FF_lockFAT (FF_IOMAN *pIoman); void FF_lockFAT (FF_IOMAN *pIoman);
void FF_unlockFAT (FF_IOMAN *pIoman); void FF_unlockFAT (FF_IOMAN *pIoman);

View file

@ -86,5 +86,20 @@
#define FF_FAT_ATTR_ARCHIVE 0x20 #define FF_FAT_ATTR_ARCHIVE 0x20
#define FF_FAT_ATTR_LFN 0x0F #define FF_FAT_ATTR_LFN 0x0F
/**
* -- Hein_Tibosch additions for mixed case in shortnames --
*
* Specifically, bit 4 means lowercase extension and bit 3 lowercase basename,
* which allows for combinations such as "example.TXT" or "HELLO.txt" but not "Mixed.txt"
*/
#define FF_FAT_CASE_OFFS 0x0C ///< After NT/XP : 2 case bits
#define FF_FAT_CASE_ATTR_BASE 0x08
#define FF_FAT_CASE_ATTR_EXT 0x10
#if defined(FF_LFN_SUPPORT) && defined(FF_INCLUDE_SHORT_NAME)
#define FF_FAT_ATTR_IS_LFN 0x40 ///< artificial attribute, for debugging only
#endif
#endif #endif

View file

@ -75,19 +75,29 @@ typedef struct _FF_FILE {
//---------- PROTOTYPES //---------- PROTOTYPES
// PUBLIC (Interfaces): // PUBLIC (Interfaces):
FF_FILE *FF_Open (FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT8 Mode, FF_ERROR *pError); #ifdef FF_UNICODE_SUPPORT
FF_FILE *FF_Open(FF_IOMAN *pIoman, const FF_T_WCHAR *path, FF_T_UINT8 Mode, FF_ERROR *pError);
FF_T_BOOL FF_isDirEmpty (FF_IOMAN *pIoman, const FF_T_WCHAR *Path);
FF_ERROR FF_RmFile (FF_IOMAN *pIoman, const FF_T_WCHAR *path);
FF_ERROR FF_RmDir (FF_IOMAN *pIoman, const FF_T_WCHAR *path);
FF_ERROR FF_Move (FF_IOMAN *pIoman, const FF_T_WCHAR *szSourceFile, const FF_T_WCHAR *szDestinationFile);
#else
FF_FILE *FF_Open(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT8 Mode, FF_ERROR *pError);
FF_T_BOOL FF_isDirEmpty (FF_IOMAN *pIoman, const FF_T_INT8 *Path);
FF_ERROR FF_RmFile (FF_IOMAN *pIoman, const FF_T_INT8 *path);
FF_ERROR FF_RmDir (FF_IOMAN *pIoman, const FF_T_INT8 *path);
FF_ERROR FF_Move (FF_IOMAN *pIoman, const FF_T_INT8 *szSourceFile, const FF_T_INT8 *szDestinationFile);
#endif
FF_ERROR FF_Close (FF_FILE *pFile); FF_ERROR FF_Close (FF_FILE *pFile);
FF_T_SINT32 FF_GetC (FF_FILE *pFile); FF_T_SINT32 FF_GetC (FF_FILE *pFile);
FF_T_SINT32 FF_GetLine (FF_FILE *pFile, FF_T_INT8 *szLine, FF_T_UINT32 ulLimit);
FF_T_SINT32 FF_Read (FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, FF_T_UINT8 *buffer); FF_T_SINT32 FF_Read (FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, FF_T_UINT8 *buffer);
FF_T_SINT32 FF_Write (FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, FF_T_UINT8 *buffer); FF_T_SINT32 FF_Write (FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, FF_T_UINT8 *buffer);
FF_T_BOOL FF_isEOF (FF_FILE *pFile); FF_T_BOOL FF_isEOF (FF_FILE *pFile);
FF_ERROR FF_Seek (FF_FILE *pFile, FF_T_SINT32 Offset, FF_T_INT8 Origin); FF_ERROR FF_Seek (FF_FILE *pFile, FF_T_SINT32 Offset, FF_T_INT8 Origin);
FF_T_SINT32 FF_PutC (FF_FILE *pFile, FF_T_UINT8 Value); FF_T_SINT32 FF_PutC (FF_FILE *pFile, FF_T_UINT8 Value);
FF_T_UINT32 FF_Tell (FF_FILE *pFile); FF_T_UINT32 FF_Tell (FF_FILE *pFile);
FF_ERROR FF_RmFile (FF_IOMAN *pIoman, const FF_T_INT8 *path);
FF_ERROR FF_RmDir (FF_IOMAN *pIoman, const FF_T_INT8 *path);
FF_T_BOOL FF_isDirEmpty (FF_IOMAN *pIoman, const FF_T_INT8 *Path);
FF_ERROR FF_Move (FF_IOMAN *pIoman, const FF_T_INT8 *szSourceFile, const FF_T_INT8 *szDestinationFile);
FF_T_UINT8 FF_GetModeBits (FF_T_INT8 *Mode); FF_T_UINT8 FF_GetModeBits (FF_T_INT8 *Mode);
// Private : // Private :

View file

@ -0,0 +1,47 @@
/*****************************************************************************
* FullFAT - High Performance, Thread-Safe Embedded FAT File-System *
* Copyright (C) 2009 James Walmsley (james@worm.me.uk) *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
* IMPORTANT NOTICE: *
* ================= *
* Alternative Licensing is available directly from the Copyright holder, *
* (James Walmsley). For more information consult LICENSING.TXT to obtain *
* a Commercial license. *
* *
* See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT. *
* *
* Removing the above notice is illegal and will invalidate this license. *
*****************************************************************************
* See http://worm.me.uk/fullfat for more information. *
* Or http://fullfat.googlecode.com/ for latest releases and the wiki. *
*****************************************************************************/
/**
* @file ff_format.c
* @author James Walmsley
* @ingroup FORMAT
*
**/
#ifndef _FF_FORMAT_H_
#define _FF_FORMAT_H_
#endif

View file

@ -87,8 +87,8 @@ typedef FF_T_SINT32 (*FF_READ_BLOCKS) (FF_T_UINT8 *pBuffer, FF_T_UINT32 SectorAd
* @brief Describes the block device driver interface to FullFAT. * @brief Describes the block device driver interface to FullFAT.
**/ **/
typedef struct { typedef struct {
FF_WRITE_BLOCKS fnWriteBlocks; ///< Function Pointer, to write a block(s) from a block device. FF_WRITE_BLOCKS fnpWriteBlocks; ///< Function Pointer, to write a block(s) from a block device.
FF_READ_BLOCKS fnReadBlocks; ///< Function Pointer, to read a block(s) from a block device. FF_READ_BLOCKS fnpReadBlocks; ///< Function Pointer, to read a block(s) from a block device.
FF_T_UINT16 devBlkSize; ///< Block size that the driver deals with. FF_T_UINT16 devBlkSize; ///< Block size that the driver deals with.
void *pParam; ///< Pointer to some parameters e.g. for a Low-Level Driver Handle void *pParam; ///< Pointer to some parameters e.g. for a Low-Level Driver Handle
} FF_BLK_DEVICE; } FF_BLK_DEVICE;
@ -110,14 +110,23 @@ typedef struct {
} FF_BUFFER; } FF_BUFFER;
typedef struct { typedef struct {
#ifdef FF_UNICODE_SUPPORT
FF_T_WCHAR Path[FF_MAX_PATH];
#else
FF_T_INT8 Path[FF_MAX_PATH]; FF_T_INT8 Path[FF_MAX_PATH];
FF_T_UINT32 DirCluster;
#ifdef FF_HASH_TABLE_SUPPORT
FF_HASH_TABLE pHashTable;
FF_T_BOOL bHashed;
#endif #endif
FF_T_UINT32 DirCluster;
} FF_PATHCACHE; } FF_PATHCACHE;
#ifdef FF_HASH_CACHE
typedef struct {
FF_T_UINT32 ulDirCluster; ///< The Starting Cluster of the dir that the hash represents.
FF_HASH_TABLE pHashTable; ///< Pointer to the Hash Table object.
FF_T_UINT32 ulNumHandles; ///< Number of active Handles using this hash table.
FF_T_UINT32 ulMisses; ///< Number of times this Hash Table was missed, (i.e. how redundant it is).
} FF_HASHCACHE;
#endif
/** /**
* @private * @private
* @brief FullFAT identifies a partition with the following data. * @brief FullFAT identifies a partition with the following data.
@ -183,6 +192,9 @@ typedef struct {
FF_PARTITION *pPartition; ///< Pointer to a partition description. FF_PARTITION *pPartition; ///< Pointer to a partition description.
FF_BUFFER *pBuffers; ///< Pointer to the first buffer description. FF_BUFFER *pBuffers; ///< Pointer to the first buffer description.
void *pSemaphore; ///< Pointer to a Semaphore object. (For buffer description modifications only!). void *pSemaphore; ///< Pointer to a Semaphore object. (For buffer description modifications only!).
#ifdef FF_BLKDEV_USES_SEM
void *pBlkDevSemaphore; ///< Semaphore to guarantee Atomic access to the underlying block device, if required.
#endif
void *FirstFile; ///< Pointer to the first File object. void *FirstFile; ///< Pointer to the first File object.
FF_T_UINT8 *pCacheMem; ///< Pointer to a block of memory for the cache. FF_T_UINT8 *pCacheMem; ///< Pointer to a block of memory for the cache.
FF_T_UINT32 LastReplaced; ///< Marks which sector was last replaced in the cache. FF_T_UINT32 LastReplaced; ///< Marks which sector was last replaced in the cache.
@ -191,6 +203,9 @@ typedef struct {
FF_T_UINT8 PreventFlush; ///< Flushing to disk only allowed when 0 FF_T_UINT8 PreventFlush; ///< Flushing to disk only allowed when 0
FF_T_UINT8 MemAllocation; ///< Bit-Mask identifying allocated pointers. FF_T_UINT8 MemAllocation; ///< Bit-Mask identifying allocated pointers.
FF_T_UINT8 Locks; ///< Lock Flag for FAT & DIR Locking etc (This must be accessed via a semaphore). FF_T_UINT8 Locks; ///< Lock Flag for FAT & DIR Locking etc (This must be accessed via a semaphore).
#ifdef FF_HASH_CACHE
FF_HASHCACHE HashCache[FF_HASH_CACHE_DEPTH];
#endif
} FF_IOMAN; } FF_IOMAN;
// Bit-Masks for Memory Allocation testing. // Bit-Masks for Memory Allocation testing.
@ -220,6 +235,8 @@ FF_T_UINT32 FF_GetVolumeSize(FF_IOMAN *pIoman);
#endif #endif
// PUBLIC (To FullFAT Only): // PUBLIC (To FullFAT Only):
FF_T_SINT32 FF_BlockRead (FF_IOMAN *pIoman, FF_T_UINT32 ulSectorLBA, FF_T_UINT32 ulNumSectors, void *pBuffer);
FF_T_SINT32 FF_BlockWrite (FF_IOMAN *pIoman, FF_T_UINT32 ulSectorLBA, FF_T_UINT32 ulNumSectors, void *pBuffer);
FF_ERROR FF_IncreaseFreeClusters (FF_IOMAN *pIoman, FF_T_UINT32 Count); FF_ERROR FF_IncreaseFreeClusters (FF_IOMAN *pIoman, FF_T_UINT32 Count);
FF_ERROR FF_DecreaseFreeClusters (FF_IOMAN *pIoman, FF_T_UINT32 Count); FF_ERROR FF_DecreaseFreeClusters (FF_IOMAN *pIoman, FF_T_UINT32 Count);
FF_BUFFER *FF_GetBuffer (FF_IOMAN *pIoman, FF_T_UINT32 Sector, FF_T_UINT8 Mode); FF_BUFFER *FF_GetBuffer (FF_IOMAN *pIoman, FF_T_UINT32 Sector, FF_T_UINT8 Mode);

View file

@ -76,7 +76,7 @@ typedef struct {
#else #else
#error Little or Big Endian? #error Little or Big Endian? - Please set an endianess in ff_config.h
#endif #endif

View file

@ -44,11 +44,37 @@
#define _FF_STRING_H_ #define _FF_STRING_H_
#include "ff_types.h" #include "ff_types.h"
#include "ff_config.h"
#include <string.h>
void FF_tolower (FF_T_INT8 *string, FF_T_UINT32 strLen); #ifdef WIN32
void FF_toupper (FF_T_INT8 *string, FF_T_UINT32 strLen); #define stricmp stricmp
FF_T_BOOL FF_strmatch (const FF_T_INT8 *str1, const FF_T_INT8 *str2, FF_T_UINT16 len); #define FF_stricmp stricmp
FF_T_INT8 *FF_strtok (const FF_T_INT8 *string, FF_T_INT8 *token, FF_T_UINT16 *tokenNumber, FF_T_BOOL *last, FF_T_UINT16 Length); #else
FF_T_BOOL FF_wildcompare(const FF_T_INT8 *pszWildCard, const FF_T_INT8 *pszString); #define strcasecmp strcasecmp
#define FF_stricmp strcasecmp
#endif
#ifdef FF_UNICODE_SUPPORT
void FF_tolower (FF_T_WCHAR *string, FF_T_UINT32 strLen);
void FF_toupper (FF_T_WCHAR *string, FF_T_UINT32 strLen);
FF_T_BOOL FF_strmatch (const FF_T_WCHAR *str1, const FF_T_WCHAR *str2, FF_T_UINT16 len);
FF_T_WCHAR *FF_strtok (const FF_T_WCHAR *string, FF_T_WCHAR *token, FF_T_UINT16 *tokenNumber, FF_T_BOOL *last, FF_T_UINT16 Length);
FF_T_BOOL FF_wildcompare (const FF_T_WCHAR *pszWildCard, const FF_T_WCHAR *pszString);
// ASCII to UTF16 and UTF16 to ASCII routines. -- These are lossy routines, and are only for converting ASCII to UTF-16
// and the equivalent back to ASCII. Do not use them for international text.
void FF_cstrtowcs(FF_T_WCHAR *wcsDest, const FF_T_INT8 *szpSource);
void FF_wcstocstr(FF_T_INT8 *szpDest, const FF_T_WCHAR *wcsSource);
void FF_cstrntowcs(FF_T_WCHAR *wcsDest, const FF_T_INT8 *szpSource, FF_T_UINT32 len);
void FF_wcsntocstr(FF_T_INT8 *szpDest, const FF_T_WCHAR *wcsSource, FF_T_UINT32 len);
#else
void FF_tolower (FF_T_INT8 *string, FF_T_UINT32 strLen);
void FF_toupper (FF_T_INT8 *string, FF_T_UINT32 strLen);
FF_T_BOOL FF_strmatch (const FF_T_INT8 *str1, const FF_T_INT8 *str2, FF_T_UINT16 len);
FF_T_INT8 *FF_strtok (const FF_T_INT8 *string, FF_T_INT8 *token, FF_T_UINT16 *tokenNumber, FF_T_BOOL *last, FF_T_UINT16 Length);
FF_T_BOOL FF_wildcompare (const FF_T_INT8 *pszWildCard, const FF_T_INT8 *pszString);
#endif
#endif #endif

View file

@ -61,6 +61,11 @@ typedef long FF_T_INT32; ///< 32 bit default integer.
typedef unsigned long FF_T_UINT32; ///< 32 bit unsigned integer. typedef unsigned long FF_T_UINT32; ///< 32 bit unsigned integer.
typedef signed long FF_T_SINT32; ///< 32 bit signed integer. typedef signed long FF_T_SINT32; ///< 32 bit signed integer.
//---------------- Platform Integer Sizes
typedef int FF_T_INT;
typedef unsigned int FF_T_UINT;
typedef signed int FF_T_SINT;
#ifdef FF_64_NUM_SUPPORT #ifdef FF_64_NUM_SUPPORT
//---------------- 64 BIT INTEGERS // If you cannot define these, then make sure you see ff_config.h //---------------- 64 BIT INTEGERS // If you cannot define these, then make sure you see ff_config.h
typedef long long FF_T_INT64; // about 64-bit number support. typedef long long FF_T_INT64; // about 64-bit number support.
@ -70,5 +75,9 @@ typedef signed long long FF_T_SINT64; // > 4GB in bytes if you cannot support 64
#endif #endif
typedef FF_T_SINT32 FF_ERROR; ///< A special error code type to ease some inconsistencies in Error reporting. typedef FF_T_SINT32 FF_ERROR; ///< A special error code type to ease some inconsistencies in Error reporting.
#ifdef FF_UNICODE_SUPPORT
#include <wchar.h>
typedef wchar_t FF_T_WCHAR; ///< Unicode UTF-16 Charachter type, for FullFAT when UNICODE is enabled.
#endif
#endif // end of include guard #endif // end of include guard

View file

@ -0,0 +1,60 @@
/*****************************************************************************
* FullFAT - High Performance, Thread-Safe Embedded FAT File-System *
* Copyright (C) 2009 James Walmsley (james@worm.me.uk) *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
* IMPORTANT NOTICE: *
* ================= *
* Alternative Licensing is available directly from the Copyright holder, *
* (James Walmsley). For more information consult LICENSING.TXT to obtain *
* a Commercial license. *
* *
* See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT. *
* *
* Removing the above notice is illegal and will invalidate this license. *
*****************************************************************************
* See http://worm.me.uk/fullfat for more information. *
* Or http://fullfat.googlecode.com/ for latest releases and the wiki. *
*****************************************************************************/
/**
* @file ff_unicode.c
* @author James Walmsley
* @ingroup UNICODE
*
**/
#ifndef _FF_UNICODE_H_
#define _FF_UNICODE_H_
#include "ff_config.h"
#include "ff_types.h"
#include "ff_error.h"
// UTF8 / UTF16 Transformation Functions
FF_T_UINT FF_GetUtf16SequenceLen (FF_T_UINT16 usLeadChar);
FF_T_SINT32 FF_Utf8ctoUtf16c (FF_T_UINT16 *utf16Dest, const FF_T_UINT8 *utf8Source, FF_T_UINT32 ulSize);
FF_T_SINT32 FF_Utf16ctoUtf8c (FF_T_UINT8 *utf8Dest, const FF_T_UINT16 *utf16Source, FF_T_UINT32 ulSize);
// UTF16 / UTF32 Transformation Functions
FF_T_SINT32 FF_Utf16ctoUtf32c(FF_T_UINT32 *utf32Dest, const FF_T_UINT16 *utf16Source);
FF_T_SINT32 FF_Utf32ctoUtf16c(FF_T_UINT16 *utf16Dest, FF_T_UINT32 utf32char, FF_T_UINT32 ulSize);
// String transformations
FF_T_SINT32 FF_Utf32stoUtf8s(FF_T_UINT8 *Utf8String, FF_T_UINT32 *Utf32String);
#endif

View file

@ -45,6 +45,7 @@ extern "C" {
#include "ff_crc.h" #include "ff_crc.h"
#include "ff_hash.h" #include "ff_hash.h"
#include "ff_string.h" #include "ff_string.h"
#include "ff_unicode.h"
//#include "ff_format.h" //#include "ff_format.h"
#ifdef __cplusplus #ifdef __cplusplus

View file

@ -41,7 +41,68 @@
#include "ff_crc.h" #include "ff_crc.h"
static const FF_T_UINT8 CRC16_Low[256] =
static const FF_T_UINT32 crc32_table[256] = {
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106,
0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA,
0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84,
0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,
0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
};
FF_T_UINT32 FF_GetCRC32(FF_T_UINT8 *pbyData, FF_T_UINT32 stLength) {
register FF_T_UINT32 crc = 0xFFFFFFFF;
while(stLength--) {
crc = ((crc >> 8) & 0x00FFFFFF) ^ crc32_table[(crc^*pbyData++) & 0x000000FF];
}
return (crc ^ 0xFFFFFFFF);
}
static const FF_T_UINT8 crc16_table_low[256] =
{ {
0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041,
0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040,
@ -77,7 +138,7 @@ static const FF_T_UINT8 CRC16_Low[256] =
0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040,
}; };
static const FF_T_UINT8 CRC16_High[256] = static const FF_T_UINT8 crc16_table_high[256] =
{ {
0x000, 0x0c0, 0x0c1, 0x001, 0x0c3, 0x003, 0x002, 0x0c2, 0x000, 0x0c0, 0x0c1, 0x001, 0x0c3, 0x003, 0x002, 0x0c2,
0x0c6, 0x006, 0x007, 0x0c7, 0x005, 0x0c5, 0x0c4, 0x004, 0x0c6, 0x006, 0x007, 0x0c7, 0x005, 0x0c5, 0x0c4, 0x004,
@ -130,15 +191,15 @@ FF_T_UINT16 FF_GetCRC16(FF_T_UINT8 *pbyData, FF_T_UINT32 stLength) {
while (stLength--) { while (stLength--) {
bTableValue = (FF_T_UINT8)((wCRC & 0x00FF) ^ *pbyData++); bTableValue = (FF_T_UINT8)((wCRC & 0x00FF) ^ *pbyData++);
wCRC = (FF_T_UINT16)(((CRC16_High[bTableValue]) << 8) wCRC = (FF_T_UINT16)(((crc16_table_high[bTableValue]) << 8)
+ (CRC16_Low[bTableValue] ^ ((wCRC >> 8) & 0x00FF))); + (crc16_table_low[bTableValue] ^ ((wCRC >> 8) & 0x00FF)));
} }
return wCRC; return wCRC;
} }
static const FF_T_UINT8 byCRCLookUpTable[256] = static const FF_T_UINT8 crc8_table[256] =
{ {
0, 94, 188, 226, 97, 63, 221, 131, 0, 94, 188, 226, 97, 63, 221, 131,
194, 156, 126, 32, 163, 253, 31, 65, 194, 156, 126, 32, 163, 253, 31, 65,
@ -188,7 +249,7 @@ FF_T_UINT8 FF_GetCRC8(FF_T_UINT8 *pbyData, FF_T_UINT32 stLength) {
FF_T_UINT8 byCRC = 0, byData; FF_T_UINT8 byCRC = 0, byData;
while (stLength--) { while (stLength--) {
byData = *pbyData++; byData = *pbyData++;
byCRC = byCRCLookUpTable[(byCRC ^ byData)]; byCRC = crc8_table[(byCRC ^ byData)];
} }
return byCRC; return byCRC;
} }

File diff suppressed because it is too large Load diff

View file

@ -52,54 +52,118 @@
#include <string.h> #include <string.h>
typedef struct { typedef struct {
FF_T_INT8 FileName[FF_MAX_FILENAME]; FF_T_UINT32 ulChainLength;
FF_T_UINT8 Attrib; FF_T_UINT32 ulDirCluster;
FF_T_UINT32 ulCurrentClusterLCN;
FF_T_UINT32 ulCurrentClusterNum;
FF_T_UINT32 ulCurrentEntry;
FF_BUFFER *pBuffer;
} FF_FETCH_CONTEXT;
typedef struct {
FF_T_UINT32 Filesize; FF_T_UINT32 Filesize;
FF_T_UINT32 ObjectCluster; FF_T_UINT32 ObjectCluster;
// Book Keeping
FF_T_UINT32 CurrentCluster;
FF_T_UINT32 AddrCurrentCluster;
FF_T_UINT32 DirCluster;
FF_T_UINT16 CurrentItem;
// End Book Keeping
#ifdef FF_TIME_SUPPORT #ifdef FF_TIME_SUPPORT
FF_SYSTEMTIME CreateTime; ///< Date and Time Created. FF_SYSTEMTIME CreateTime; ///< Date and Time Created.
FF_SYSTEMTIME ModifiedTime; ///< Date and Time Modified. FF_SYSTEMTIME ModifiedTime; ///< Date and Time Modified.
FF_SYSTEMTIME AccessedTime; ///< Date of Last Access. FF_SYSTEMTIME AccessedTime; ///< Date of Last Access.
#endif #endif
//---- Book Keeping for FF_Find Functions #ifdef FF_FINDAPI_ALLOW_WILDCARDS
FF_T_UINT16 CurrentItem; #ifdef FF_UNICODE_SUPPORT
FF_T_UINT32 DirCluster; FF_T_WCHAR szWildCard[FF_MAX_FILENAME];
FF_T_UINT32 CurrentCluster; #else
FF_T_UINT32 AddrCurrentCluster; FF_T_INT8 szWildCard[FF_MAX_FILENAME];
//FF_T_UINT8 NumLFNs; #endif
#endif
#ifdef FF_UNICODE_SUPPORT
FF_T_WCHAR FileName[FF_MAX_FILENAME];
#else
FF_T_INT8 FileName[FF_MAX_FILENAME];
#endif
#if defined(FF_LFN_SUPPORT) && defined(FF_INCLUDE_SHORT_NAME)
FF_T_INT8 ShortName[13];
#endif
FF_T_UINT8 Attrib;
FF_FETCH_CONTEXT FetchContext;
} FF_DIRENT; } FF_DIRENT;
FF_ERROR FF_GetEntry (FF_IOMAN *pIoman, FF_T_UINT16 nEntry, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent);
FF_T_SINT8 FF_PutEntry (FF_IOMAN *pIoman, FF_T_UINT16 Entry, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent);
FF_T_SINT8 FF_FindEntry (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *Name, FF_DIRENT *pDirent, FF_T_BOOL LFNs);
FF_ERROR FF_FindFirst (FF_IOMAN *pIoman, FF_DIRENT *pDirent, const FF_T_INT8 *path);
FF_ERROR FF_FindNext (FF_IOMAN *pIoman, FF_DIRENT *pDirent);
void FF_PopulateShortDirent(FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_T_UINT8 *EntryBuffer);
FF_T_SINT8 FF_PopulateLongDirent(FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_T_UINT32 DirCluster, FF_T_UINT16 nEntry);
FF_T_SINT8 FF_FetchEntry (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT16 nEntry, FF_T_UINT8 *buffer);
FF_T_SINT8 FF_PushEntry (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT16 nEntry, FF_T_UINT8 *buffer);
FF_T_BOOL FF_isEndOfDir (FF_T_UINT8 *EntryBuffer);
FF_T_SINT8 FF_FindNextInDir(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent);
FF_T_UINT32 FF_FindEntryInDir(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *name, FF_T_UINT8 pa_Attrib, FF_DIRENT *pDirent);
FF_T_SINT8 FF_CreateShortName(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *ShortName, FF_T_INT8 *LongName);
void FF_lockDIR (FF_IOMAN *pIoman);
void FF_unlockDIR (FF_IOMAN *pIoman);
FF_T_UINT32 FF_CreateFile(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *FileName, FF_DIRENT *pDirent);
FF_ERROR FF_MkDir(FF_IOMAN *pIoman, const FF_T_INT8 *Path);
FF_T_SINT8 FF_CreateDirent(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent);
FF_T_SINT8 FF_ExtendDirectory(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster);
FF_T_UINT32 FF_FindDir(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT16 pathLen);
FF_T_BOOL FF_CheckDirentHash(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT32 nHash); // PUBLIC API
FF_T_BOOL FF_DirHashed(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster); #ifdef FF_UNICODE_SUPPORT
FF_ERROR FF_AddDirentHash(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT32 nHash); FF_ERROR FF_FindFirst (FF_IOMAN *pIoman, FF_DIRENT *pDirent, const FF_T_WCHAR *path);
void FF_SetDirHashed(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster); FF_ERROR FF_MkDir (FF_IOMAN *pIoman, const FF_T_WCHAR *Path);
#else
FF_ERROR FF_FindFirst (FF_IOMAN *pIoman, FF_DIRENT *pDirent, const FF_T_INT8 *path);
FF_ERROR FF_MkDir (FF_IOMAN *pIoman, const FF_T_INT8 *Path);
#endif
void FF_RmLFNs(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT16 DirEntry); FF_ERROR FF_FindNext (FF_IOMAN *pIoman, FF_DIRENT *pDirent);
// INTERNAL API
FF_ERROR FF_GetEntry (FF_IOMAN *pIoman, FF_T_UINT16 nEntry, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent);
FF_ERROR FF_PutEntry (FF_IOMAN *pIoman, FF_T_UINT16 Entry, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent);
FF_T_SINT8 FF_FindEntry (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *Name, FF_DIRENT *pDirent, FF_T_BOOL LFNs);
void FF_PopulateShortDirent (FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_T_UINT8 *EntryBuffer);
FF_ERROR FF_PopulateLongDirent (FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_T_UINT16 nEntry, FF_FETCH_CONTEXT *pFetchContext);
FF_ERROR FF_InitEntryFetch (FF_IOMAN *pIoman, FF_T_UINT32 ulDirCluster, FF_FETCH_CONTEXT *pContext);
FF_ERROR FF_FetchEntryWithContext (FF_IOMAN *pIoman, FF_T_UINT32 ulEntry, FF_FETCH_CONTEXT *pContext, FF_T_UINT8 *pEntryBuffer);
FF_ERROR FF_PushEntryWithContext (FF_IOMAN *pIoman, FF_T_UINT32 ulEntry, FF_FETCH_CONTEXT *pContext, FF_T_UINT8 *pEntryBuffer);
void FF_CleanupEntryFetch (FF_IOMAN *pIoman, FF_FETCH_CONTEXT *pContext);
FF_T_SINT8 FF_PushEntry (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT16 nEntry, FF_T_UINT8 *buffer, void *pParam);
FF_T_BOOL FF_isEndOfDir (FF_T_UINT8 *EntryBuffer);
FF_ERROR FF_FindNextInDir (FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_FETCH_CONTEXT *pFetchContext);
#ifdef FF_UNICODE_SUPPORT
FF_T_UINT32 FF_FindEntryInDir (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, const FF_T_WCHAR *name, FF_T_UINT8 pa_Attrib, FF_DIRENT *pDirent, FF_ERROR *pError);
FF_T_SINT8 FF_CreateShortName (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_WCHAR *ShortName, FF_T_WCHAR *LongName);
#else
FF_T_UINT32 FF_FindEntryInDir (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, const FF_T_INT8 *name, FF_T_UINT8 pa_Attrib, FF_DIRENT *pDirent, FF_ERROR *pError);
FF_T_SINT8 FF_CreateShortName (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *ShortName, FF_T_INT8 *LongName);
#endif
void FF_lockDIR (FF_IOMAN *pIoman);
void FF_unlockDIR (FF_IOMAN *pIoman);
#ifdef FF_UNICODE_SUPPORT
FF_T_UINT32 FF_CreateFile(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_WCHAR *FileName, FF_DIRENT *pDirent, FF_ERROR *pError);
#else
FF_T_UINT32 FF_CreateFile(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *FileName, FF_DIRENT *pDirent, FF_ERROR *pError);
#endif
FF_ERROR FF_CreateDirent (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent);
FF_ERROR FF_ExtendDirectory (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster);
#ifdef FF_UNICODE_SUPPORT
FF_T_UINT32 FF_FindDir (FF_IOMAN *pIoman, const FF_T_WCHAR *path, FF_T_UINT16 pathLen, FF_ERROR *pError);
#else
FF_T_UINT32 FF_FindDir (FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT16 pathLen, FF_ERROR *pError);
#endif
#ifdef FF_HASH_CACHE
FF_T_BOOL FF_CheckDirentHash (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT32 nHash);
FF_T_BOOL FF_DirHashed (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster);
FF_ERROR FF_AddDirentHash (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT32 nHash);
FF_ERROR FF_HashDir (FF_IOMAN *pIoman, FF_T_UINT32 ulDirCluster);
#endif
FF_ERROR FF_RmLFNs(FF_IOMAN *pIoman, FF_T_UINT16 usDirEntry, FF_FETCH_CONTEXT *pContext);
#endif #endif

View file

@ -56,7 +56,7 @@ const struct _FFERRTAB
{"Not enough memory (malloc() returned NULL).", FF_ERR_NOT_ENOUGH_MEMORY}, {"Not enough memory (malloc() returned NULL).", FF_ERR_NOT_ENOUGH_MEMORY},
{"Device Driver returned a FATAL error!.", FF_ERR_DEVICE_DRIVER_FAILED}, {"Device Driver returned a FATAL error!.", FF_ERR_DEVICE_DRIVER_FAILED},
{"The blocksize is not 512 multiple.", FF_ERR_IOMAN_BAD_BLKSIZE}, {"The blocksize is not 512 multiple.", FF_ERR_IOMAN_BAD_BLKSIZE},
{"The provided memory size, is not a multiple of the blocksize.", FF_ERR_IOMAN_BAD_MEMSIZE}, {"The memory size, is not a multiple of the blocksize. (Atleast 2 Blocks).", FF_ERR_IOMAN_BAD_MEMSIZE},
{"Device is already registered, use FF_UnregisterBlkDevice() first.", FF_ERR_IOMAN_DEV_ALREADY_REGD}, {"Device is already registered, use FF_UnregisterBlkDevice() first.", FF_ERR_IOMAN_DEV_ALREADY_REGD},
{"No mountable partition was found on the specified device.", FF_ERR_IOMAN_NO_MOUNTABLE_PARTITION}, {"No mountable partition was found on the specified device.", FF_ERR_IOMAN_NO_MOUNTABLE_PARTITION},
{"The format of the MBR was unrecognised.", FF_ERR_IOMAN_INVALID_FORMAT}, {"The format of the MBR was unrecognised.", FF_ERR_IOMAN_INVALID_FORMAT},
@ -65,6 +65,7 @@ const struct _FFERRTAB
{"Cannot register device. (BlkSize not a multiple of 512).", FF_ERR_IOMAN_DEV_INVALID_BLKSIZE}, {"Cannot register device. (BlkSize not a multiple of 512).", FF_ERR_IOMAN_DEV_INVALID_BLKSIZE},
{"Cannot unregister device, a partition is still mounted.", FF_ERR_IOMAN_PARTITION_MOUNTED}, {"Cannot unregister device, a partition is still mounted.", FF_ERR_IOMAN_PARTITION_MOUNTED},
{"Cannot unmount the partition while there are active FILE handles.", FF_ERR_IOMAN_ACTIVE_HANDLES}, {"Cannot unmount the partition while there are active FILE handles.", FF_ERR_IOMAN_ACTIVE_HANDLES},
{"The GPT partition header appears to be corrupt, refusing to mount.", FF_ERR_IOMAN_GPT_HEADER_CORRUPT},
{"Cannot open the file, file already in use.", FF_ERR_FILE_ALREADY_OPEN}, {"Cannot open the file, file already in use.", FF_ERR_FILE_ALREADY_OPEN},
{"The specified file could not be found.", FF_ERR_FILE_NOT_FOUND}, {"The specified file could not be found.", FF_ERR_FILE_NOT_FOUND},
{"Cannot open a Directory.", FF_ERR_FILE_OBJECT_IS_A_DIR}, {"Cannot open a Directory.", FF_ERR_FILE_OBJECT_IS_A_DIR},
@ -84,6 +85,9 @@ const struct _FFERRTAB
{"Source file was not found.", FF_ERR_FILE_SOURCE_NOT_FOUND}, {"Source file was not found.", FF_ERR_FILE_SOURCE_NOT_FOUND},
{"Destination path (dir) was not found.", FF_ERR_FILE_DIR_NOT_FOUND}, {"Destination path (dir) was not found.", FF_ERR_FILE_DIR_NOT_FOUND},
{"Failed to create the directory Entry.", FF_ERR_FILE_COULD_NOT_CREATE_DIRENT}, {"Failed to create the directory Entry.", FF_ERR_FILE_COULD_NOT_CREATE_DIRENT},
{"Not enough free disk space to complete the disk transaction.", FF_ERR_IOMAN_NOT_ENOUGH_FREE_SPACE},
{"Attempted to Read a sector out of bounds.", FF_ERR_IOMAN_OUT_OF_BOUNDS_READ},
{"Attempted to Write a sector out of bounds.", FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE},
}; };
/** /**

View file

@ -110,7 +110,7 @@ FF_T_UINT32 FF_LBA2Cluster(FF_IOMAN *pIoman, FF_T_UINT32 Address) {
/** /**
* @private * @private
**/ **/
FF_T_SINT32 FF_getFatEntry(FF_IOMAN *pIoman, FF_T_UINT32 nCluster) { FF_T_UINT32 FF_getFatEntry(FF_IOMAN *pIoman, FF_T_UINT32 nCluster, FF_ERROR *pError) {
FF_BUFFER *pBuffer; FF_BUFFER *pBuffer;
FF_T_UINT32 FatOffset; FF_T_UINT32 FatOffset;
@ -148,7 +148,8 @@ FF_T_SINT32 FF_getFatEntry(FF_IOMAN *pIoman, FF_T_UINT32 nCluster) {
pBuffer = FF_GetBuffer(pIoman, FatSector + LBAadjust, FF_MODE_READ); pBuffer = FF_GetBuffer(pIoman, FatSector + LBAadjust, FF_MODE_READ);
{ {
if(!pBuffer) { if(!pBuffer) {
return FF_ERR_DEVICE_DRIVER_FAILED; *pError = FF_ERR_DEVICE_DRIVER_FAILED;
return 0;
} }
F12short[0] = FF_getChar(pBuffer->pBuffer, (FF_T_UINT16)(pIoman->BlkSize - 1)); F12short[0] = FF_getChar(pBuffer->pBuffer, (FF_T_UINT16)(pIoman->BlkSize - 1));
} }
@ -157,7 +158,8 @@ FF_T_SINT32 FF_getFatEntry(FF_IOMAN *pIoman, FF_T_UINT32 nCluster) {
pBuffer = FF_GetBuffer(pIoman, FatSector + LBAadjust + 1, FF_MODE_READ); pBuffer = FF_GetBuffer(pIoman, FatSector + LBAadjust + 1, FF_MODE_READ);
{ {
if(!pBuffer) { if(!pBuffer) {
return FF_ERR_DEVICE_DRIVER_FAILED; *pError = FF_ERR_DEVICE_DRIVER_FAILED;
return 0;
} }
F12short[1] = FF_getChar(pBuffer->pBuffer, 0); F12short[1] = FF_getChar(pBuffer->pBuffer, 0);
} }
@ -176,7 +178,8 @@ FF_T_SINT32 FF_getFatEntry(FF_IOMAN *pIoman, FF_T_UINT32 nCluster) {
pBuffer = FF_GetBuffer(pIoman, FatSector + LBAadjust, FF_MODE_READ); pBuffer = FF_GetBuffer(pIoman, FatSector + LBAadjust, FF_MODE_READ);
{ {
if(!pBuffer) { if(!pBuffer) {
return FF_ERR_DEVICE_DRIVER_FAILED; *pError = FF_ERR_DEVICE_DRIVER_FAILED;
return 0;
} }
switch(pIoman->pPartition->Type) { switch(pIoman->pPartition->Type) {
@ -208,11 +211,10 @@ FF_T_SINT32 FF_getFatEntry(FF_IOMAN *pIoman, FF_T_UINT32 nCluster) {
return (FF_T_SINT32) FatEntry; return (FF_T_SINT32) FatEntry;
} }
FF_T_SINT8 FF_ClearCluster(FF_IOMAN *pIoman, FF_T_UINT32 nCluster) { FF_ERROR FF_ClearCluster(FF_IOMAN *pIoman, FF_T_UINT32 nCluster) {
FF_BUFFER *pBuffer; FF_BUFFER *pBuffer;
FF_T_UINT16 i; FF_T_UINT16 i;
FF_T_UINT32 BaseLBA; FF_T_UINT32 BaseLBA;
FF_T_SINT8 RetVal = 0;
BaseLBA = FF_Cluster2LBA(pIoman, nCluster); BaseLBA = FF_Cluster2LBA(pIoman, nCluster);
BaseLBA = FF_getRealLBA(pIoman, BaseLBA); BaseLBA = FF_getRealLBA(pIoman, BaseLBA);
@ -220,16 +222,15 @@ FF_T_SINT8 FF_ClearCluster(FF_IOMAN *pIoman, FF_T_UINT32 nCluster) {
for(i = 0; i < pIoman->pPartition->SectorsPerCluster; i++) { for(i = 0; i < pIoman->pPartition->SectorsPerCluster; i++) {
pBuffer = FF_GetBuffer(pIoman, BaseLBA++, FF_MODE_WRITE); pBuffer = FF_GetBuffer(pIoman, BaseLBA++, FF_MODE_WRITE);
{ {
if(pBuffer) { if(!pBuffer) {
memset(pBuffer->pBuffer, 0x00, 512); return FF_ERR_DEVICE_DRIVER_FAILED;
} else {
RetVal = FF_ERR_DEVICE_DRIVER_FAILED;
} }
memset(pBuffer->pBuffer, 0x00, 512);
} }
FF_ReleaseBuffer(pIoman, pBuffer); FF_ReleaseBuffer(pIoman, pBuffer);
} }
return RetVal; return FF_ERR_NONE;
} }
/** /**
@ -240,17 +241,19 @@ FF_T_SINT8 FF_ClearCluster(FF_IOMAN *pIoman, FF_T_UINT32 nCluster) {
* @param Start Cluster address of the first cluster in the chain. * @param Start Cluster address of the first cluster in the chain.
* @param Count Number of Cluster in the chain, * @param Count Number of Cluster in the chain,
* *
* @return FF_TRUE if it is an end of chain, otherwise FF_FALSE. *
* *
**/ **/
FF_T_UINT32 FF_TraverseFAT(FF_IOMAN *pIoman, FF_T_UINT32 Start, FF_T_UINT32 Count) { FF_T_UINT32 FF_TraverseFAT(FF_IOMAN *pIoman, FF_T_UINT32 Start, FF_T_UINT32 Count, FF_ERROR *pError) {
FF_T_UINT32 i; FF_T_UINT32 i;
FF_T_UINT32 fatEntry = Start, currentCluster = Start; FF_T_UINT32 fatEntry = Start, currentCluster = Start;
*pError = FF_ERR_NONE;
for(i = 0; i < Count; i++) { for(i = 0; i < Count; i++) {
fatEntry = FF_getFatEntry(pIoman, currentCluster); fatEntry = FF_getFatEntry(pIoman, currentCluster, pError);
if(fatEntry == (FF_T_UINT32) FF_ERR_DEVICE_DRIVER_FAILED) { if(*pError) {
return 0; return 0;
} }
@ -264,13 +267,14 @@ FF_T_UINT32 FF_TraverseFAT(FF_IOMAN *pIoman, FF_T_UINT32 Start, FF_T_UINT32 Coun
return fatEntry; return fatEntry;
} }
FF_T_UINT32 FF_FindEndOfChain(FF_IOMAN *pIoman, FF_T_UINT32 Start) { FF_T_UINT32 FF_FindEndOfChain(FF_IOMAN *pIoman, FF_T_UINT32 Start, FF_ERROR *pError) {
FF_T_UINT32 fatEntry = Start, currentCluster = Start; FF_T_UINT32 fatEntry = Start, currentCluster = Start;
*pError = FF_ERR_NONE;
while(!FF_isEndOfChain(pIoman, fatEntry)) { while(!FF_isEndOfChain(pIoman, fatEntry)) {
fatEntry = FF_getFatEntry(pIoman, currentCluster); fatEntry = FF_getFatEntry(pIoman, currentCluster, pError);
if(fatEntry == (FF_T_UINT32) FF_ERR_DEVICE_DRIVER_FAILED) { if(*pError) {
return 0; return 0;
} }
@ -325,7 +329,7 @@ FF_T_BOOL FF_isEndOfChain(FF_IOMAN *pIoman, FF_T_UINT32 fatEntry) {
* @param nCluster Cluster Number to be modified. * @param nCluster Cluster Number to be modified.
* @param Value The Value to store. * @param Value The Value to store.
**/ **/
FF_T_SINT8 FF_putFatEntry(FF_IOMAN *pIoman, FF_T_UINT32 nCluster, FF_T_UINT32 Value) { FF_ERROR FF_putFatEntry(FF_IOMAN *pIoman, FF_T_UINT32 nCluster, FF_T_UINT32 Value) {
FF_BUFFER *pBuffer; FF_BUFFER *pBuffer;
FF_T_UINT32 FatOffset; FF_T_UINT32 FatOffset;
@ -439,7 +443,7 @@ FF_T_SINT8 FF_putFatEntry(FF_IOMAN *pIoman, FF_T_UINT32 nCluster, FF_T_UINT32 Va
} }
FF_ReleaseBuffer(pIoman, pBuffer); FF_ReleaseBuffer(pIoman, pBuffer);
return 0; return FF_ERR_NONE;
} }
@ -454,12 +458,17 @@ FF_T_SINT8 FF_putFatEntry(FF_IOMAN *pIoman, FF_T_UINT32 nCluster, FF_T_UINT32 Va
* @return 0 on error. * @return 0 on error.
**/ **/
#ifdef FF_FAT12_SUPPORT #ifdef FF_FAT12_SUPPORT
FF_T_UINT32 FF_FindFreeClusterOLD(FF_IOMAN *pIoman) { static FF_T_UINT32 FF_FindFreeClusterOLD(FF_IOMAN *pIoman, FF_ERROR *pError) {
FF_T_UINT32 nCluster; FF_T_UINT32 nCluster;
FF_T_UINT32 fatEntry; FF_T_UINT32 fatEntry;
*pError = FF_ERR_NONE;
for(nCluster = pIoman->pPartition->LastFreeCluster; nCluster < pIoman->pPartition->NumClusters; nCluster++) { for(nCluster = pIoman->pPartition->LastFreeCluster; nCluster < pIoman->pPartition->NumClusters; nCluster++) {
fatEntry = FF_getFatEntry(pIoman, nCluster); fatEntry = FF_getFatEntry(pIoman, nCluster, pError);
if(*pError) {
return 0;
}
if(fatEntry == 0x00000000) { if(fatEntry == 0x00000000) {
pIoman->pPartition->LastFreeCluster = nCluster; pIoman->pPartition->LastFreeCluster = nCluster;
return nCluster; return nCluster;
@ -469,7 +478,7 @@ FF_T_UINT32 FF_FindFreeClusterOLD(FF_IOMAN *pIoman) {
} }
#endif #endif
FF_T_UINT32 FF_FindFreeCluster(FF_IOMAN *pIoman) { FF_T_UINT32 FF_FindFreeCluster(FF_IOMAN *pIoman, FF_ERROR *pError) {
FF_BUFFER *pBuffer; FF_BUFFER *pBuffer;
FF_T_UINT32 i, x, nCluster = pIoman->pPartition->LastFreeCluster; FF_T_UINT32 i, x, nCluster = pIoman->pPartition->LastFreeCluster;
FF_T_UINT32 FatOffset; FF_T_UINT32 FatOffset;
@ -478,9 +487,11 @@ FF_T_UINT32 FF_FindFreeCluster(FF_IOMAN *pIoman) {
FF_T_UINT32 EntriesPerSector; FF_T_UINT32 EntriesPerSector;
FF_T_UINT32 FatEntry = 1; FF_T_UINT32 FatEntry = 1;
*pError = FF_ERR_NONE;
#ifdef FF_FAT12_SUPPORT #ifdef FF_FAT12_SUPPORT
if(pIoman->pPartition->Type == FF_T_FAT12) { // FAT12 tables are too small to optimise, and would make it very complicated! if(pIoman->pPartition->Type == FF_T_FAT12) { // FAT12 tables are too small to optimise, and would make it very complicated!
return FF_FindFreeClusterOLD(pIoman); return FF_FindFreeClusterOLD(pIoman, pError);
} }
#endif #endif
@ -491,15 +502,20 @@ FF_T_UINT32 FF_FindFreeCluster(FF_IOMAN *pIoman) {
EntriesPerSector = pIoman->BlkSize / 2; EntriesPerSector = pIoman->BlkSize / 2;
FatOffset = nCluster * 2; FatOffset = nCluster * 2;
} }
// HT addition: don't use non-existing clusters
if (nCluster >= pIoman->pPartition->NumClusters) {
*pError = FF_ERR_FAT_NO_FREE_CLUSTERS;
return 0;
}
FatSector = (FatOffset / pIoman->pPartition->BlkSize); FatSector = (FatOffset / pIoman->pPartition->BlkSize);
for(i = FatSector; i < pIoman->pPartition->SectorsPerFAT; i++) { for(i = FatSector; i < pIoman->pPartition->SectorsPerFAT; i++) {
pBuffer = FF_GetBuffer(pIoman, pIoman->pPartition->FatBeginLBA + i, FF_MODE_READ); pBuffer = FF_GetBuffer(pIoman, pIoman->pPartition->FatBeginLBA + i, FF_MODE_READ);
{ {
// HT addition: don't use non-existing clusters if(!pBuffer) {
if (nCluster >= pIoman->pPartition->NumClusters) { *pError = FF_ERR_DEVICE_DRIVER_FAILED;
FF_ReleaseBuffer(pIoman, pBuffer);
return 0; return 0;
} }
for(x = nCluster % EntriesPerSector; x < EntriesPerSector; x++) { for(x = nCluster % EntriesPerSector; x < EntriesPerSector; x++) {
@ -533,24 +549,54 @@ FF_T_UINT32 FF_FindFreeCluster(FF_IOMAN *pIoman) {
* @private * @private
* @brief Create's a Cluster Chain * @brief Create's a Cluster Chain
**/ **/
FF_T_UINT32 FF_CreateClusterChain(FF_IOMAN *pIoman) { FF_T_UINT32 FF_CreateClusterChain(FF_IOMAN *pIoman, FF_ERROR *pError) {
FF_T_UINT32 iStartCluster; FF_T_UINT32 iStartCluster;
FF_ERROR Error;
*pError = FF_ERR_NONE;
FF_lockFAT(pIoman); FF_lockFAT(pIoman);
{ {
iStartCluster = FF_FindFreeCluster(pIoman); iStartCluster = FF_FindFreeCluster(pIoman, &Error);
FF_putFatEntry(pIoman, iStartCluster, 0xFFFFFFFF); // Mark the cluster as EOC if(Error) {
*pError = Error;
FF_unlockFAT(pIoman);
return 0;
}
if(iStartCluster) {
Error = FF_putFatEntry(pIoman, iStartCluster, 0xFFFFFFFF); // Mark the cluster as End-Of-Chain
if(Error) {
*pError = Error;
FF_unlockFAT(pIoman);
return 0;
}
}
} }
FF_unlockFAT(pIoman); FF_unlockFAT(pIoman);
if(iStartCluster) {
Error = FF_DecreaseFreeClusters(pIoman, 1);
if(Error) {
*pError = Error;
return 0;
}
}
return iStartCluster; return iStartCluster;
} }
FF_T_UINT32 FF_GetChainLength(FF_IOMAN *pIoman, FF_T_UINT32 pa_nStartCluster, FF_T_UINT32 *piEndOfChain) { FF_T_UINT32 FF_GetChainLength(FF_IOMAN *pIoman, FF_T_UINT32 pa_nStartCluster, FF_T_UINT32 *piEndOfChain, FF_ERROR *pError) {
FF_T_UINT32 iLength = 0; FF_T_UINT32 iLength = 0;
*pError = FF_ERR_NONE;
FF_lockFAT(pIoman); FF_lockFAT(pIoman);
{ {
while(!FF_isEndOfChain(pIoman, pa_nStartCluster)) { while(!FF_isEndOfChain(pIoman, pa_nStartCluster)) {
pa_nStartCluster = FF_getFatEntry(pIoman, pa_nStartCluster); pa_nStartCluster = FF_getFatEntry(pIoman, pa_nStartCluster, pError);
if(*pError) {
return 0;
}
iLength++; iLength++;
} }
if(piEndOfChain) { if(piEndOfChain) {
@ -612,12 +658,13 @@ FF_T_UINT32 FF_ExtendClusterChain(FF_IOMAN *pIoman, FF_T_UINT32 StartCluster, FF
* @return -1 If the device driver failed to provide access. * @return -1 If the device driver failed to provide access.
* *
**/ **/
FF_T_SINT8 FF_UnlinkClusterChain(FF_IOMAN *pIoman, FF_T_UINT32 StartCluster, FF_T_UINT16 Count) { FF_ERROR FF_UnlinkClusterChain(FF_IOMAN *pIoman, FF_T_UINT32 StartCluster, FF_T_UINT16 Count) {
FF_T_UINT32 fatEntry; FF_T_UINT32 fatEntry;
FF_T_UINT32 currentCluster, chainLength = 0; FF_T_UINT32 currentCluster, chainLength = 0;
FF_T_UINT32 iLen = 0; FF_T_UINT32 iLen = 0;
FF_T_UINT32 lastFree = StartCluster; /* HT addition : reset LastFreeCluster */ FF_T_UINT32 lastFree = StartCluster; /* HT addition : reset LastFreeCluster */
FF_ERROR Error;
fatEntry = StartCluster; fatEntry = StartCluster;
@ -626,8 +673,15 @@ FF_T_SINT8 FF_UnlinkClusterChain(FF_IOMAN *pIoman, FF_T_UINT32 StartCluster, FF_
currentCluster = StartCluster; currentCluster = StartCluster;
fatEntry = currentCluster; fatEntry = currentCluster;
do { do {
fatEntry = FF_getFatEntry(pIoman, fatEntry); fatEntry = FF_getFatEntry(pIoman, fatEntry, &Error);
FF_putFatEntry(pIoman, currentCluster, 0x00000000); if(Error) {
return Error;
}
Error = FF_putFatEntry(pIoman, currentCluster, 0x00000000);
if(Error) {
return Error;
}
if (lastFree > currentCluster) { if (lastFree > currentCluster) {
lastFree = currentCluster; lastFree = currentCluster;
} }
@ -637,11 +691,17 @@ FF_T_SINT8 FF_UnlinkClusterChain(FF_IOMAN *pIoman, FF_T_UINT32 StartCluster, FF_
if (pIoman->pPartition->LastFreeCluster > lastFree) { if (pIoman->pPartition->LastFreeCluster > lastFree) {
pIoman->pPartition->LastFreeCluster = lastFree; pIoman->pPartition->LastFreeCluster = lastFree;
} }
FF_IncreaseFreeClusters(pIoman, iLen); Error = FF_IncreaseFreeClusters(pIoman, iLen);
if(Error) {
return Error;
}
} else { } else {
// Truncation - This is quite hard, because we can only do it backwards. // Truncation - This is quite hard, because we can only do it backwards.
do { do {
fatEntry = FF_getFatEntry(pIoman, fatEntry); fatEntry = FF_getFatEntry(pIoman, fatEntry, &Error);
if(Error) {
return Error;
}
chainLength++; chainLength++;
}while(!FF_isEndOfChain(pIoman, fatEntry)); }while(!FF_isEndOfChain(pIoman, fatEntry));
} }
@ -650,14 +710,19 @@ FF_T_SINT8 FF_UnlinkClusterChain(FF_IOMAN *pIoman, FF_T_UINT32 StartCluster, FF_
} }
#ifdef FF_FAT12_SUPPORT #ifdef FF_FAT12_SUPPORT
FF_T_UINT32 FF_CountFreeClustersOLD(FF_IOMAN *pIoman) { FF_T_UINT32 FF_CountFreeClustersOLD(FF_IOMAN *pIoman, FF_ERROR *pError) {
FF_T_UINT32 i; FF_T_UINT32 i;
FF_T_UINT32 TotalClusters = pIoman->pPartition->DataSectors / pIoman->pPartition->SectorsPerCluster; FF_T_UINT32 TotalClusters = pIoman->pPartition->DataSectors / pIoman->pPartition->SectorsPerCluster;
FF_T_UINT32 FatEntry; FF_T_UINT32 FatEntry;
FF_T_UINT32 FreeClusters = 0; FF_T_UINT32 FreeClusters = 0;
*pError = FF_ERR_NONE;
for(i = 0; i < TotalClusters; i++) { for(i = 0; i < TotalClusters; i++) {
FatEntry = FF_getFatEntry(pIoman, i); FatEntry = FF_getFatEntry(pIoman, i, pError);
if(*pError) {
return 0;
}
if(!FatEntry) { if(!FatEntry) {
FreeClusters++; FreeClusters++;
} }
@ -668,7 +733,7 @@ FF_T_UINT32 FF_CountFreeClustersOLD(FF_IOMAN *pIoman) {
#endif #endif
FF_T_UINT32 FF_CountFreeClusters(FF_IOMAN *pIoman) { FF_T_UINT32 FF_CountFreeClusters(FF_IOMAN *pIoman, FF_ERROR *pError) {
FF_BUFFER *pBuffer; FF_BUFFER *pBuffer;
FF_T_UINT32 i, x, nCluster = 0; FF_T_UINT32 i, x, nCluster = 0;
FF_T_UINT32 FatOffset; FF_T_UINT32 FatOffset;
@ -678,9 +743,14 @@ FF_T_UINT32 FF_CountFreeClusters(FF_IOMAN *pIoman) {
FF_T_UINT32 FatEntry = 1; FF_T_UINT32 FatEntry = 1;
FF_T_UINT32 FreeClusters = 0; FF_T_UINT32 FreeClusters = 0;
*pError = FF_ERR_NONE;
#ifdef FF_FAT12_SUPPORT #ifdef FF_FAT12_SUPPORT
if(pIoman->pPartition->Type == FF_T_FAT12) { // FAT12 tables are too small to optimise, and would make it very complicated! if(pIoman->pPartition->Type == FF_T_FAT12) { // FAT12 tables are too small to optimise, and would make it very complicated!
return FF_CountFreeClustersOLD(pIoman); FreeClusters = FF_CountFreeClustersOLD(pIoman, pError);
if(*pError) {
return 0;
}
} }
#endif #endif
@ -697,6 +767,10 @@ FF_T_UINT32 FF_CountFreeClusters(FF_IOMAN *pIoman) {
for(i = 0; i < pIoman->pPartition->SectorsPerFAT; i++) { for(i = 0; i < pIoman->pPartition->SectorsPerFAT; i++) {
pBuffer = FF_GetBuffer(pIoman, pIoman->pPartition->FatBeginLBA + i, FF_MODE_READ); pBuffer = FF_GetBuffer(pIoman, pIoman->pPartition->FatBeginLBA + i, FF_MODE_READ);
{ {
if(!pBuffer) {
*pError = FF_ERR_DEVICE_DRIVER_FAILED;
return 0;
}
for(x = nCluster % EntriesPerSector; x < EntriesPerSector; x++) { for(x = nCluster % EntriesPerSector; x < EntriesPerSector; x++) {
if(pIoman->pPartition->Type == FF_T_FAT32) { if(pIoman->pPartition->Type == FF_T_FAT32) {
FatOffset = x * 4; FatOffset = x * 4;
@ -722,15 +796,23 @@ FF_T_UINT32 FF_CountFreeClusters(FF_IOMAN *pIoman) {
} }
#ifdef FF_64_NUM_SUPPORT #ifdef FF_64_NUM_SUPPORT
FF_T_UINT64 FF_GetFreeSize(FF_IOMAN *pIoman) { FF_T_UINT64 FF_GetFreeSize(FF_IOMAN *pIoman, FF_ERROR *pError) {
FF_T_UINT32 FreeClusters; FF_T_UINT32 FreeClusters;
FF_T_UINT64 FreeSize; FF_T_UINT64 FreeSize;
FF_ERROR Error;
if(pIoman) { if(pIoman) {
FF_lockFAT(pIoman); FF_lockFAT(pIoman);
{ {
if(!pIoman->pPartition->FreeClusterCount) { if(!pIoman->pPartition->FreeClusterCount) {
pIoman->pPartition->FreeClusterCount = FF_CountFreeClusters(pIoman); pIoman->pPartition->FreeClusterCount = FF_CountFreeClusters(pIoman, &Error);
if(Error) {
if(pError) {
*pError = Error;
}
FF_unlockFAT(pIoman);
return 0;
}
} }
FreeClusters = pIoman->pPartition->FreeClusterCount; FreeClusters = pIoman->pPartition->FreeClusterCount;
} }

File diff suppressed because it is too large Load diff

132
reactos/lib/3rdparty/fullfat/ff_format.c vendored Normal file
View file

@ -0,0 +1,132 @@
/*****************************************************************************
* FullFAT - High Performance, Thread-Safe Embedded FAT File-System *
* Copyright (C) 2009 James Walmsley (james@worm.me.uk) *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
* IMPORTANT NOTICE: *
* ================= *
* Alternative Licensing is available directly from the Copyright holder, *
* (James Walmsley). For more information consult LICENSING.TXT to obtain *
* a Commercial license. *
* *
* See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT. *
* *
* Removing the above notice is illegal and will invalidate this license. *
*****************************************************************************
* See http://worm.me.uk/fullfat for more information. *
* Or http://fullfat.googlecode.com/ for latest releases and the wiki. *
*****************************************************************************/
/**
* @file ff_format.c
* @author James Walmsley
* @ingroup FORMAT
*
* @defgroup FORMAT Independent FAT Formatter
* @brief Provides an interface to format a partition with FAT.
*
*
*
**/
#include "ff_format.h"
#include "ff_types.h"
#include "ff_ioman.h"
#include "ff_fatdef.h"
static FF_T_SINT8 FF_PartitionCount (FF_T_UINT8 *pBuffer)
{
FF_T_SINT8 count = 0;
FF_T_SINT8 part;
// Check PBR or MBR signature
if (FF_getChar(pBuffer, FF_FAT_MBR_SIGNATURE) != 0x55 &&
FF_getChar(pBuffer, FF_FAT_MBR_SIGNATURE) != 0xAA ) {
// No MBR, but is it a PBR ?
if (FF_getChar(pBuffer, 0) == 0xEB && // PBR Byte 0
FF_getChar(pBuffer, 2) == 0x90 && // PBR Byte 2
(FF_getChar(pBuffer, 21) & 0xF0) == 0xF0) {// PBR Byte 21 : Media byte
return 1; // No MBR but PBR exist then only one partition
}
return 0; // No MBR and no PBR then no partition found
}
for (part = 0; part < 4; part++) {
FF_T_UINT8 active = FF_getChar(pBuffer, FF_FAT_PTBL + FF_FAT_PTBL_ACTIVE + (16 * part));
FF_T_UINT8 part_id = FF_getChar(pBuffer, FF_FAT_PTBL + FF_FAT_PTBL_ID + (16 * part));
// The first sector must be a MBR, then check the partition entry in the MBR
if (active != 0x80 && (active != 0 || part_id == 0)) {
break;
}
count++;
}
return count;
}
FF_ERROR FF_FormatPartition(FF_IOMAN *pIoman, FF_T_UINT32 ulPartitionNumber, FF_T_UINT32 ulClusterSize) {
FF_BUFFER *pBuffer;
FF_T_UINT8 ucPartitionType;
FF_T_SINT8 scPartitionCount;
FF_T_UINT32 /*ulPartitionBeginLBA, ulPartitionLength,*/ ulPnum;
FF_ERROR Error = FF_ERR_NONE;
ulClusterSize = 0;
// Get Partition Metrics, and pass on to FF_Format() function
pBuffer = FF_GetBuffer(pIoman, 0, FF_MODE_READ);
{
if(!pBuffer) {
return FF_ERR_DEVICE_DRIVER_FAILED;
}
scPartitionCount = FF_PartitionCount(pBuffer->pBuffer);
ucPartitionType = FF_getChar(pBuffer->pBuffer, FF_FAT_PTBL + FF_FAT_PTBL_ID);
if(ucPartitionType == 0xEE) {
// Handle Extended Partitions
ulPnum = 0;
} else {
if(ulPartitionNumber > (FF_T_UINT32) scPartitionCount) {
FF_ReleaseBuffer(pIoman, pBuffer);
return FF_ERR_IOMAN_INVALID_PARTITION_NUM;
}
ulPnum = ulPartitionNumber;
}
}
FF_ReleaseBuffer(pIoman, pBuffer);
return Error;
}
FF_ERROR FF_Format(FF_IOMAN *pIoman, FF_T_UINT32 ulStartLBA, FF_T_UINT32 ulEndLBA, FF_T_UINT32 ulClusterSize) {
FF_T_UINT32 ulTotalSectors;
FF_T_UINT32 ulTotalClusters;
ulTotalSectors = ulEndLBA - ulStartLBA;
ulTotalClusters = ulTotalSectors / (ulClusterSize / pIoman->BlkSize);
return -1;
}

View file

@ -43,9 +43,9 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#ifdef FF_HASH_TABLE_SUPPORT #ifdef FF_HASH_CACHE
struct _FF_HASH_TABLE { struct _FF_HASH_TABLE {
FF_T_UINT8 bitTable[FF_HASH_TABLE_SIZE]; FF_T_UINT8 bitTable[FF_HASH_TABLE_SIZE];
}; };
/** /**

View file

@ -46,9 +46,10 @@
#include "ff_ioman.h" // Includes ff_types.h, ff_safety.h, <stdio.h> #include "ff_ioman.h" // Includes ff_types.h, ff_safety.h, <stdio.h>
#include "ff_fatdef.h" #include "ff_fatdef.h"
#include "ff_crc.h"
extern FF_T_UINT32 FF_FindFreeCluster (FF_IOMAN *pIoman); //extern FF_T_UINT32 FF_FindFreeCluster (FF_IOMAN *pIoman);
extern FF_T_UINT32 FF_CountFreeClusters (FF_IOMAN *pIoman); extern FF_T_UINT32 FF_CountFreeClusters (FF_IOMAN *pIoman, FF_ERROR *pError);
static void FF_IOMAN_InitBufferDescriptors(FF_IOMAN *pIoman); static void FF_IOMAN_InitBufferDescriptors(FF_IOMAN *pIoman);
@ -57,7 +58,7 @@ static void FF_IOMAN_InitBufferDescriptors(FF_IOMAN *pIoman);
* @brief Creates an FF_IOMAN object, to initialise FullFAT * @brief Creates an FF_IOMAN object, to initialise FullFAT
* *
* @param pCacheMem Pointer to a buffer for the cache. (NULL if ok to Malloc). * @param pCacheMem Pointer to a buffer for the cache. (NULL if ok to Malloc).
* @param Size The size of the provided buffer, or size of the cache to be created. * @param Size The size of the provided buffer, or size of the cache to be created. (Must be atleast 2 * BlkSize). Always a multiple of BlkSize.
* @param BlkSize The block size of devices to be attached. If in doubt use 512. * @param BlkSize The block size of devices to be attached. If in doubt use 512.
* @param pError Pointer to a signed byte for error checking. Can be NULL if not required. * @param pError Pointer to a signed byte for error checking. Can be NULL if not required.
* @param pError To be checked when a NULL pointer is returned. * @param pError To be checked when a NULL pointer is returned.
@ -77,16 +78,16 @@ FF_IOMAN *FF_CreateIOMAN(FF_T_UINT8 *pCacheMem, FF_T_UINT32 Size, FF_T_UINT16 Bl
*pError = FF_ERR_NONE; *pError = FF_ERR_NONE;
} }
if((BlkSize % 512) != 0 || Size == 0) { if((BlkSize % 512) != 0 || BlkSize == 0) {
if(pError) { if(pError) {
*pError = FF_ERR_IOMAN_BAD_BLKSIZE; *pError = FF_ERR_IOMAN_BAD_BLKSIZE | FF_CREATEIOMAN;
} }
return NULL; // BlkSize Size not a multiple of 512 > 0 return NULL; // BlkSize Size not a multiple of 512 > 0
} }
if((Size % BlkSize) != 0 || Size == 0) { if((Size % BlkSize) != 0 || Size == 0 || Size == BlkSize) { // Size must now be atleast 2 * BlkSize (or a deadlock will occur).
if(pError) { if(pError) {
*pError = FF_ERR_IOMAN_BAD_MEMSIZE; *pError = FF_ERR_IOMAN_BAD_MEMSIZE | FF_CREATEIOMAN;
} }
return NULL; // Memory Size not a multiple of BlkSize > 0 return NULL; // Memory Size not a multiple of BlkSize > 0
} }
@ -95,7 +96,7 @@ FF_IOMAN *FF_CreateIOMAN(FF_T_UINT8 *pCacheMem, FF_T_UINT32 Size, FF_T_UINT16 Bl
if(!pIoman) { // Ensure malloc() succeeded. if(!pIoman) { // Ensure malloc() succeeded.
if(pError) { if(pError) {
*pError = FF_ERR_NOT_ENOUGH_MEMORY; *pError = FF_ERR_NOT_ENOUGH_MEMORY | FF_CREATEIOMAN;
} }
return NULL; return NULL;
} }
@ -107,7 +108,7 @@ FF_IOMAN *FF_CreateIOMAN(FF_T_UINT8 *pCacheMem, FF_T_UINT32 Size, FF_T_UINT16 Bl
pIoman->pPartition = (FF_PARTITION *) FF_MALLOC(sizeof(FF_PARTITION)); pIoman->pPartition = (FF_PARTITION *) FF_MALLOC(sizeof(FF_PARTITION));
if(!pIoman->pPartition) { if(!pIoman->pPartition) {
if(pError) { if(pError) {
*pError = FF_ERR_NOT_ENOUGH_MEMORY; *pError = FF_ERR_NOT_ENOUGH_MEMORY | FF_CREATEIOMAN;
} }
FF_DestroyIOMAN(pIoman); FF_DestroyIOMAN(pIoman);
return NULL; return NULL;
@ -122,17 +123,25 @@ FF_IOMAN *FF_CreateIOMAN(FF_T_UINT8 *pCacheMem, FF_T_UINT32 Size, FF_T_UINT16 Bl
for(i = 0; i < FF_PATH_CACHE_DEPTH; i++) { for(i = 0; i < FF_PATH_CACHE_DEPTH; i++) {
pIoman->pPartition->PathCache[i].DirCluster = 0; pIoman->pPartition->PathCache[i].DirCluster = 0;
pIoman->pPartition->PathCache[i].Path[0] = '\0'; pIoman->pPartition->PathCache[i].Path[0] = '\0';
#ifdef FF_HASH_TABLE_SUPPORT /*#ifdef FF_HASH_TABLE_SUPPORT
pIoman->pPartition->PathCache[i].pHashTable = FF_CreateHashTable(); pIoman->pPartition->PathCache[i].pHashTable = FF_CreateHashTable();
pIoman->pPartition->PathCache[i].bHashed = FF_FALSE; pIoman->pPartition->PathCache[i].bHashed = FF_FALSE;
#endif*/
}
#endif #endif
#ifdef FF_HASH_CACHE
for(i = 0; i < FF_HASH_CACHE_DEPTH; i++) {
pIoman->HashCache[i].pHashTable = FF_CreateHashTable();
pIoman->HashCache[i].ulDirCluster = 0;
pIoman->HashCache[i].ulMisses = 100;
} }
#endif #endif
pIoman->pBlkDevice = (FF_BLK_DEVICE *) FF_MALLOC(sizeof(FF_BLK_DEVICE)); pIoman->pBlkDevice = (FF_BLK_DEVICE *) FF_MALLOC(sizeof(FF_BLK_DEVICE));
if(!pIoman->pBlkDevice) { // If succeeded, flag that allocation. if(!pIoman->pBlkDevice) { // If succeeded, flag that allocation.
if(pError) { if(pError) {
*pError = FF_ERR_NOT_ENOUGH_MEMORY; *pError = FF_ERR_NOT_ENOUGH_MEMORY | FF_CREATEIOMAN;
} }
FF_DestroyIOMAN(pIoman); FF_DestroyIOMAN(pIoman);
return NULL; return NULL;
@ -141,8 +150,8 @@ FF_IOMAN *FF_CreateIOMAN(FF_T_UINT8 *pCacheMem, FF_T_UINT32 Size, FF_T_UINT16 Bl
pIoman->MemAllocation |= FF_IOMAN_ALLOC_BLKDEV; pIoman->MemAllocation |= FF_IOMAN_ALLOC_BLKDEV;
// Make sure all pointers are NULL // Make sure all pointers are NULL
pIoman->pBlkDevice->fnReadBlocks = NULL; pIoman->pBlkDevice->fnpReadBlocks = NULL;
pIoman->pBlkDevice->fnWriteBlocks = NULL; pIoman->pBlkDevice->fnpWriteBlocks = NULL;
pIoman->pBlkDevice->pParam = NULL; pIoman->pBlkDevice->pParam = NULL;
// Organise the memory provided, or create our own! // Organise the memory provided, or create our own!
@ -153,7 +162,7 @@ FF_IOMAN *FF_CreateIOMAN(FF_T_UINT8 *pCacheMem, FF_T_UINT32 Size, FF_T_UINT16 Bl
pIoman->pCacheMem = (FF_T_UINT8 *) pLong; pIoman->pCacheMem = (FF_T_UINT8 *) pLong;
if(!pIoman->pCacheMem) { if(!pIoman->pCacheMem) {
if(pError) { if(pError) {
*pError = FF_ERR_NOT_ENOUGH_MEMORY; *pError = FF_ERR_NOT_ENOUGH_MEMORY | FF_CREATEIOMAN;
} }
FF_DestroyIOMAN(pIoman); FF_DestroyIOMAN(pIoman);
return NULL; return NULL;
@ -175,7 +184,7 @@ FF_IOMAN *FF_CreateIOMAN(FF_T_UINT8 *pCacheMem, FF_T_UINT32 Size, FF_T_UINT16 Bl
if(!pIoman->pBuffers) { if(!pIoman->pBuffers) {
if(pError) { if(pError) {
*pError = FF_ERR_NOT_ENOUGH_MEMORY; *pError = FF_ERR_NOT_ENOUGH_MEMORY | FF_CREATEIOMAN;
} }
FF_DestroyIOMAN(pIoman); FF_DestroyIOMAN(pIoman);
return NULL; // HT added return NULL; // HT added
@ -188,6 +197,10 @@ FF_IOMAN *FF_CreateIOMAN(FF_T_UINT8 *pCacheMem, FF_T_UINT32 Size, FF_T_UINT16 Bl
// Finally create a Semaphore for Buffer Description modifications. // Finally create a Semaphore for Buffer Description modifications.
pIoman->pSemaphore = FF_CreateSemaphore(); pIoman->pSemaphore = FF_CreateSemaphore();
#ifdef FF_BLKDEV_USES_SEM
pIoman->pBlkDevSemaphore = FF_CreateSemaphore();
#endif
return pIoman; // Sucess, return the created object. return pIoman; // Sucess, return the created object.
} }
@ -202,9 +215,13 @@ FF_IOMAN *FF_CreateIOMAN(FF_T_UINT8 *pCacheMem, FF_T_UINT32 Size, FF_T_UINT16 Bl
**/ **/
FF_ERROR FF_DestroyIOMAN(FF_IOMAN *pIoman) { FF_ERROR FF_DestroyIOMAN(FF_IOMAN *pIoman) {
#ifdef FF_HASH_CACHE
FF_T_UINT32 i;
#endif
// Ensure no NULL pointer was provided. // Ensure no NULL pointer was provided.
if(!pIoman) { if(!pIoman) {
return FF_ERR_NULL_POINTER; return FF_ERR_NULL_POINTER | FF_DESTROYIOMAN;
} }
// Ensure pPartition pointer was allocated. // Ensure pPartition pointer was allocated.
@ -231,6 +248,18 @@ FF_ERROR FF_DestroyIOMAN(FF_IOMAN *pIoman) {
if(pIoman->pSemaphore) { if(pIoman->pSemaphore) {
FF_DestroySemaphore(pIoman->pSemaphore); FF_DestroySemaphore(pIoman->pSemaphore);
} }
#ifdef FF_BLKDEV_USES_SEM
if(pIoman->pBlkDevSemaphore) {
FF_DestroySemaphore(pIoman->pBlkDevSemaphore);
}
#endif
// Destroy HashCache
#ifdef FF_HASH_CACHE
for(i = 0; i < FF_HASH_CACHE_DEPTH; i++) {
FF_DestroyHashTable(pIoman->HashCache[i].pHashTable);
}
#endif
// Finally free the FF_IOMAN object. // Finally free the FF_IOMAN object.
FF_FREE(pIoman); FF_FREE(pIoman);
@ -256,94 +285,6 @@ static void FF_IOMAN_InitBufferDescriptors(FF_IOMAN *pIoman) {
} }
} }
/**
* @private
* @brief Tests the Mode for validity.
*
* @param Mode Mode of buffer to check.
*
* @return FF_TRUE when valid, else FF_FALSE.
**/
/*static FF_T_BOOL FF_IOMAN_ModeValid(FF_T_UINT8 Mode) {
if(Mode == FF_MODE_READ || Mode == FF_MODE_WRITE) {
return FF_TRUE;
}
return FF_FALSE;
}*/
/**
* @private
* @brief Fills a buffer with the appropriate sector via the device driver.
*
* @param pIoman FF_IOMAN object.
* @param Sector LBA address of the sector to fetch.
* @param pBuffer Pointer to a byte-wise buffer to store the fetched data.
*
* HT Note: will be called while semaphore claimed (by FF_GetBuffer)
*
* @return FF_TRUE when valid, else FF_FALSE.
**/
static FF_ERROR FF_IOMAN_FillBuffer(FF_IOMAN *pIoman, FF_T_UINT32 Sector, FF_T_UINT8 *pBuffer) {
FF_T_SINT32 retVal = 0;
if(pIoman->pBlkDevice->fnReadBlocks) { // Make sure we don't execute a NULL.
do{
// Called from FF_GetBuffer with semaphore claimed
retVal = pIoman->pBlkDevice->fnReadBlocks(pBuffer, Sector, 1, pIoman->pBlkDevice->pParam);
if(retVal == FF_ERR_DRIVER_BUSY) {
FF_Sleep(FF_DRIVER_BUSY_SLEEP);
}
} while(retVal == FF_ERR_DRIVER_BUSY);
if(retVal < 0) {
return -1; // FF_ERR_DRIVER_FATAL_ERROR was returned Fail!
} else {
if(retVal == 1) {
return 0; // 1 Block was sucessfully read.
} else {
return -1; // 0 Blocks we're read, Error!
}
}
}
return -1; // error no device diver registered.
}
/**
* @private
* @brief Flushes a buffer to the device driver.
*
* @param pIoman FF_IOMAN object.
* @param Sector LBA address of the sector to fetch.
* @param pBuffer Pointer to a byte-wise buffer to store the fetched data.
*
*
* HT made it a globally accesible function to be used by new module ff_format.c
* Note that this function is called when semaphore is already locked
*
* @return FF_TRUE when valid, else FF_FALSE.
**/
/* static */ FF_ERROR FF_IOMAN_FlushBuffer(FF_IOMAN *pIoman, FF_T_UINT32 Sector, FF_T_UINT8 *pBuffer) {
FF_T_SINT32 retVal = 0;
if(pIoman->pBlkDevice->fnWriteBlocks) { // Make sure we don't execute a NULL.
do{
retVal = pIoman->pBlkDevice->fnWriteBlocks(pBuffer, Sector, 1, pIoman->pBlkDevice->pParam);
if(retVal == FF_ERR_DRIVER_BUSY) {
FF_Sleep(FF_DRIVER_BUSY_SLEEP);
}
} while(retVal == FF_ERR_DRIVER_BUSY);
if(retVal < 0) {
return -1; // FF_ERR_DRIVER_FATAL_ERROR was returned Fail!
} else {
if(retVal == 1) {
return FF_ERR_NONE; // 1 Block was sucessfully written.
} else {
return -1; // 0 Blocks we're written, Error!
}
}
}
return -1; // error no device diver registered.
}
/** /**
* @private * @private
@ -358,7 +299,7 @@ FF_ERROR FF_FlushCache(FF_IOMAN *pIoman) {
FF_T_UINT16 i,x; FF_T_UINT16 i,x;
if(!pIoman) { if(!pIoman) {
return FF_ERR_NULL_POINTER; return FF_ERR_NULL_POINTER | FF_FLUSHCACHE;
} }
FF_PendSemaphore(pIoman->pSemaphore); FF_PendSemaphore(pIoman->pSemaphore);
@ -366,7 +307,7 @@ FF_ERROR FF_FlushCache(FF_IOMAN *pIoman) {
for(i = 0; i < pIoman->CacheSize; i++) { for(i = 0; i < pIoman->CacheSize; i++) {
if((pIoman->pBuffers + i)->NumHandles == 0 && (pIoman->pBuffers + i)->Modified == FF_TRUE) { if((pIoman->pBuffers + i)->NumHandles == 0 && (pIoman->pBuffers + i)->Modified == FF_TRUE) {
FF_IOMAN_FlushBuffer(pIoman, (pIoman->pBuffers + i)->Sector, (pIoman->pBuffers + i)->pBuffer); FF_BlockWrite(pIoman, (pIoman->pBuffers + i)->Sector, 1, (pIoman->pBuffers + i)->pBuffer);
// Buffer has now been flushed, mark it as a read buffer and unmodified. // Buffer has now been flushed, mark it as a read buffer and unmodified.
(pIoman->pBuffers + i)->Mode = FF_MODE_READ; (pIoman->pBuffers + i)->Mode = FF_MODE_READ;
@ -389,13 +330,6 @@ FF_ERROR FF_FlushCache(FF_IOMAN *pIoman) {
return FF_ERR_NONE; return FF_ERR_NONE;
} }
/*static FF_T_BOOL FF_isFATSector(FF_IOMAN *pIoman, FF_T_UINT32 Sector) {
if(Sector >= pIoman->pPartition->FatBeginLBA && Sector < (pIoman->pPartition->FatBeginLBA + pIoman->pPartition->ReservedSectors)) {
return FF_TRUE;
}
return FF_FALSE;
}*/
FF_BUFFER *FF_GetBuffer(FF_IOMAN *pIoman, FF_T_UINT32 Sector, FF_T_UINT8 Mode) { FF_BUFFER *FF_GetBuffer(FF_IOMAN *pIoman, FF_T_UINT32 Sector, FF_T_UINT8 Mode) {
FF_BUFFER *pBuffer; FF_BUFFER *pBuffer;
FF_BUFFER *pBufLRU = NULL; FF_BUFFER *pBufLRU = NULL;
@ -407,35 +341,13 @@ FF_BUFFER *FF_GetBuffer(FF_IOMAN *pIoman, FF_T_UINT32 Sector, FF_T_UINT8 Mode) {
while(!pBufMatch) { while(!pBufMatch) {
FF_PendSemaphore(pIoman->pSemaphore); FF_PendSemaphore(pIoman->pSemaphore);
{ {
for(i = 0; i < pIoman->CacheSize; i++) { pBuffer = pIoman->pBuffers;
// HT if a perfect match has priority, find that first
for(i = 0; i < pIoman->CacheSize; i++, pBuffer++) {
pBuffer = (pIoman->pBuffers + i); pBuffer = (pIoman->pBuffers + i);
if(pBuffer->Sector == Sector && pBuffer->Valid == FF_TRUE) { if(pBuffer->Sector == Sector && pBuffer->Valid == FF_TRUE) {
pBufMatch = pBuffer; pBufMatch = pBuffer;
} else { break; // Why look further if you found a perfect match?
if(pBuffer->NumHandles == 0) {
pBuffer->LRU += 1;
if(!pBufLRU) {
pBufLRU = pBuffer;
}
if(!pBufLHITS) {
pBufLHITS = pBuffer;
}
if(pBuffer->LRU >= pBufLRU->LRU) {
if(pBuffer->LRU == pBufLRU->LRU) {
if(pBuffer->Persistance > pBufLRU->Persistance) {
pBufLRU = pBuffer;
}
} else {
pBufLRU = pBuffer;
}
}
if(pBuffer->Persistance < pBufLHITS->Persistance) {
pBufLHITS = pBuffer;
}
}
} }
} }
@ -468,11 +380,38 @@ FF_BUFFER *FF_GetBuffer(FF_IOMAN *pIoman, FF_T_UINT32 Sector, FF_T_UINT8 Mode) {
pBufMatch = NULL; // Sector is already in use, keep yielding until its available! pBufMatch = NULL; // Sector is already in use, keep yielding until its available!
} else { } else {
// Choose a suitable buffer! pBuffer = pIoman->pBuffers;
for(i = 0; i < pIoman->CacheSize; i++, pBuffer++) {
if(pBuffer->NumHandles == 0) {
pBuffer->LRU += 1;
if(!pBufLRU) {
pBufLRU = pBuffer;
}
if(!pBufLHITS) {
pBufLHITS = pBuffer;
}
if(pBuffer->LRU >= pBufLRU->LRU) {
if(pBuffer->LRU == pBufLRU->LRU) {
if(pBuffer->Persistance > pBufLRU->Persistance) {
pBufLRU = pBuffer;
}
} else {
pBufLRU = pBuffer;
}
}
if(pBuffer->Persistance < pBufLHITS->Persistance) {
pBufLHITS = pBuffer;
}
}
}
if(pBufLRU) { if(pBufLRU) {
// Process the suitable candidate. // Process the suitable candidate.
if(pBufLRU->Modified == FF_TRUE) { if(pBufLRU->Modified == FF_TRUE) {
FF_IOMAN_FlushBuffer(pIoman, pBufLRU->Sector, pBufLRU->pBuffer); FF_BlockWrite(pIoman, pBufLRU->Sector, 1, pBufLRU->pBuffer);
} }
pBufLRU->Mode = Mode; pBufLRU->Mode = Mode;
pBufLRU->Persistance = 1; pBufLRU->Persistance = 1;
@ -486,7 +425,7 @@ FF_BUFFER *FF_GetBuffer(FF_IOMAN *pIoman, FF_T_UINT32 Sector, FF_T_UINT8 Mode) {
pBufLRU->Modified = FF_FALSE; pBufLRU->Modified = FF_FALSE;
} }
FF_IOMAN_FillBuffer(pIoman, Sector, pBufLRU->pBuffer); FF_BlockRead(pIoman, Sector, 1, pBufLRU->pBuffer);
pBufLRU->Valid = FF_TRUE; pBufLRU->Valid = FF_TRUE;
FF_ReleaseSemaphore(pIoman->pSemaphore); FF_ReleaseSemaphore(pIoman->pSemaphore);
return pBufLRU; return pBufLRU;
@ -540,39 +479,94 @@ void FF_ReleaseBuffer(FF_IOMAN *pIoman, FF_BUFFER *pBuffer) {
**/ **/
FF_ERROR FF_RegisterBlkDevice(FF_IOMAN *pIoman, FF_T_UINT16 BlkSize, FF_WRITE_BLOCKS fnWriteBlocks, FF_READ_BLOCKS fnReadBlocks, void *pParam) { FF_ERROR FF_RegisterBlkDevice(FF_IOMAN *pIoman, FF_T_UINT16 BlkSize, FF_WRITE_BLOCKS fnWriteBlocks, FF_READ_BLOCKS fnReadBlocks, void *pParam) {
if(!pIoman) { // We can't do anything without an IOMAN object. if(!pIoman) { // We can't do anything without an IOMAN object.
return FF_ERR_NULL_POINTER; return FF_ERR_NULL_POINTER | FF_REGISTERBLKDEVICE;
} }
if((BlkSize % 512) != 0 || BlkSize == 0) { if((BlkSize % 512) != 0 || BlkSize == 0) {
return FF_ERR_IOMAN_DEV_INVALID_BLKSIZE; // BlkSize Size not a multiple of IOMAN's Expected BlockSize > 0 return FF_ERR_IOMAN_DEV_INVALID_BLKSIZE | FF_REGISTERBLKDEVICE; // BlkSize Size not a multiple of IOMAN's Expected BlockSize > 0
} }
if((BlkSize % pIoman->BlkSize) != 0 || BlkSize == 0) { if((BlkSize % pIoman->BlkSize) != 0 || BlkSize == 0) {
return FF_ERR_IOMAN_DEV_INVALID_BLKSIZE; // BlkSize Size not a multiple of IOMAN's Expected BlockSize > 0 return FF_ERR_IOMAN_DEV_INVALID_BLKSIZE | FF_REGISTERBLKDEVICE; // BlkSize Size not a multiple of IOMAN's Expected BlockSize > 0
} }
// Ensure that a device cannot be re-registered "mid-flight" // Ensure that a device cannot be re-registered "mid-flight"
// Doing so would corrupt the context of FullFAT // Doing so would corrupt the context of FullFAT
if(pIoman->pBlkDevice->fnReadBlocks) { if(pIoman->pBlkDevice->fnpReadBlocks) {
return FF_ERR_IOMAN_DEV_ALREADY_REGD; return FF_ERR_IOMAN_DEV_ALREADY_REGD | FF_REGISTERBLKDEVICE;
} }
if(pIoman->pBlkDevice->fnWriteBlocks) { if(pIoman->pBlkDevice->fnpWriteBlocks) {
return FF_ERR_IOMAN_DEV_ALREADY_REGD; return FF_ERR_IOMAN_DEV_ALREADY_REGD | FF_REGISTERBLKDEVICE;
} }
if(pIoman->pBlkDevice->pParam) { if(pIoman->pBlkDevice->pParam) {
return FF_ERR_IOMAN_DEV_ALREADY_REGD; return FF_ERR_IOMAN_DEV_ALREADY_REGD | FF_REGISTERBLKDEVICE;
} }
// Here we shall just set the values. // Here we shall just set the values.
// FullFAT checks before using any of these values. // FullFAT checks before using any of these values.
pIoman->pBlkDevice->devBlkSize = BlkSize; pIoman->pBlkDevice->devBlkSize = BlkSize;
pIoman->pBlkDevice->fnReadBlocks = fnReadBlocks; pIoman->pBlkDevice->fnpReadBlocks = fnReadBlocks;
pIoman->pBlkDevice->fnWriteBlocks = fnWriteBlocks; pIoman->pBlkDevice->fnpWriteBlocks = fnWriteBlocks;
pIoman->pBlkDevice->pParam = pParam; pIoman->pBlkDevice->pParam = pParam;
return FF_ERR_NONE; // Success return FF_ERR_NONE; // Success
} }
/*
New Interface for FullFAT to read blocks.
*/
FF_T_SINT32 FF_BlockRead(FF_IOMAN *pIoman, FF_T_UINT32 ulSectorLBA, FF_T_UINT32 ulNumSectors, void *pBuffer) {
FF_T_SINT32 slRetVal = 0;
if(pIoman->pPartition->TotalSectors) {
if((ulSectorLBA + ulNumSectors) > (pIoman->pPartition->TotalSectors + pIoman->pPartition->BeginLBA)) {
return -(FF_ERR_IOMAN_OUT_OF_BOUNDS_READ | FF_BLOCKREAD);
}
}
if(pIoman->pBlkDevice->fnpReadBlocks) { // Make sure we don't execute a NULL.
#ifdef FF_BLKDEV_USES_SEM
FF_PendSemaphore(pIoman->pBlkDevSemaphore);
#endif
slRetVal = pIoman->pBlkDevice->fnpReadBlocks(pBuffer, ulSectorLBA, ulNumSectors, pIoman->pBlkDevice->pParam);
#ifdef FF_BLKDEV_USES_SEM
FF_ReleaseSemaphore(pIoman->pBlkDevSemaphore);
#endif
if(FF_GETERROR(slRetVal) == FF_ERR_DRIVER_BUSY) {
FF_Sleep(FF_DRIVER_BUSY_SLEEP);
}
} while(FF_GETERROR(slRetVal) == FF_ERR_DRIVER_BUSY);
return slRetVal;
}
FF_T_SINT32 FF_BlockWrite(FF_IOMAN *pIoman, FF_T_UINT32 ulSectorLBA, FF_T_UINT32 ulNumSectors, void *pBuffer) {
FF_T_SINT32 slRetVal = 0;
if(pIoman->pPartition->TotalSectors) {
if((ulSectorLBA + ulNumSectors) > (pIoman->pPartition->TotalSectors + pIoman->pPartition->BeginLBA)) {
return -(FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_BLOCKWRITE);
}
}
if(pIoman->pBlkDevice->fnpWriteBlocks) { // Make sure we don't execute a NULL.
#ifdef FF_BLKDEV_USES_SEM
FF_PendSemaphore(pIoman->pBlkDevSemaphore);
#endif
slRetVal = pIoman->pBlkDevice->fnpWriteBlocks(pBuffer, ulSectorLBA, ulNumSectors, pIoman->pBlkDevice->pParam);
#ifdef FF_BLKDEV_USES_SEM
FF_ReleaseSemaphore(pIoman->pBlkDevSemaphore);
#endif
if(FF_GETERROR(slRetVal) == FF_ERR_DRIVER_BUSY) {
FF_Sleep(FF_DRIVER_BUSY_SLEEP);
}
} while(FF_GETERROR(slRetVal) == FF_ERR_DRIVER_BUSY);
return slRetVal;
}
/** /**
* @private * @private
**/ **/
@ -638,7 +632,7 @@ static FF_ERROR FF_DetermineFatType(FF_IOMAN *pIoman) {
testLong = FF_getLong(pBuffer->pBuffer, 0x0000); testLong = FF_getLong(pBuffer->pBuffer, 0x0000);
} }
FF_ReleaseBuffer(pIoman, pBuffer); FF_ReleaseBuffer(pIoman, pBuffer);
if((testLong & 0x0FFFFFF8) != 0x0FFFFFF8) { if((testLong & 0x0FFFFFF8) != 0x0FFFFFF8 && (testLong & 0x0FFFFFF8) != 0x0FFFFFF0) {
return FF_ERR_IOMAN_NOT_FAT_FORMATTED; return FF_ERR_IOMAN_NOT_FAT_FORMATTED;
} }
#endif #endif
@ -676,6 +670,91 @@ static FF_T_SINT8 FF_PartitionCount (FF_T_UINT8 *pBuffer)
return count; return count;
} }
/*
Mount GPT Partition Tables
*/
#define FF_GPT_HEAD_ENTRY_SIZE 0x54
#define FF_GPT_HEAD_TOTAL_ENTRIES 0x50
#define FF_GPT_HEAD_PART_ENTRY_LBA 0x48
#define FF_GPT_ENTRY_FIRST_SECTOR_LBA 0x20
#define FF_GPT_HEAD_CRC 0x10
#define FF_GPT_HEAD_LENGTH 0x0C
static FF_ERROR FF_GetEfiPartitionEntry(FF_IOMAN *pIoman, FF_T_UINT32 ulPartitionNumber) {
// Continuing on from FF_MountPartition() pPartition->BeginLBA should be the sector of the GPT Header
FF_BUFFER *pBuffer;
FF_PARTITION *pPart = pIoman->pPartition;
FF_T_UINT32 ulBeginGPT;
FF_T_UINT32 ulEntrySector;
FF_T_UINT32 ulSectorOffset;
FF_T_UINT32 ulTotalPartitionEntries;
FF_T_UINT32 ulPartitionEntrySize;
FF_T_UINT32 ulGPTHeadCRC, ulGPTCrcCheck, ulGPTHeadLength;
if(ulPartitionNumber >= 128) {
return FF_ERR_IOMAN_INVALID_PARTITION_NUM;
}
pBuffer = FF_GetBuffer(pIoman, pPart->BeginLBA, FF_MODE_READ);
{
if(!pBuffer) {
return FF_ERR_DEVICE_DRIVER_FAILED;
}
// Verify this is an EFI header
if(memcmp(pBuffer->pBuffer, "EFI PART", 8) != 0) {
FF_ReleaseBuffer(pIoman, pBuffer);
return FF_ERR_IOMAN_INVALID_FORMAT;
}
ulBeginGPT = FF_getLong(pBuffer->pBuffer, FF_GPT_HEAD_PART_ENTRY_LBA);
ulTotalPartitionEntries = FF_getLong(pBuffer->pBuffer, FF_GPT_HEAD_TOTAL_ENTRIES);
ulPartitionEntrySize = FF_getLong(pBuffer->pBuffer, FF_GPT_HEAD_ENTRY_SIZE);
ulGPTHeadCRC = FF_getLong(pBuffer->pBuffer, FF_GPT_HEAD_CRC);
ulGPTHeadLength = FF_getLong(pBuffer->pBuffer, FF_GPT_HEAD_LENGTH);
// Calculate Head CRC
// Blank CRC field
FF_putLong(pBuffer->pBuffer, FF_GPT_HEAD_CRC, 0x00000000);
// Calculate CRC
ulGPTCrcCheck = FF_GetCRC32(pBuffer->pBuffer, ulGPTHeadLength);
// Restore The CRC field
FF_putLong(pBuffer->pBuffer, FF_GPT_HEAD_CRC, ulGPTHeadCRC);
}
FF_ReleaseBuffer(pIoman, pBuffer);
// Check CRC
if(ulGPTHeadCRC != ulGPTCrcCheck) {
return FF_ERR_IOMAN_GPT_HEADER_CORRUPT;
}
// Calculate Sector Containing the Partition Entry we want to use.
ulEntrySector = ((ulPartitionNumber * ulPartitionEntrySize) / pIoman->BlkSize) + ulBeginGPT;
ulSectorOffset = (ulPartitionNumber % (pIoman->BlkSize / ulPartitionEntrySize)) * ulPartitionEntrySize;
pBuffer = FF_GetBuffer(pIoman, ulEntrySector, FF_MODE_READ);
{
if(!pBuffer) {
return FF_ERR_DEVICE_DRIVER_FAILED;
}
pPart->BeginLBA = FF_getLong(pBuffer->pBuffer, ulSectorOffset + FF_GPT_ENTRY_FIRST_SECTOR_LBA);
}
FF_ReleaseBuffer(pIoman, pBuffer);
if(!pPart->BeginLBA) {
return FF_ERR_IOMAN_INVALID_PARTITION_NUM;
}
return FF_ERR_NONE;
}
/** /**
* @public * @public
* @brief Mounts the Specified partition, the volume specified by the FF_IOMAN object provided. * @brief Mounts the Specified partition, the volume specified by the FF_IOMAN object provided.
@ -697,15 +776,19 @@ static FF_T_SINT8 FF_PartitionCount (FF_T_UINT8 *pBuffer)
FF_ERROR FF_MountPartition(FF_IOMAN *pIoman, FF_T_UINT8 PartitionNumber) { FF_ERROR FF_MountPartition(FF_IOMAN *pIoman, FF_T_UINT8 PartitionNumber) {
FF_PARTITION *pPart; FF_PARTITION *pPart;
FF_BUFFER *pBuffer = 0; FF_BUFFER *pBuffer = 0;
FF_ERROR Error;
FF_T_UINT8 ucPartitionType;
int partCount; int partCount;
if(!pIoman) { if(!pIoman) {
return FF_ERR_NULL_POINTER; return FF_ERR_NULL_POINTER;
} }
if(PartitionNumber > 3) { /*if(PartitionNumber > 3) {
return FF_ERR_IOMAN_INVALID_PARTITION_NUM; return FF_ERR_IOMAN_INVALID_PARTITION_NUM;
} }*/
pPart = pIoman->pPartition; pPart = pIoman->pPartition;
@ -728,10 +811,32 @@ FF_ERROR FF_MountPartition(FF_IOMAN *pIoman, FF_T_UINT8 PartitionNumber) {
// Volume is not partitioned (MBR Found) // Volume is not partitioned (MBR Found)
pPart->BeginLBA = 0; pPart->BeginLBA = 0;
} else { } else {
// Primary Partitions to deal with!
pPart->BeginLBA = FF_getLong(pBuffer->pBuffer, FF_FAT_PTBL + FF_FAT_PTBL_LBA + (16 * PartitionNumber)); ucPartitionType = FF_getChar(pBuffer->pBuffer, FF_FAT_PTBL + FF_FAT_PTBL_ID); // Ensure its not an EFI partition!
if(ucPartitionType != 0xEE) {
if(PartitionNumber > 3) {
FF_ReleaseBuffer(pIoman, pBuffer);
return FF_ERR_IOMAN_INVALID_PARTITION_NUM;
}
// Primary Partitions to deal with!
pPart->BeginLBA = FF_getLong(pBuffer->pBuffer, FF_FAT_PTBL + FF_FAT_PTBL_LBA + (16 * PartitionNumber));
}
FF_ReleaseBuffer(pIoman, pBuffer); FF_ReleaseBuffer(pIoman, pBuffer);
if(ucPartitionType == 0xEE) {
pPart->BeginLBA = FF_getLong(pBuffer->pBuffer, FF_FAT_PTBL + FF_FAT_PTBL_LBA);
Error = FF_GetEfiPartitionEntry(pIoman, PartitionNumber);
if(Error) {
return Error;
}
}
if(!pPart->BeginLBA) { if(!pPart->BeginLBA) {
return FF_ERR_IOMAN_NO_MOUNTABLE_PARTITION; return FF_ERR_IOMAN_NO_MOUNTABLE_PARTITION;
} }
@ -778,13 +883,25 @@ FF_ERROR FF_MountPartition(FF_IOMAN *pIoman, FF_T_UINT8 PartitionNumber) {
} }
FF_ReleaseBuffer(pIoman, pBuffer); // Release the buffer finally! FF_ReleaseBuffer(pIoman, pBuffer); // Release the buffer finally!
if(!pPart->BlkSize) {
return FF_ERR_IOMAN_INVALID_FORMAT;
}
pPart->RootDirSectors = ((FF_getShort(pBuffer->pBuffer, FF_FAT_ROOT_ENTRY_COUNT) * 32) + pPart->BlkSize - 1) / pPart->BlkSize; pPart->RootDirSectors = ((FF_getShort(pBuffer->pBuffer, FF_FAT_ROOT_ENTRY_COUNT) * 32) + pPart->BlkSize - 1) / pPart->BlkSize;
pPart->FirstDataSector = pPart->ClusterBeginLBA + pPart->RootDirSectors; pPart->FirstDataSector = pPart->ClusterBeginLBA + pPart->RootDirSectors;
pPart->DataSectors = pPart->TotalSectors - (pPart->ReservedSectors + (pPart->NumFATS * pPart->SectorsPerFAT) + pPart->RootDirSectors); pPart->DataSectors = pPart->TotalSectors - (pPart->ReservedSectors + (pPart->NumFATS * pPart->SectorsPerFAT) + pPart->RootDirSectors);
if(!pPart->SectorsPerCluster) {
return FF_ERR_IOMAN_INVALID_FORMAT;
}
pPart->NumClusters = pPart->DataSectors / pPart->SectorsPerCluster; pPart->NumClusters = pPart->DataSectors / pPart->SectorsPerCluster;
if(FF_DetermineFatType(pIoman)) { Error = FF_DetermineFatType(pIoman);
return FF_ERR_IOMAN_NOT_FAT_FORMATTED;
if(Error) {
return Error;
} }
#ifdef FF_MOUNT_FIND_FREE #ifdef FF_MOUNT_FIND_FREE
@ -820,8 +937,8 @@ FF_ERROR FF_UnregisterBlkDevice(FF_IOMAN *pIoman) {
{ {
if(pIoman->pPartition->PartitionMounted == FF_FALSE) { if(pIoman->pPartition->PartitionMounted == FF_FALSE) {
pIoman->pBlkDevice->devBlkSize = 0; pIoman->pBlkDevice->devBlkSize = 0;
pIoman->pBlkDevice->fnReadBlocks = NULL; pIoman->pBlkDevice->fnpReadBlocks = NULL;
pIoman->pBlkDevice->fnWriteBlocks = NULL; pIoman->pBlkDevice->fnpWriteBlocks = NULL;
pIoman->pBlkDevice->pParam = NULL; pIoman->pBlkDevice->pParam = NULL;
} else { } else {
RetVal = FF_ERR_IOMAN_PARTITION_MOUNTED; RetVal = FF_ERR_IOMAN_PARTITION_MOUNTED;
@ -876,7 +993,11 @@ FF_ERROR FF_UnmountPartition(FF_IOMAN *pIoman) {
{ {
if(!FF_ActiveHandles(pIoman)) { if(!FF_ActiveHandles(pIoman)) {
if(pIoman->FirstFile == NULL) { if(pIoman->FirstFile == NULL) {
// Release Semaphore to call this function!
FF_ReleaseSemaphore(pIoman->pSemaphore);
FF_FlushCache(pIoman); // Flush any unwritten sectors to disk. FF_FlushCache(pIoman); // Flush any unwritten sectors to disk.
// Reclaim Semaphore
FF_PendSemaphore(pIoman->pSemaphore);
pIoman->pPartition->PartitionMounted = FF_FALSE; pIoman->pPartition->PartitionMounted = FF_FALSE;
} else { } else {
RetVal = FF_ERR_IOMAN_ACTIVE_HANDLES; RetVal = FF_ERR_IOMAN_ACTIVE_HANDLES;
@ -893,12 +1014,17 @@ FF_ERROR FF_UnmountPartition(FF_IOMAN *pIoman) {
FF_ERROR FF_IncreaseFreeClusters(FF_IOMAN *pIoman, FF_T_UINT32 Count) { FF_ERROR FF_IncreaseFreeClusters(FF_IOMAN *pIoman, FF_T_UINT32 Count) {
FF_ERROR Error;
//FF_PendSemaphore(pIoman->pSemaphore); //FF_PendSemaphore(pIoman->pSemaphore);
//{ //{
if(!pIoman->pPartition->FreeClusterCount) { if(!pIoman->pPartition->FreeClusterCount) {
pIoman->pPartition->FreeClusterCount = FF_CountFreeClusters(pIoman); pIoman->pPartition->FreeClusterCount = FF_CountFreeClusters(pIoman, &Error);
if(Error) {
return Error;
}
} else {
pIoman->pPartition->FreeClusterCount += Count;
} }
pIoman->pPartition->FreeClusterCount += Count;
//} //}
//FF_ReleaseSemaphore(pIoman->pSemaphore); //FF_ReleaseSemaphore(pIoman->pSemaphore);
@ -907,12 +1033,18 @@ FF_ERROR FF_IncreaseFreeClusters(FF_IOMAN *pIoman, FF_T_UINT32 Count) {
FF_ERROR FF_DecreaseFreeClusters(FF_IOMAN *pIoman, FF_T_UINT32 Count) { FF_ERROR FF_DecreaseFreeClusters(FF_IOMAN *pIoman, FF_T_UINT32 Count) {
FF_ERROR Error;
//FF_lockFAT(pIoman); //FF_lockFAT(pIoman);
//{ //{
if(!pIoman->pPartition->FreeClusterCount) { if(!pIoman->pPartition->FreeClusterCount) {
pIoman->pPartition->FreeClusterCount = FF_CountFreeClusters(pIoman); pIoman->pPartition->FreeClusterCount = FF_CountFreeClusters(pIoman, &Error);
if(Error) {
return Error;
}
} else {
pIoman->pPartition->FreeClusterCount -= Count;
} }
pIoman->pPartition->FreeClusterCount -= Count;
//} //}
//FF_unlockFAT(pIoman); //FF_unlockFAT(pIoman);

View file

@ -42,27 +42,57 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <ctype.h>
#include "ff_string.h" #include "ff_string.h"
#include "ff_error.h"
#ifdef FF_UNICODE_SUPPORT
#include <wchar.h>
#include <wctype.h>
#endif
/* /*
* These will eventually be moved into a platform independent string * These will eventually be moved into a platform independent string
* library. Which will be optional. (To allow the use of system specific versions). * library. Which will be optional. (To allow the use of system specific versions).
*/ */
#ifdef FF_UNICODE_SUPPORT
void FF_cstrntowcs(FF_T_WCHAR *wcsDest, const FF_T_INT8 *szpSource, FF_T_UINT32 len) {
while(*szpSource && len--) {
*wcsDest++ = *szpSource++;
}
*wcsDest = '\0';
}
void FF_cstrtowcs(FF_T_WCHAR *wcsDest, const FF_T_INT8 *szpSource) {
while(*szpSource) {
*wcsDest++ = (FF_T_WCHAR) *szpSource++;
}
*wcsDest = '\0';
}
void FF_wcstocstr(FF_T_INT8 *szpDest, const FF_T_WCHAR *wcsSource) {
while(*wcsSource) {
*szpDest++ = (FF_T_INT8) *wcsSource++;
}
*szpDest = '\0';
}
void FF_wcsntocstr(FF_T_INT8 *szpDest, const FF_T_WCHAR *wcsSource, FF_T_UINT32 len) {
while(*wcsSource && len--) {
*szpDest++ = (FF_T_INT8) *wcsSource++;
}
*szpDest = '\0';
}
#endif
/** /**
* @private * @private
* @brief Converts an ASCII string to lowercase. * @brief Converts an ASCII string to lowercase.
**/ **/
void FF_tolower(FF_T_INT8 *string, FF_T_UINT32 strLen) { #ifndef FF_UNICODE_SUPPORT
FF_T_UINT32 i;
for(i = 0; i < strLen; i++) {
if(string[i] >= 'A' && string[i] <= 'Z')
string[i] += 32;
if(string[i] == '\0')
break;
}
}
/** /**
* @private * @private
* @brief Converts an ASCII string to uppercase. * @brief Converts an ASCII string to uppercase.
@ -76,6 +106,32 @@ void FF_toupper(FF_T_INT8 *string, FF_T_UINT32 strLen) {
break; break;
} }
} }
void FF_tolower(FF_T_INT8 *string, FF_T_UINT32 strLen) {
FF_T_UINT32 i;
for(i = 0; i < strLen; i++) {
if(string[i] >= 'A' && string[i] <= 'Z')
string[i] += 32;
if(string[i] == '\0')
break;
}
}
#else
void FF_toupper(FF_T_WCHAR *string, FF_T_UINT32 strLen) {
FF_T_UINT32 i;
for(i = 0; i < strLen; i++) {
string[i] = towupper(string[i]);
}
}
void FF_tolower(FF_T_WCHAR *string, FF_T_UINT32 strLen) {
FF_T_UINT32 i;
for(i = 0; i < strLen; i++) {
string[i] = towlower(string[i]);
}
}
#endif
/** /**
@ -84,6 +140,8 @@ void FF_toupper(FF_T_INT8 *string, FF_T_UINT32 strLen) {
* otherwise FF_FALSE is returned. * otherwise FF_FALSE is returned.
* *
**/ **/
#ifndef FF_UNICODE_SUPPORT
FF_T_BOOL FF_strmatch(const FF_T_INT8 *str1, const FF_T_INT8 *str2, FF_T_UINT16 len) { FF_T_BOOL FF_strmatch(const FF_T_INT8 *str1, const FF_T_INT8 *str2, FF_T_UINT16 len) {
register FF_T_UINT16 i; register FF_T_UINT16 i;
register FF_T_INT8 char1, char2; register FF_T_INT8 char1, char2;
@ -112,12 +170,38 @@ FF_T_BOOL FF_strmatch(const FF_T_INT8 *str1, const FF_T_INT8 *str2, FF_T_UINT16
return FF_TRUE; return FF_TRUE;
} }
#else
FF_T_BOOL FF_strmatch(const FF_T_WCHAR *str1, const FF_T_WCHAR *str2, FF_T_UINT16 len) {
register FF_T_UINT16 i;
register FF_T_WCHAR char1, char2;
if(!len) {
if(wcslen(str1) != wcslen(str2)) {
return FF_FALSE;
}
len = (FF_T_UINT16) wcslen(str1);
}
for(i = 0; i < len; i++) {
char1 = towlower(str1[i]);
char2 = towlower(str2[i]);
if(char1 != char2) {
return FF_FALSE;
}
}
return FF_TRUE;
}
#endif
/** /**
* @private * @private
* @brief A re-entrant Strtok function. No documentation is provided :P * @brief A re-entrant Strtok function. No documentation is provided :P
* Use at your own risk. (This is for FullFAT's use only). * Use at your own risk. (This is for FullFAT's use only).
**/ **/
#ifndef FF_UNICODE_SUPPORT
FF_T_INT8 *FF_strtok(const FF_T_INT8 *string, FF_T_INT8 *token, FF_T_UINT16 *tokenNumber, FF_T_BOOL *last, FF_T_UINT16 Length) { FF_T_INT8 *FF_strtok(const FF_T_INT8 *string, FF_T_INT8 *token, FF_T_UINT16 *tokenNumber, FF_T_BOOL *last, FF_T_UINT16 Length) {
FF_T_UINT16 strLen = Length; FF_T_UINT16 strLen = Length;
FF_T_UINT16 i,y, tokenStart, tokenEnd = 0; FF_T_UINT16 i,y, tokenStart, tokenEnd = 0;
@ -153,20 +237,80 @@ FF_T_INT8 *FF_strtok(const FF_T_INT8 *string, FF_T_INT8 *token, FF_T_UINT16 *tok
} }
tokenEnd = i; tokenEnd = i;
} }
if((tokenEnd - tokenStart) < FF_MAX_FILENAME) {
memcpy(token, (string + tokenStart), (FF_T_UINT32)(tokenEnd - tokenStart)); memcpy(token, (string + tokenStart), (FF_T_UINT32)(tokenEnd - tokenStart));
token[tokenEnd - tokenStart] = '\0'; token[tokenEnd - tokenStart] = '\0';
} else {
memcpy(token, (string + tokenStart), (FF_T_UINT32)(FF_MAX_FILENAME));
token[FF_MAX_FILENAME-1] = '\0';
}
//token[tokenEnd - tokenStart] = '\0';
*tokenNumber += 1; *tokenNumber += 1;
return token; return token;
} }
#else
FF_T_WCHAR *FF_strtok(const FF_T_WCHAR *string, FF_T_WCHAR *token, FF_T_UINT16 *tokenNumber, FF_T_BOOL *last, FF_T_UINT16 Length) {
FF_T_UINT16 strLen = Length;
FF_T_UINT16 i,y, tokenStart, tokenEnd = 0;
FF_T_BOOL FF_wildcompare(const FF_T_INT8 *pszWildCard, const FF_T_INT8 *pszString) { i = 0;
/* Check to see if the string contains the wild card */ y = 0;
if(string[i] == '\\' || string[i] == '/') {
i++;
}
tokenStart = i;
while(i < strLen) {
if(string[i] == '\\' || string[i] == '/') {
y++;
if(y == *tokenNumber) {
tokenStart = (FF_T_UINT16)(i + 1);
}
if(y == (*tokenNumber + 1)) {
tokenEnd = i;
break;
}
}
i++;
}
if(!tokenEnd) {
if(*last == FF_TRUE) {
return NULL;
} else {
*last = FF_TRUE;
}
tokenEnd = i;
}
if((tokenEnd - tokenStart) < FF_MAX_FILENAME) {
memcpy(token, (string + tokenStart), (FF_T_UINT32)(tokenEnd - tokenStart) * sizeof(FF_T_WCHAR));
token[tokenEnd - tokenStart] = '\0';
} else {
memcpy(token, (string + tokenStart), (FF_T_UINT32)(FF_MAX_FILENAME) * sizeof(FF_T_WCHAR));
token[FF_MAX_FILENAME-1] = '\0';
}
//token[tokenEnd - tokenStart] = '\0';
*tokenNumber += 1;
return token;
}
#endif
/*
A Wild-Card Comparator Library function, Provided by Adam Fullerton.
This can be extended or altered to improve or advance wildCard matching
of the FF_FindFirst() and FF_FindNext() API's.
*/
#ifdef FF_FINDAPI_ALLOW_WILDCARDS
/*FF_T_BOOL FF_wildcompare(const FF_T_INT8 *pszWildCard, const FF_T_INT8 *pszString) {
// Check to see if the string contains the wild card
if (!memchr(pszWildCard, '*', strlen(pszWildCard))) if (!memchr(pszWildCard, '*', strlen(pszWildCard)))
{ {
/* if it does not then do a straight string compare */ // if it does not then do a straight string compare
if (strcmp(pszWildCard, pszString)) if (strcmp(pszWildCard, pszString))
{ {
return FF_FALSE; return FF_FALSE;
@ -177,20 +321,20 @@ FF_T_BOOL FF_wildcompare(const FF_T_INT8 *pszWildCard, const FF_T_INT8 *pszStrin
while ((*pszWildCard) while ((*pszWildCard)
&& (*pszString)) && (*pszString))
{ {
/* Test for the wild card */ // Test for the wild card
if (*pszWildCard == '*') if (*pszWildCard == '*')
{ {
/* Eat more than one */ // Eat more than one
while (*pszWildCard == '*') while (*pszWildCard == '*')
{ {
pszWildCard++; pszWildCard++;
} }
/* If there are more chars in the string */ // If there are more chars in the string
if (*pszWildCard) if (*pszWildCard)
{ {
/* Search for the next char */ // Search for the next char
pszString = memchr(pszString, (int)*pszWildCard, strlen(pszString)); pszString = memchr(pszString, (int)*pszWildCard, strlen(pszString));
/* if it does not exist then the strings don't match */ // if it does not exist then the strings don't match
if (!pszString) if (!pszString)
{ {
return FF_FALSE; return FF_FALSE;
@ -201,7 +345,7 @@ FF_T_BOOL FF_wildcompare(const FF_T_INT8 *pszWildCard, const FF_T_INT8 *pszStrin
{ {
if (*pszWildCard) if (*pszWildCard)
{ {
/* continue */ // continue
break; break;
} }
else else
@ -212,17 +356,17 @@ FF_T_BOOL FF_wildcompare(const FF_T_INT8 *pszWildCard, const FF_T_INT8 *pszStrin
} }
else else
{ {
/* Fail if they don't match */ // Fail if they don't match
if (*pszWildCard != *pszString) if (*pszWildCard != *pszString)
{ {
return FF_FALSE; return FF_FALSE;
} }
} }
/* Bump both pointers */ // Bump both pointers
pszWildCard++; pszWildCard++;
pszString++; pszString++;
} }
/* fail if different lengths */ // fail if different lengths
if (*pszWildCard != *pszString) if (*pszWildCard != *pszString)
{ {
return FF_FALSE; return FF_FALSE;
@ -230,5 +374,83 @@ FF_T_BOOL FF_wildcompare(const FF_T_INT8 *pszWildCard, const FF_T_INT8 *pszStrin
} }
return FF_TRUE; return FF_TRUE;
} }*/
/*
This is a better Wild-card compare function, that works perfectly, and is much more efficient.
This function was contributed by one of our commercial customers.
*/
#ifdef FF_UNICODE_SUPPORT
FF_T_BOOL FF_wildcompare(const FF_T_WCHAR *pszWildCard, const FF_T_WCHAR *pszString) {
register const FF_T_WCHAR *pszWc = NULL;
register const FF_T_WCHAR *pszStr = NULL; // Encourage the string pointers to be placed in memory.
do {
if ( *pszWildCard == '*' ) {
while(*(1 + pszWildCard++) == '*'); // Eat up multiple '*''s
pszWc = (pszWildCard - 1);
pszStr = pszString;
}
if (*pszWildCard == '?' && !*pszString) {
return FF_FALSE; // False when the string is ended, yet a ? charachter is demanded.
}
#ifdef FF_WILDCARD_CASE_INSENSITIVE
if (*pszWildCard != '?' && tolower(*pszWildCard) != tolower(*pszString)) {
#else
if (*pszWildCard != '?' && *pszWildCard != *pszString) {
#endif
if (pszWc == NULL) {
return FF_FALSE;
}
pszWildCard = pszWc;
pszString = pszStr++;
}
} while ( *pszWildCard++ && *pszString++ );
while(*pszWildCard == '*') {
pszWildCard++;
}
if(!*(pszWildCard - 1)) { // WildCard is at the end. (Terminated)
return FF_TRUE; // Therefore this must be a match.
}
return FF_FALSE; // If not, then return FF_FALSE!
}
#else
FF_T_BOOL FF_wildcompare(const FF_T_INT8 *pszWildCard, const FF_T_INT8 *pszString) {
register const FF_T_INT8 *pszWc = NULL;
register const FF_T_INT8 *pszStr = NULL; // Encourage the string pointers to be placed in memory.
do {
if ( *pszWildCard == '*' ) {
while(*(1 + pszWildCard++) == '*'); // Eat up multiple '*''s
pszWc = (pszWildCard - 1);
pszStr = pszString;
}
if (*pszWildCard == '?' && !*pszString) {
return FF_FALSE; // False when the string is ended, yet a ? charachter is demanded.
}
#ifdef FF_WILDCARD_CASE_INSENSITIVE
if (*pszWildCard != '?' && tolower(*pszWildCard) != tolower(*pszString)) {
#else
if (*pszWildCard != '?' && *pszWildCard != *pszString) {
#endif
if (pszWc == NULL) {
return FF_FALSE;
}
pszWildCard = pszWc;
pszString = pszStr++;
}
} while ( *pszWildCard++ && *pszString++ );
while(*pszWildCard == '*') {
pszWildCard++;
}
if(!*(pszWildCard - 1)) { // WildCard is at the end. (Terminated)
return FF_TRUE; // Therefore this must be a match.
}
return FF_FALSE; // If not, then return FF_FALSE!
}
#endif
#endif

View file

@ -0,0 +1,294 @@
/*****************************************************************************
* FullFAT - High Performance, Thread-Safe Embedded FAT File-System *
* Copyright (C) 2009 James Walmsley (james@worm.me.uk) *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
* IMPORTANT NOTICE: *
* ================= *
* Alternative Licensing is available directly from the Copyright holder, *
* (James Walmsley). For more information consult LICENSING.TXT to obtain *
* a Commercial license. *
* *
* See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT. *
* *
* Removing the above notice is illegal and will invalidate this license. *
*****************************************************************************
* See http://worm.me.uk/fullfat for more information. *
* Or http://fullfat.googlecode.com/ for latest releases and the wiki. *
*****************************************************************************/
/**
* @file ff_unicode.c
* @author James Walmsley
* @ingroup UNICODE
*
* @defgroup UNICODE FullFAT UNICODE Library
* @brief Portable UNICODE Transformation Library for FullFAT
*
**/
#include "ff_unicode.h"
#include "string.h"
// UTF-8 Routines
/*
UCS-4 range (hex.) UTF-8 octet sequence (binary)
0000 0000-0000 007F 0xxxxxxx
0000 0080-0000 07FF 110xxxxx 10xxxxxx
0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-001F FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
0020 0000-03FF FFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx -- We don't encode these because we won't receive them. (Invalid UNICODE).
0400 0000-7FFF FFFF 1111110x 10xxxxxx ... 10xxxxxx -- We don't encode these because we won't receive them. (Invalid UNICODE).
*/
FF_T_UINT FF_GetUtf16SequenceLen(FF_T_UINT16 usLeadChar) {
if((usLeadChar & 0xFC00) == 0xD800) {
return 2;
}
return 1;
}
/*
Returns the number of UTF-8 units read.
Will not exceed ulSize UTF-16 units. (ulSize * 2 bytes).
*/
/*
UCS-4 range (hex.) UTF-8 octet sequence (binary)
0000 0000-0000 007F 0xxxxxxx
0000 0080-0000 07FF 110xxxxx 10xxxxxx
0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-001F FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
0020 0000-03FF FFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx -- We don't encode these because we won't receive them. (Invalid UNICODE).
0400 0000-7FFF FFFF 1111110x 10xxxxxx ... 10xxxxxx -- We don't encode these because we won't receive them. (Invalid UNICODE).
*/
FF_T_SINT32 FF_Utf8ctoUtf16c(FF_T_UINT16 *utf16Dest, const FF_T_UINT8 *utf8Source, FF_T_UINT32 ulSize) {
FF_T_UINT32 ulUtf32char;
FF_T_UINT16 utf16Source = 0;
register FF_T_INT uiSequenceNumber = 0;
while((*utf8Source & (0x80 >> (uiSequenceNumber)))) { // Count number of set bits before a zero.
uiSequenceNumber++;
}
if(!uiSequenceNumber) {
uiSequenceNumber++;
}
if(!ulSize) {
return FF_ERR_UNICODE_DEST_TOO_SMALL;
}
switch(uiSequenceNumber) {
case 1:
utf16Source = (FF_T_UINT16) *utf8Source;
memcpy(utf16Dest,&utf16Source,sizeof(FF_T_UINT16));
//bobtntfullfat *utf16Dest = (FF_T_UINT16) *utf8Source;
break;
case 2:
utf16Source =(FF_T_UINT16) ((*utf8Source & 0x1F) << 6) | ((*(utf8Source + 1) & 0x3F));
memcpy(utf16Dest,&utf16Source,sizeof(FF_T_UINT16));
//bobtntfullfat *utf16Dest = (FF_T_UINT16) ((*utf8Source & 0x1F) << 6) | ((*(utf8Source + 1) & 0x3F));
break;
case 3:
utf16Source =(FF_T_UINT16) ((*utf8Source & 0x0F) << 12) | ((*(utf8Source + 1) & 0x3F) << 6) | ((*(utf8Source + 2) & 0x3F));
memcpy(utf16Dest,&utf16Source,sizeof(FF_T_UINT16));
//bobtntfullfat *utf16Dest = (FF_T_UINT16) ((*utf8Source & 0x0F) << 12) | ((*(utf8Source + 1) & 0x3F) << 6) | ((*(utf8Source + 2) & 0x3F));
break;
case 4:
// Convert to UTF-32 and then into UTF-16
if(ulSize < 2) {
return FF_ERR_UNICODE_DEST_TOO_SMALL;
}
ulUtf32char = (FF_T_UINT16) ((*utf8Source & 0x0F) << 18) | ((*(utf8Source + 1) & 0x3F) << 12) | ((*(utf8Source + 2) & 0x3F) << 6) | ((*(utf8Source + 3) & 0x3F));
utf16Source = (FF_T_UINT16) (((ulUtf32char - 0x10000) & 0xFFC00) >> 10) | 0xD800;
memcpy(utf16Dest,&utf16Source,sizeof(FF_T_UINT16));
utf16Source = (FF_T_UINT16) (((ulUtf32char - 0x10000) & 0x003FF) >> 00) | 0xDC00;
memcpy(utf16Dest+1,&utf16Source,sizeof(FF_T_UINT16));
//bobtntfullfat *(utf16Dest + 0) = (FF_T_UINT16) (((ulUtf32char - 0x10000) & 0xFFC00) >> 10) | 0xD800;
//bobtntfullfat *(utf16Dest + 1) = (FF_T_UINT16) (((ulUtf32char - 0x10000) & 0x003FF) >> 00) | 0xDC00;
break;
default:
break;
}
return uiSequenceNumber;
}
/*
Returns the number of UTF-8 units required to encode the UTF-16 sequence.
Will not exceed ulSize UTF-8 units. (ulSize * 1 bytes).
*/
FF_T_SINT32 FF_Utf16ctoUtf8c(FF_T_UINT8 *utf8Dest, const FF_T_UINT16 *utf16Source, FF_T_UINT32 ulSize) {
FF_T_UINT32 ulUtf32char;
FF_T_UINT16 ulUtf16char;
if(!ulSize) {
return FF_ERR_UNICODE_DEST_TOO_SMALL;
}
memcpy(&ulUtf16char, utf16Source, sizeof(FF_T_UINT16));
if((/*bobtntfullfat *utf16Source*/ulUtf16char & 0xF800) == 0xD800) { // A surrogate sequence was encountered. Must transform to UTF32 first.
ulUtf32char = ((FF_T_UINT32) (ulUtf16char & 0x003FF) << 10) + 0x10000;
//bobtntfullfat ulUtf32char = ((FF_T_UINT32) (*(utf16Source + 0) & 0x003FF) << 10) + 0x10000;
memcpy(&ulUtf16char, utf16Source + 1, sizeof(FF_T_UINT16));
if((/*bobtntfullfat *(utf16Source + 1)*/ulUtf16char & 0xFC00) != 0xDC00) {
return FF_ERR_UNICODE_INVALID_SEQUENCE; // Invalid UTF-16 sequence.
}
ulUtf32char |= ((FF_T_UINT32) (/*bobtntfullfat *(utf16Source + 1)*/ulUtf16char & 0x003FF));
} else {
ulUtf32char = (FF_T_UINT32) /*bobtntfullfat *utf16Source*/ulUtf16char;
}
// Now convert to the UTF-8 sequence.
if(ulUtf32char < 0x00000080) { // Single byte UTF-8 sequence.
*(utf8Dest + 0) = (FF_T_UINT8) ulUtf32char;
return 1;
}
if(ulUtf32char < 0x00000800) { // Double byte UTF-8 sequence.
if(ulSize < 2) {
return FF_ERR_UNICODE_DEST_TOO_SMALL;
}
*(utf8Dest + 0) = (FF_T_UINT8) (0xC0 | ((ulUtf32char >> 6) & 0x1F));
*(utf8Dest + 1) = (FF_T_UINT8) (0x80 | ((ulUtf32char >> 0) & 0x3F));
return 2;
}
if(ulUtf32char < 0x00010000) { // Triple byte UTF-8 sequence.
if(ulSize < 3) {
return FF_ERR_UNICODE_DEST_TOO_SMALL;
}
*(utf8Dest + 0) = (FF_T_UINT8) (0xE0 | ((ulUtf32char >> 12) & 0x0F));
*(utf8Dest + 1) = (FF_T_UINT8) (0x80 | ((ulUtf32char >> 6 ) & 0x3F));
*(utf8Dest + 2) = (FF_T_UINT8) (0x80 | ((ulUtf32char >> 0 ) & 0x3F));
return 3;
}
if(ulUtf32char < 0x00200000) { // Quadruple byte UTF-8 sequence.
if(ulSize < 4) {
return FF_ERR_UNICODE_DEST_TOO_SMALL;
}
*(utf8Dest + 0) = (FF_T_UINT8) (0xF0 | ((ulUtf32char >> 18) & 0x07));
*(utf8Dest + 1) = (FF_T_UINT8) (0x80 | ((ulUtf32char >> 12) & 0x3F));
*(utf8Dest + 2) = (FF_T_UINT8) (0x80 | ((ulUtf32char >> 6 ) & 0x3F));
*(utf8Dest + 3) = (FF_T_UINT8) (0x80 | ((ulUtf32char >> 0 ) & 0x3F));
return 4;
}
return FF_ERR_UNICODE_INVALID_CODE; // Invalid Charachter
}
// UTF-16 Support Functions
// Converts a UTF-32 Charachter into its equivalent UTF-16 sequence.
FF_T_SINT32 FF_Utf32ctoUtf16c(FF_T_UINT16 *utf16Dest, FF_T_UINT32 utf32char, FF_T_UINT32 ulSize) {
// Check that its a valid UTF-32 wide-char!
if(utf32char >= 0xD800 && utf32char <= 0xDFFF) { // This range is not a valid Unicode code point.
return FF_ERR_UNICODE_INVALID_CODE; // Invalid charachter.
}
if(utf32char < 0x10000) {
*utf16Dest = (FF_T_UINT16) utf32char; // Simple conversion! Char comes within UTF-16 space (without surrogates).
return 1;
}
if(ulSize < 2) {
return FF_ERR_UNICODE_DEST_TOO_SMALL; // Not enough UTF-16 units to record this charachter.
}
if(utf32char < 0x00200000) {
// Conversion to a UTF-16 Surrogate pair!
//valueImage = utf32char - 0x10000;
*(utf16Dest + 0) = (FF_T_UINT16) (((utf32char - 0x10000) & 0xFFC00) >> 10) | 0xD800;
*(utf16Dest + 1) = (FF_T_UINT16) (((utf32char - 0x10000) & 0x003FF) >> 00) | 0xDC00;
return 2; // Surrogate pair encoded value.
}
return FF_ERR_UNICODE_INVALID_CODE; // Invalid Charachter
}
// Converts a UTF-16 sequence into its equivalent UTF-32 code point.
FF_T_SINT32 FF_Utf16ctoUtf32c(FF_T_UINT32 *utf32Dest, const FF_T_UINT16 *utf16Source) {
if((*utf16Source & 0xFC00) != 0xD800) { // Not a surrogate sequence.
*utf32Dest = (FF_T_UINT32) *utf16Source;
return 1; // A single UTF-16 item was used to represent the charachter.
}
*utf32Dest = ((FF_T_UINT32) (*(utf16Source + 0) & 0x003FF) << 10) + 0x10000;
if((*(utf16Source + 1) & 0xFC00) != 0xDC00) {
return FF_ERR_UNICODE_INVALID_SEQUENCE; // Invalid UTF-16 sequence.
}
*utf32Dest |= ((FF_T_UINT32) (*(utf16Source + 1) & 0x003FF));
return 2; // 2 utf-16 units make up the Unicode code-point.
}
/*
Returns the total number of UTF-16 items required to represent
the provided UTF-32 string in UTF-16 form.
*/
/*
FF_T_UINT FF_Utf32GetUtf16Len(const FF_T_UINT32 *utf32String) {
FF_T_UINT utf16len = 0;
while(*utf32String) {
if(*utf32String++ <= 0xFFFF) {
utf16len++;
} else {
utf16len += 2;
}
}
return utf16len;
}*/
// String conversions
FF_T_SINT32 FF_Utf32stoUtf8s(FF_T_UINT8 *Utf8String, FF_T_UINT32 *Utf32String) {
int i = 0,y = 0;
FF_T_UINT16 utf16buffer[2];
while(Utf32String[i]) {
// Convert to a UTF16 char.
FF_Utf32ctoUtf16c(utf16buffer, Utf32String[i], 2);
// Now convert the UTF16 to UTF8 sequence.
y += FF_Utf16ctoUtf8c(&Utf8String[y], utf16buffer, 4);
i++;
}
Utf8String[y] = '\0';
return 0;
}

View file

@ -1,6 +1,6 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<!DOCTYPE module SYSTEM "../../../tools/rbuild/project.dtd"> <!DOCTYPE module SYSTEM "../../../tools/rbuild/project.dtd">
<module name="fullfat" type="staticlibrary"> <module name="fullfat" type="staticlibrary" allowwarnings="true" >
<include base="ReactOS">include/reactos/libs/fullfat</include> <include base="ReactOS">include/reactos/libs/fullfat</include>
<define name="__NTDRIVER__" /> <define name="__NTDRIVER__" />
@ -10,10 +10,12 @@
<file>ff_error.c</file> <file>ff_error.c</file>
<file>ff_fat.c</file> <file>ff_fat.c</file>
<file>ff_file.c</file> <file>ff_file.c</file>
<file>ff_format.c</file>
<file>ff_hash.c</file> <file>ff_hash.c</file>
<file>ff_ioman.c</file> <file>ff_ioman.c</file>
<file>ff_memory.c</file> <file>ff_memory.c</file>
<file>ff_safety.c</file> <file>ff_safety.c</file>
<file>ff_string.c</file> <file>ff_string.c</file>
<file>ff_time.c</file> <file>ff_time.c</file>
<file>ff_unicode.c</file>
</module> </module>