diff --git a/reactos/include/reactos/libs/fullfat/ff_config.h b/reactos/include/reactos/libs/fullfat/ff_config.h index 4588ef9c305..0c8e3f37db2 100644 --- a/reactos/include/reactos/libs/fullfat/ff_config.h +++ b/reactos/include/reactos/libs/fullfat/ff_config.h @@ -34,108 +34,138 @@ Here you can change the configuration of FullFAT as appropriate to your platform. */ - //---------- ENDIANESS -#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. - // See ff_memory.c for more information. +#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. + // See ff_memory.c for more information. + //---------- LFN (Long File-name) SUPPORT -#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! +#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! -//---------- LEGAL LFNS -//#define FF_LEGAL_LFNS // Enabling this define causes FullFAT to not infringe on any of Microsoft's patents when making LFN names. - // To do this, it will only create LFNs and no shortnames. Microsofts patents are only relevent when mapping - // a shortname to a long name. This is the same way that Linux gets around the FAT legal issues: - // 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_INCLUDE_SHORT_NAME // HT addition, in 'FF_DIRENT', beside FileName, ShortName will be filled as well + // Useful for debugging, but also some situations its useful to know both. +//---------- SHORTNAMES CAN USE THE CASE BITS +#define FF_SHORTNAME_CASE // Works for XP+ e.g. short.TXT or SHORT.txt. -#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_NO_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. + // FF_FindFirst() and FF_FindNext() will also return Filenames in UTF-8 format. -#define FF_MALLOC(aSize) malloc(aSize) -#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 + // Note the 2 UNICODE options are mutually exclusive. Only one can be enabled. + // Ensure that dirents are big enough to hold the maximum UTF-8 sequence. //---------- FAT12 SUPPORT -#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, - // therefore savings can be made by not having it. +#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, + // 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 -#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: - // FF_GetFreeSize() and FF_GetVolumeSize() don't make sense when reporting sizes > 4GB. +#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: + // 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 -#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. +//---------- Driver Sleep Time +#define FF_DRIVER_BUSY_SLEEP 20 // How long FullFAT should sleep the thread for in ms, if FF_ERR_DRIVER_BUSY is recieved. -//---------- Actively Determine if partition is FAT -#define FF_FAT_CHECK // This is experimental, so if FullFAT won't mount your volume, comment this out - // Also report the problem to james@worm.me.uk + +//---------- DEBUGGING FEATURES (HELPFUL ERROR MESSAGES) +#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! #ifdef FF_LFN_SUPPORT -#define FF_MAX_FILENAME (129) +#define FF_MAX_FILENAME (260) #else -#define FF_MAX_FILENAME 13 +#define FF_MAX_FILENAME (13) #endif #ifdef FF_USE_NATIVE_STDIO #ifdef MAX_PATH #define FF_MAX_PATH MAX_PATH +#elif PATH_MAX +#define FF_MAX_PATH PATH_MAX #else #define FF_MAX_PATH 2600 #endif @@ -155,6 +185,16 @@ #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_BIG_ENDIAN #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 -#ifdef FF_HASH_TABLE_SUPPORT +#ifdef FF_HASH_CACHE #if FF_HASH_FUNCTION == CRC16 #define FF_HASH_TABLE_SIZE 8192 #elif FF_HASH_FUNCTION == CRC8 #define FF_HASH_TABLE_SIZE 32 #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 + +//---------- END-OF-CONFIGURATION diff --git a/reactos/include/reactos/libs/fullfat/ff_crc.h b/reactos/include/reactos/libs/fullfat/ff_crc.h index 7349269d836..51b658dc1f3 100644 --- a/reactos/include/reactos/libs/fullfat/ff_crc.h +++ b/reactos/include/reactos/libs/fullfat/ff_crc.h @@ -44,6 +44,7 @@ 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_UINT32 FF_GetCRC32 (FF_T_UINT8 *pbyData, FF_T_UINT32 stLength); #endif diff --git a/reactos/include/reactos/libs/fullfat/ff_dir.h b/reactos/include/reactos/libs/fullfat/ff_dir.h index 41eb7278f8d..6c99b7279c5 100644 --- a/reactos/include/reactos/libs/fullfat/ff_dir.h +++ b/reactos/include/reactos/libs/fullfat/ff_dir.h @@ -52,54 +52,118 @@ #include typedef struct { - FF_T_INT8 FileName[FF_MAX_FILENAME]; - FF_T_UINT8 Attrib; + FF_T_UINT32 ulChainLength; + 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 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 FF_SYSTEMTIME CreateTime; ///< Date and Time Created. FF_SYSTEMTIME ModifiedTime; ///< Date and Time Modified. FF_SYSTEMTIME AccessedTime; ///< Date of Last Access. #endif - //---- Book Keeping for FF_Find Functions - FF_T_UINT16 CurrentItem; - FF_T_UINT32 DirCluster; - FF_T_UINT32 CurrentCluster; - FF_T_UINT32 AddrCurrentCluster; - //FF_T_UINT8 NumLFNs; +#ifdef FF_FINDAPI_ALLOW_WILDCARDS +#ifdef FF_UNICODE_SUPPORT + FF_T_WCHAR szWildCard[FF_MAX_FILENAME]; +#else + FF_T_INT8 szWildCard[FF_MAX_FILENAME]; +#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_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); -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); -void FF_SetDirHashed(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster); +// PUBLIC API +#ifdef FF_UNICODE_SUPPORT +FF_ERROR FF_FindFirst (FF_IOMAN *pIoman, FF_DIRENT *pDirent, const FF_T_WCHAR *path); +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 diff --git a/reactos/include/reactos/libs/fullfat/ff_error.h b/reactos/include/reactos/libs/fullfat/ff_error.h index 8a48c8f1cce..c6b39dcd018 100644 --- a/reactos/include/reactos/libs/fullfat/ff_error.h +++ b/reactos/include/reactos/libs/fullfat/ff_error.h @@ -40,53 +40,111 @@ #include "ff_config.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 that all error codes remain unique, and their meaning can be quickly identified. */ // Global Error Codes -#define FF_ERR_NONE 0 ///< No Error -#define FF_ERR_NULL_POINTER -2 ///< pIoman was NULL. -#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. +#define FF_ERR_NONE 0 ///< No Error +//#define FF_ERR_GENERIC 1 ///< BAD NEVER USE THIS! +#define FF_ERR_NULL_POINTER 2 ///< pIoman was NULL. +#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 -#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_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_INVALID_FORMAT -15 ///< The -#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_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_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_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_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_INVALID_FORMAT 15 ///< The +#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_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_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 + -#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_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_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_READ_MODE -36 -#define FF_ERR_FILE_EXTEND_FAILED -37 ///< Could not extend the file. -#define FF_ERR_FILE_DESTINATION_EXISTS -38 -#define FF_ERR_FILE_SOURCE_NOT_FOUND -39 -#define FF_ERR_FILE_DIR_NOT_FOUND -40 -#define FF_ERR_FILE_COULD_NOT_CREATE_DIRENT -41 +// File Error Codes 30 + +#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_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_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_READ_MODE 36 +#define FF_ERR_FILE_EXTEND_FAILED 37 ///< Could not extend the file. +#define FF_ERR_FILE_DESTINATION_EXISTS 38 +#define FF_ERR_FILE_SOURCE_NOT_FOUND 39 +#define FF_ERR_FILE_DIR_NOT_FOUND 40 +#define FF_ERR_FILE_COULD_NOT_CREATE_DIRENT 41 -// 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_DIRECTORY_FULL -51 ///< No more items could be added to the directory. -#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_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. +// 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_DIRECTORY_FULL 51 ///< No more items could be added to the directory. +#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_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_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 + -#define FF_ERR_FAT_NO_FREE_CLUSTERS -70 ///< No more free space is available on the disk. +// Fat Error Codes 70 + +#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 const FF_T_INT8 *FF_GetErrMessage(FF_ERROR iErrorCode); diff --git a/reactos/include/reactos/libs/fullfat/ff_fat.h b/reactos/include/reactos/libs/fullfat/ff_fat.h index 8add6d0132e..0ff784590ab 100644 --- a/reactos/include/reactos/libs/fullfat/ff_fat.h +++ b/reactos/include/reactos/libs/fullfat/ff_fat.h @@ -52,24 +52,23 @@ 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_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_SINT8 FF_putFatEntry (FF_IOMAN *pIoman, FF_T_UINT32 nCluster, FF_T_UINT32 Value); - FF_T_UINT32 FF_FindFreeCluster (FF_IOMAN *pIoman); + FF_T_UINT32 FF_FindFreeCluster (FF_IOMAN *pIoman, FF_ERROR *pError); 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_T_UINT32 FF_TraverseFAT (FF_IOMAN *pIoman, FF_T_UINT32 Start, FF_T_UINT32 Count); - FF_T_UINT32 FF_CreateClusterChain (FF_IOMAN *pIoman); - FF_T_UINT32 FF_GetChainLength (FF_IOMAN *pIoman, FF_T_UINT32 pa_nStartCluster, FF_T_UINT32 *piEndOfChain); - FF_T_UINT32 FF_FindEndOfChain (FF_IOMAN *pIoman, FF_T_UINT32 Start); - FF_T_SINT8 FF_ClearCluster (FF_IOMAN *pIoman, FF_T_UINT32 nCluster); + 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_ERROR *pError); + 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_ERROR *pError); + FF_T_UINT32 FF_FindEndOfChain (FF_IOMAN *pIoman, FF_T_UINT32 Start, FF_ERROR *pError); + FF_ERROR FF_ClearCluster (FF_IOMAN *pIoman, FF_T_UINT32 nCluster); #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 - FF_T_UINT32 FF_GetFreeSize (FF_IOMAN *pIoman); + FF_T_UINT32 FF_GetFreeSize (FF_IOMAN *pIoman, FF_ERROR *pError); #endif - FF_T_UINT32 FF_FindFreeCluster (FF_IOMAN *pIoman); - FF_T_UINT32 FF_CountFreeClusters (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! void FF_lockFAT (FF_IOMAN *pIoman); void FF_unlockFAT (FF_IOMAN *pIoman); diff --git a/reactos/include/reactos/libs/fullfat/ff_fatdef.h b/reactos/include/reactos/libs/fullfat/ff_fatdef.h index 7fd7c3c5f6f..8e86d138a6d 100644 --- a/reactos/include/reactos/libs/fullfat/ff_fatdef.h +++ b/reactos/include/reactos/libs/fullfat/ff_fatdef.h @@ -86,5 +86,20 @@ #define FF_FAT_ATTR_ARCHIVE 0x20 #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 diff --git a/reactos/include/reactos/libs/fullfat/ff_file.h b/reactos/include/reactos/libs/fullfat/ff_file.h index e74d4a6a6ed..ac5528e38c7 100644 --- a/reactos/include/reactos/libs/fullfat/ff_file.h +++ b/reactos/include/reactos/libs/fullfat/ff_file.h @@ -75,19 +75,29 @@ typedef struct _FF_FILE { //---------- PROTOTYPES // 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_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_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_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_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); // Private : diff --git a/reactos/include/reactos/libs/fullfat/ff_format.h b/reactos/include/reactos/libs/fullfat/ff_format.h new file mode 100644 index 00000000000..d7c53e58a9f --- /dev/null +++ b/reactos/include/reactos/libs/fullfat/ff_format.h @@ -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 . * + * * + * 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 diff --git a/reactos/include/reactos/libs/fullfat/ff_ioman.h b/reactos/include/reactos/libs/fullfat/ff_ioman.h index d59c10593cd..92d62ebd85d 100644 --- a/reactos/include/reactos/libs/fullfat/ff_ioman.h +++ b/reactos/include/reactos/libs/fullfat/ff_ioman.h @@ -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. **/ typedef struct { - FF_WRITE_BLOCKS fnWriteBlocks; ///< 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_WRITE_BLOCKS fnpWriteBlocks; ///< Function Pointer, to write 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. void *pParam; ///< Pointer to some parameters e.g. for a Low-Level Driver Handle } FF_BLK_DEVICE; @@ -110,14 +110,23 @@ typedef struct { } FF_BUFFER; typedef struct { +#ifdef FF_UNICODE_SUPPORT + FF_T_WCHAR Path[FF_MAX_PATH]; +#else 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 + FF_T_UINT32 DirCluster; } 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 * @brief FullFAT identifies a partition with the following data. @@ -183,6 +192,9 @@ typedef struct { FF_PARTITION *pPartition; ///< Pointer to a partition description. FF_BUFFER *pBuffers; ///< Pointer to the first buffer description. 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. 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. @@ -191,6 +203,9 @@ typedef struct { FF_T_UINT8 PreventFlush; ///< Flushing to disk only allowed when 0 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). +#ifdef FF_HASH_CACHE + FF_HASHCACHE HashCache[FF_HASH_CACHE_DEPTH]; +#endif } FF_IOMAN; // Bit-Masks for Memory Allocation testing. @@ -220,6 +235,8 @@ FF_T_UINT32 FF_GetVolumeSize(FF_IOMAN *pIoman); #endif // 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_DecreaseFreeClusters (FF_IOMAN *pIoman, FF_T_UINT32 Count); FF_BUFFER *FF_GetBuffer (FF_IOMAN *pIoman, FF_T_UINT32 Sector, FF_T_UINT8 Mode); diff --git a/reactos/include/reactos/libs/fullfat/ff_memory.h b/reactos/include/reactos/libs/fullfat/ff_memory.h index 555a829210a..03ae55a77a3 100644 --- a/reactos/include/reactos/libs/fullfat/ff_memory.h +++ b/reactos/include/reactos/libs/fullfat/ff_memory.h @@ -76,7 +76,7 @@ typedef struct { #else -#error Little or Big Endian? +#error Little or Big Endian? - Please set an endianess in ff_config.h #endif diff --git a/reactos/include/reactos/libs/fullfat/ff_string.h b/reactos/include/reactos/libs/fullfat/ff_string.h index e3789102e4b..a5e85955da4 100644 --- a/reactos/include/reactos/libs/fullfat/ff_string.h +++ b/reactos/include/reactos/libs/fullfat/ff_string.h @@ -44,11 +44,37 @@ #define _FF_STRING_H_ #include "ff_types.h" +#include "ff_config.h" +#include -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); +#ifdef WIN32 +#define stricmp stricmp +#define FF_stricmp stricmp +#else +#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 diff --git a/reactos/include/reactos/libs/fullfat/ff_types.h b/reactos/include/reactos/libs/fullfat/ff_types.h index 59a599670a3..0a3d5c280f1 100644 --- a/reactos/include/reactos/libs/fullfat/ff_types.h +++ b/reactos/include/reactos/libs/fullfat/ff_types.h @@ -61,6 +61,11 @@ typedef long FF_T_INT32; ///< 32 bit default integer. typedef unsigned long FF_T_UINT32; ///< 32 bit unsigned 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 //---------------- 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. @@ -70,5 +75,9 @@ typedef signed long long FF_T_SINT64; // > 4GB in bytes if you cannot support 64 #endif typedef FF_T_SINT32 FF_ERROR; ///< A special error code type to ease some inconsistencies in Error reporting. +#ifdef FF_UNICODE_SUPPORT +#include +typedef wchar_t FF_T_WCHAR; ///< Unicode UTF-16 Charachter type, for FullFAT when UNICODE is enabled. +#endif #endif // end of include guard diff --git a/reactos/include/reactos/libs/fullfat/ff_unicode.h b/reactos/include/reactos/libs/fullfat/ff_unicode.h new file mode 100644 index 00000000000..9f0cbecb4cd --- /dev/null +++ b/reactos/include/reactos/libs/fullfat/ff_unicode.h @@ -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 . * + * * + * 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 diff --git a/reactos/include/reactos/libs/fullfat/fullfat.h b/reactos/include/reactos/libs/fullfat/fullfat.h index e4e8363e432..18aa2bb2549 100644 --- a/reactos/include/reactos/libs/fullfat/fullfat.h +++ b/reactos/include/reactos/libs/fullfat/fullfat.h @@ -45,6 +45,7 @@ extern "C" { #include "ff_crc.h" #include "ff_hash.h" #include "ff_string.h" +#include "ff_unicode.h" //#include "ff_format.h" #ifdef __cplusplus diff --git a/reactos/lib/3rdparty/fullfat/ff_crc.c b/reactos/lib/3rdparty/fullfat/ff_crc.c index 9c6ea469334..2b6f76ba5a2 100644 --- a/reactos/lib/3rdparty/fullfat/ff_crc.c +++ b/reactos/lib/3rdparty/fullfat/ff_crc.c @@ -41,7 +41,68 @@ #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, 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, }; -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, 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--) { bTableValue = (FF_T_UINT8)((wCRC & 0x00FF) ^ *pbyData++); - wCRC = (FF_T_UINT16)(((CRC16_High[bTableValue]) << 8) - + (CRC16_Low[bTableValue] ^ ((wCRC >> 8) & 0x00FF))); + wCRC = (FF_T_UINT16)(((crc16_table_high[bTableValue]) << 8) + + (crc16_table_low[bTableValue] ^ ((wCRC >> 8) & 0x00FF))); } 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, 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; while (stLength--) { byData = *pbyData++; - byCRC = byCRCLookUpTable[(byCRC ^ byData)]; + byCRC = crc8_table[(byCRC ^ byData)]; } return byCRC; } diff --git a/reactos/lib/3rdparty/fullfat/ff_dir.c b/reactos/lib/3rdparty/fullfat/ff_dir.c index f35d91c02e6..f34c18ecbab 100644 --- a/reactos/lib/3rdparty/fullfat/ff_dir.c +++ b/reactos/lib/3rdparty/fullfat/ff_dir.c @@ -42,16 +42,44 @@ #include "ff_dir.h" #include "ff_string.h" +#include "ff_unicode.h" #include + +#ifdef FF_UNICODE_SUPPORT +#include +#endif + +#ifdef WIN32 +#else +#include // tolower() +int strcasecmp(const char *s1, const char *s2) +{ + unsigned char c1,c2; + do { + c1 = *s1++; + c2 = *s2++; + c1 = (unsigned char) tolower( (unsigned char) c1); + c2 = (unsigned char) tolower( (unsigned char) c2); + } + while((c1 == c2) && (c1 != '\0')); + return (int) c1-c2; +} +#endif + + +#ifdef FF_UNICODE_SUPPORT +static void FF_ProcessShortName(FF_T_WCHAR *name); +#else static void FF_ProcessShortName(FF_T_INT8 *name); +#endif void FF_lockDIR(FF_IOMAN *pIoman) { - FF_PendSemaphore(pIoman->pSemaphore); // Use Semaphore to protect FAT modifications. + FF_PendSemaphore(pIoman->pSemaphore); // Use Semaphore to protect DIR modifications. { while((pIoman->Locks & FF_DIR_LOCK)) { FF_ReleaseSemaphore(pIoman->pSemaphore); - FF_Yield(); // Keep Releasing and Yielding until we have the Fat protector. + FF_Yield(); // Keep Releasing and Yielding until we have the DIR protector. FF_PendSemaphore(pIoman->pSemaphore); } pIoman->Locks |= FF_DIR_LOCK; @@ -77,24 +105,28 @@ static FF_T_UINT8 FF_CreateChkSum(const FF_T_UINT8 *pa_pShortName) { return ChkSum; } -FF_T_SINT8 FF_FindNextInDir(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent) { + +FF_ERROR FF_FindNextInDir(FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_FETCH_CONTEXT *pFetchContext) { - FF_T_UINT8 numLFNs; - FF_T_UINT8 EntryBuffer[32]; + FF_T_UINT8 numLFNs; + FF_T_UINT8 EntryBuffer[32]; + FF_ERROR Error; if(!pIoman) { return FF_ERR_NULL_POINTER; } - //pDirent->NumLFNs = 0; - for(; pDirent->CurrentItem < 0xFFFF; pDirent->CurrentItem += 1) { - if(FF_FetchEntry(pIoman, DirCluster, pDirent->CurrentItem, EntryBuffer)) { - return -2; + + Error = FF_FetchEntryWithContext(pIoman, pDirent->CurrentItem, pFetchContext, EntryBuffer); + + if(Error) { + return Error; } + if(EntryBuffer[0] != 0xE5) { if(FF_isEndOfDir(EntryBuffer)){ - return -2; + return FF_ERR_DIR_END_OF_DIR; } pDirent->Attrib = FF_getChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB)); if((pDirent->Attrib & FF_FAT_ATTR_LFN) == FF_FAT_ATTR_LFN) { @@ -102,8 +134,11 @@ FF_T_SINT8 FF_FindNextInDir(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_DIRENT numLFNs = (FF_T_UINT8)(EntryBuffer[0] & ~0x40); //pDirent->NumLFNs = numLFNs; #ifdef FF_LFN_SUPPORT - FF_PopulateLongDirent(pIoman, pDirent, DirCluster, pDirent->CurrentItem); - return 0; + Error = FF_PopulateLongDirent(pIoman, pDirent, pDirent->CurrentItem, pFetchContext); + if(Error) { + return Error; + } + return FF_ERR_NONE; #else pDirent->CurrentItem += (numLFNs - 1); #endif @@ -113,421 +148,307 @@ FF_T_SINT8 FF_FindNextInDir(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_DIRENT } else { FF_PopulateShortDirent(pIoman, pDirent, EntryBuffer); pDirent->CurrentItem += 1; - return 0; + return FF_ERR_NONE; } } } - return -1; + return FF_ERR_DIR_END_OF_DIR; } -/* -FF_T_BOOL FF_ShortNameExists(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *name) { - FF_DIRENT MyDir; +#ifdef FF_UNICODE_SUPPORT +static FF_T_BOOL FF_ShortNameExists(FF_IOMAN *pIoman, FF_T_UINT32 ulDirCluster, FF_T_WCHAR *szShortName, FF_ERROR *pError) { +#else +static FF_T_BOOL FF_ShortNameExists(FF_IOMAN *pIoman, FF_T_UINT32 ulDirCluster, FF_T_INT8 *szShortName, FF_ERROR *pError) { +#endif - if(FF_FindEntry(pIoman, DirCluster, name, &MyDir, FF_FALSE)) { - return FF_FALSE; - } + FF_T_UINT16 i; + FF_T_UINT8 EntryBuffer[32]; + FF_T_UINT8 Attrib; + FF_FETCH_CONTEXT FetchContext; + +#ifdef FF_UNICODE_SUPPORT + FF_T_WCHAR UTF16EntryBuffer[32]; +#endif - return FF_TRUE; -}*/ +#ifdef FF_HASH_CACHE + FF_T_UINT32 ulHash; +#endif -FF_T_BOOL FF_ShortNameExists(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *name) { + *pError = FF_ERR_NONE; - FF_T_UINT16 i; - FF_T_UINT8 EntryBuffer[32]; - FF_T_UINT8 Attrib; -#ifdef FF_HASH_TABLE_SUPPORT - - if(!FF_DirHashed(pIoman, DirCluster)) { - for(i = 0; i < 0xFFFF; i++) { - if(FF_FetchEntry(pIoman, DirCluster, i, EntryBuffer)) { - FF_SetDirHashed(pIoman, DirCluster); - break; - } - Attrib = FF_getChar(EntryBuffer, FF_FAT_DIRENT_ATTRIB); - if(FF_getChar(EntryBuffer, 0x00) != 0xE5) { - if(Attrib != FF_FAT_ATTR_LFN) { - if(FF_isEndOfDir(EntryBuffer)) { - FF_SetDirHashed(pIoman, DirCluster); - break; - } - FF_ProcessShortName((FF_T_INT8 *)EntryBuffer); - FF_AddDirentHash(pIoman, DirCluster, FF_GetCRC16((FF_T_UINT8 *) EntryBuffer, strlen(EntryBuffer))); - } - } - } - } +#ifdef FF_HASH_CACHE + if(!FF_DirHashed(pIoman, ulDirCluster)) { + // Hash the directory + FF_HashDir(pIoman, ulDirCluster); + } #if FF_HASH_FUNCTION == CRC16 - if(FF_CheckDirentHash(pIoman, DirCluster, (FF_T_UINT32)FF_GetCRC16((FF_T_UINT8 *) name, strlen(name)))) { + ulHash = (FF_T_UINT32) FF_GetCRC16((FF_T_UINT8 *) szShortName, strlen(szShortName)); #elif FF_HASH_FUNCTION == CRC8 - if(FF_CheckDirentHash(pIoman, DirCluster, (FF_T_UINT32)FF_GetCRC8((FF_T_UINT8 *) name, strlen(name)))) { + ulHash = (FF_T_UINT32) FF_GetCRC8((FF_T_UINT8 *) szShortName, strlen(szShortName)); +#endif + + if(!FF_CheckDirentHash(pIoman, ulDirCluster, ulHash)) { + return FF_FALSE; + } + +#endif + + *pError = FF_InitEntryFetch(pIoman, ulDirCluster, &FetchContext); + if(*pError) { + return FF_FALSE; + } + + for(i = 0; i < 0xFFFF; i++) { + *pError = FF_FetchEntryWithContext(pIoman, i, &FetchContext, EntryBuffer); + if(*pError) { + FF_CleanupEntryFetch(pIoman, &FetchContext); + return FF_FALSE; + } + Attrib = FF_getChar(EntryBuffer, FF_FAT_DIRENT_ATTRIB); + if(FF_getChar(EntryBuffer, 0x00) != 0xE5) { + if(Attrib != FF_FAT_ATTR_LFN) { +#ifdef FF_UNICODE_SUPPORT + // Convert Entry Buffer into UTF16 + FF_cstrntowcs(UTF16EntryBuffer, (FF_T_INT8 *) EntryBuffer, 32); + FF_ProcessShortName(UTF16EntryBuffer); #else - { + FF_ProcessShortName((FF_T_INT8 *)EntryBuffer); #endif + if(FF_isEndOfDir(EntryBuffer)) { + FF_CleanupEntryFetch(pIoman, &FetchContext); + return FF_FALSE; + } +#ifdef FF_UNICODE_SUPPORT + if(wcscmp(szShortName, UTF16EntryBuffer) == 0) { +#else + if(strcmp(szShortName, (FF_T_INT8 *)EntryBuffer) == 0) { #endif - - for(i = 0; i < 0xFFFF; i++) { - FF_FetchEntry(pIoman, DirCluster, i, EntryBuffer); - Attrib = FF_getChar(EntryBuffer, FF_FAT_DIRENT_ATTRIB); - if(FF_getChar(EntryBuffer, 0x00) != 0xE5) { - if(Attrib != FF_FAT_ATTR_LFN) { - FF_ProcessShortName((FF_T_INT8 *)EntryBuffer); - if(FF_isEndOfDir(EntryBuffer)) { - return FF_FALSE; - } - if(strcmp(name, (FF_T_INT8 *)EntryBuffer) == 0) { - return FF_TRUE; - } - } + FF_CleanupEntryFetch(pIoman, &FetchContext); + return FF_TRUE; } } -#ifdef FF_HASH_TABLE_SUPPORT } -#endif - - return FF_FALSE; + } + + FF_CleanupEntryFetch(pIoman, &FetchContext); + return FF_FALSE; } -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_UINT16 fnameLen; - FF_T_UINT16 compareLength; - FF_T_UINT16 nameLen; - FF_T_INT8 Filename[FF_MAX_FILENAME]; - FF_T_INT8 MyFname[FF_MAX_FILENAME]; - FF_T_BOOL bBreak = FF_FALSE; - - pDirent->CurrentItem = 0; - nameLen = (FF_T_UINT16) strlen(name); +#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) { +#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) { +#endif - while(!bBreak) { - if(FF_FindNextInDir(pIoman, DirCluster, pDirent)) { - break; // end of dir, file not found! - } - - if((pDirent->Attrib & pa_Attrib) == pa_Attrib){ - strcpy(Filename, pDirent->FileName); - fnameLen = (FF_T_UINT16) strlen(Filename); - FF_tolower(Filename, (FF_T_UINT32) fnameLen); - if(nameLen < FF_MAX_FILENAME) { - memcpy(MyFname, name, nameLen + 1); - } else { - memcpy(MyFname, name, FF_MAX_FILENAME); - MyFname[FF_MAX_FILENAME - 1] = '\0'; - } - FF_tolower(MyFname, (FF_T_UINT32) nameLen); - if(nameLen > fnameLen) { - compareLength = nameLen; - } else { - compareLength = fnameLen; - } - if(strncmp(MyFname, Filename, (FF_T_UINT32) compareLength) == 0) { - // Object found! - return pDirent->ObjectCluster; // Return the cluster number - } - } - } - - return 0; -} - -/* -#define FF_DIR_LFN_TRAVERSED 0x01 -#define FF_DIR_LFN_DELETED 0x02 - -FF_T_SINT8 FF_PopulateLongBufEntry(FF_IOMAN *pIoman, FF_BUFFER **ppBuffer, FF_DIRENT *pDirent) { - // Relative positions! - FF_T_UINT32 RelBlockNum; - FF_T_UINT32 RelBlockPos = FF_getMinorBlockEntry(pIoman, pDirent->CurrentItem, 32); - FF_T_UINT32 iItemLBA; - FF_T_INT8 *DirBuffer = ((*ppBuffer)->pBuffer + (RelBlockPos * 32)); - FF_T_UINT8 numLFNs = (FF_getChar(DirBuffer, (FF_T_UINT16) 0) & ~0x40); - FF_T_UINT16 x,i,y,myShort, lenlfn = 0; - FF_T_UINT32 CurrentCluster; - FF_T_SINT8 RetVal = FF_ERR_NONE; - FF_T_INT8 ShortName[13]; - FF_T_UINT8 CheckSum = FF_getChar(DirBuffer, FF_FAT_LFN_CHECKSUM); - - while(numLFNs > 0) { - - for(i = 0, y = 0; i < 5; i++, y += 2) { - pDirent->FileName[i + ((numLFNs - 1) * 13)] = DirBuffer[FF_FAT_LFN_NAME_1 + y]; - lenlfn++; - } - - for(i = 0, y = 0; i < 6; i++, y += 2) { - pDirent->FileName[i + ((numLFNs - 1) * 13) + 5] = DirBuffer[FF_FAT_LFN_NAME_2 + y]; - lenlfn++; - } - - for(i = 0, y = 0; i < 2; i++, y += 2) { - pDirent->FileName[i + ((numLFNs - 1) * 13) + 11] = DirBuffer[FF_FAT_LFN_NAME_3 + y]; - lenlfn++; - } - numLFNs--; - pDirent->CurrentItem += 1; - - CurrentCluster = FF_getClusterChainNumber(pIoman, pDirent->CurrentItem, 32); - RelBlockNum = FF_getMajorBlockNumber(pIoman, pDirent->CurrentItem, 32); - RelBlockPos = FF_getMinorBlockEntry(pIoman, pDirent->CurrentItem, 32); - iItemLBA = FF_Cluster2LBA(pIoman, pDirent->AddrCurrentCluster) + RelBlockNum; - - if(CurrentCluster > pDirent->CurrentCluster) { - pDirent->AddrCurrentCluster = FF_TraverseFAT(pIoman, pDirent->AddrCurrentCluster, 1); - pDirent->CurrentCluster += 1; - iItemLBA = FF_Cluster2LBA(pIoman, pDirent->AddrCurrentCluster) + RelBlockNum; - FF_ReleaseBuffer(pIoman, *ppBuffer); - *ppBuffer = FF_GetBuffer(pIoman, iItemLBA, FF_MODE_READ); - RetVal |= FF_DIR_LFN_TRAVERSED; - } else if(iItemLBA > ((*ppBuffer)->Sector)) { - FF_ReleaseBuffer(pIoman, *ppBuffer); - *ppBuffer = FF_GetBuffer(pIoman, iItemLBA, FF_MODE_READ); - RetVal |= FF_DIR_LFN_TRAVERSED; - } - - DirBuffer = ((*ppBuffer)->pBuffer + (RelBlockPos * 32)); - } - - if(FF_getChar(DirBuffer, (FF_T_UINT16) 0) == FF_FAT_DELETED) { - RetVal |= FF_DIR_LFN_DELETED; - return RetVal; - } - - pDirent->FileName[lenlfn] = '\0'; - - // Process the ShortName Entry - memcpy(ShortName, DirBuffer, 11); - if(CheckSum != FF_CreateChkSum(ShortName)) { - FF_ProcessShortName(ShortName); - strcpy(pDirent->FileName, ShortName); - } else { - FF_ProcessShortName(ShortName); - } - - myShort = FF_getShort(DirBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_HIGH)); - pDirent->ObjectCluster = (FF_T_UINT32) (myShort << 16); - myShort = FF_getShort(DirBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_LOW)); - pDirent->ObjectCluster |= myShort; - - // Get the filesize. - pDirent->Filesize = FF_getLong(DirBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_FILESIZE)); - // Get the attribute. - pDirent->Attrib = FF_getChar(DirBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB)); - - return RetVal; -}*/ - -/* -FF_T_SINT8 FF_FindEntry(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *Name, FF_DIRENT *pDirent, FF_T_BOOL LFNs) { - - FF_T_UINT32 iItemLBA; - FF_BUFFER *pBuffer; - FF_T_INT8 *DirBuffer; - FF_T_UINT32 fatEntry = DirCluster; - FF_T_UINT32 i,x; - FF_T_UINT32 numLFNs; - FF_T_UINT16 NameLen, DirentNameLen; - FF_T_BOOL Compare = FF_FALSE; - FF_T_SINT8 RetVal = 0; - FF_T_UINT16 RelEntry; + FF_FETCH_CONTEXT FetchContext; + FF_T_UINT8 *src; // Pointer to read from pBuffer + FF_T_UINT8 *lastSrc; +#ifdef FF_UNICODE_UTF8_SUPPORT + FF_T_SINT32 utf8Error; + FF_T_UINT8 bSurrogate = FF_FALSE; +#endif +#ifdef FF_UNICODE_SUPPORT + FF_T_WCHAR *ptr; // Pointer to store a LFN +#else + FF_T_INT8 *ptr; // Pointer to store a LFN +#endif +#ifdef FF_UNICODE_SUPPORT + FF_T_WCHAR *lastPtr = pDirent->FileName + sizeof(pDirent->FileName); +#else + FF_T_INT8 *lastPtr = pDirent->FileName + sizeof(pDirent->FileName); +#endif + FF_T_UINT8 CheckSum; + FF_T_UINT8 lastAttrib; + FF_T_INT8 totalLFNs = 0; + FF_T_INT8 numLFNs = 0; + FF_T_INT32 i; + FF_T_UINT16 lfnItem = 0; pDirent->CurrentItem = 0; - pDirent->AddrCurrentCluster = DirCluster; - pDirent->CurrentCluster = 0; - pDirent->DirCluster = DirCluster; + pDirent->Attrib = 0; - do { - - pDirent->AddrCurrentCluster = fatEntry; - iItemLBA = FF_Cluster2LBA(pIoman, pDirent->AddrCurrentCluster); + FF_InitEntryFetch(pIoman, DirCluster, &FetchContext); - for(i = 0; i < pIoman->pPartition->SectorsPerCluster; i++) { - - if(FF_getClusterChainNumber(pIoman, pDirent->CurrentItem, 32) > pDirent->CurrentCluster) { - break; - } - - pBuffer = FF_GetBuffer(pIoman, iItemLBA + i, FF_MODE_READ); - { - if(!pBuffer) { - return FF_ERR_DEVICE_DRIVER_FAILED; - } - pBuffer->Persistance = 1; - RelEntry = FF_getMinorBlockEntry(pIoman, pDirent->CurrentItem, 32); - for(x = RelEntry; x < (pIoman->BlkSize / 32); x++) { - if(FF_getMajorBlockNumber(pIoman, pDirent->CurrentItem, 32) > i) { - break; - } - if(FF_getClusterChainNumber(pIoman, pDirent->CurrentItem, 32) > pDirent->CurrentCluster) { - break; - } - RelEntry = FF_getMinorBlockEntry(pIoman, pDirent->CurrentItem, 32); - x = RelEntry; - if(x >= (pIoman->BlkSize / 32)) { - break; - } - DirBuffer = (pBuffer->pBuffer + (32 * x)); - // Process each entry and Compare to Name! - if(FF_getChar(DirBuffer, (FF_T_UINT16) 0) != FF_FAT_DELETED) { - if(DirBuffer[0] == 0x00) { - FF_ReleaseBuffer(pIoman, pBuffer); - return FF_ERR_DIR_END_OF_DIR; - } - pDirent->Attrib = FF_getChar(DirBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB)); - if((pDirent->Attrib & FF_FAT_ATTR_LFN) == FF_FAT_ATTR_LFN) { - numLFNs = (FF_T_UINT8)(DirBuffer[0] & ~0x40); - if(LFNs) { - RetVal = FF_PopulateLongBufEntry(pIoman, &pBuffer, pDirent); - if((RetVal & FF_DIR_LFN_DELETED)) { - Compare = FF_FALSE; - RetVal &= ~FF_DIR_LFN_DELETED; - } else { - Compare = FF_TRUE; - } - - pDirent->CurrentItem += 1; - } else { - pDirent->CurrentItem += numLFNs; - } - - } else { - FF_PopulateShortDirent(pDirent, DirBuffer); - Compare = FF_TRUE; - pDirent->CurrentItem += 1; - } - - if(Compare) { - // Compare the Items - NameLen = strlen(Name); - DirentNameLen = strlen(pDirent->FileName); - - if(NameLen == DirentNameLen) { // Names are same length, possible match. - if(FF_StrMatch(Name, pDirent->FileName, NameLen)) { - FF_ReleaseBuffer(pIoman, pBuffer); - return FF_ERR_NONE; // Success Item found! - } - } - Compare = FF_FALSE; - } - - if((RetVal & FF_DIR_LFN_TRAVERSED)) { - break; - } - - } else { - pDirent->CurrentItem += 1; - } - } - } - FF_ReleaseBuffer(pIoman, pBuffer); - if((RetVal & FF_DIR_LFN_TRAVERSED)) { - break; - } - } - - // Traverse! - - if((RetVal & FF_DIR_LFN_TRAVERSED)) { - RetVal = FF_ERR_NONE; - fatEntry = pDirent->AddrCurrentCluster; - } else { - if(FF_getClusterChainNumber(pIoman, pDirent->CurrentItem, 32) > pDirent->CurrentCluster) { - fatEntry = FF_getFatEntry(pIoman, pDirent->AddrCurrentCluster); - pDirent->AddrCurrentCluster = FF_TraverseFAT(pIoman, pDirent->AddrCurrentCluster, 1); - pDirent->CurrentCluster += 1; - } - } - } while(!FF_isEndOfChain(pIoman, fatEntry)); - - return FF_ERR_DIR_END_OF_DIR; -}*/ - - -/** - * @private - **/ -/*FF_T_UINT32 FF_FindEntry(FF_IOMAN *pIoman, FF_T_SINT8 *path, FF_T_UINT8 pa_Attrib, FF_DIRENT *pDirent) { - - FF_T_INT32 retVal; - FF_T_INT8 name[FF_MAX_FILENAME]; - FF_T_INT8 Filename[FF_MAX_FILENAME]; - FF_T_UINT16 fnameLen; - FF_T_UINT16 compareLength; - FF_T_UINT16 nameLen; - FF_T_UINT16 i = strlen(path); - - - while(i != 0) { - if(path[i] == '\\' || path[i] == '/') { + while(pDirent->CurrentItem < 0xFFFF) { + if (FF_FetchEntryWithContext(pIoman, pDirent->CurrentItem, &FetchContext, NULL)) { break; } - i--; - } - - if(i == 0) { - i = 1; - } - - nameLen = strlen((path + i)); - strncpy(name, (path + i), nameLen); - name[nameLen] = '\0'; - - - if(FF_FindFirst(pIoman, pDirent, path)) { - return 0; // file not found. - } - - if((pDirent->Attrib & pa_Attrib) == pa_Attrib){ - strcpy(Filename, pDirent->FileName); - fnameLen = (FF_T_UINT16) strlen(Filename); - FF_tolower(Filename, (FF_T_UINT32) fnameLen); - FF_tolower(name, (FF_T_UINT32) nameLen); - if(nameLen > fnameLen) { - compareLength = nameLen; - } else { - compareLength = fnameLen; - } - if(strncmp(name, Filename, (FF_T_UINT32) compareLength) == 0) { - // Object found!! - return pDirent->ObjectCluster; // Return the cluster number - } - } - - while(1) { - if(FF_FindNext(pIoman, pDirent)) { - return 0; // end of dir, file not found! - } - - if((pDirent->Attrib & pa_Attrib) == pa_Attrib){ - strcpy(Filename, pDirent->FileName); - fnameLen = (FF_T_UINT16) strlen(Filename); - FF_tolower(Filename, (FF_T_UINT32) fnameLen); - FF_tolower(name, (FF_T_UINT32) nameLen); - if(nameLen > fnameLen) { - compareLength = nameLen; - } else { - compareLength = fnameLen; + lastSrc = FetchContext.pBuffer->pBuffer + pIoman->BlkSize; + for (src = FetchContext.pBuffer->pBuffer; src < lastSrc; src += 32, pDirent->CurrentItem++) { + if (FF_isEndOfDir(src)) { // 0x00: end-of-dir + FF_CleanupEntryFetch(pIoman, &FetchContext); + return 0; } - if(strncmp(name, Filename, (FF_T_UINT32) compareLength) == 0) { - // Object found! - return pDirent->ObjectCluster; // Return the cluster number + if (src[0] == 0xE5) { // Entry not used + pDirent->Attrib = 0; + continue; } + lastAttrib = pDirent->Attrib; + pDirent->Attrib = FF_getChar(src, FF_FAT_DIRENT_ATTRIB); + if((pDirent->Attrib & FF_FAT_ATTR_LFN) == FF_FAT_ATTR_LFN) { + // LFN Processing +#ifdef FF_LFN_SUPPORT + if (numLFNs == 0 || (lastAttrib & FF_FAT_ATTR_LFN) != FF_FAT_ATTR_LFN) { + totalLFNs = numLFNs = (FF_T_UINT8)(src[0] & ~0x40); + lfnItem = pDirent->CurrentItem; + CheckSum = FF_getChar(src, FF_FAT_LFN_CHECKSUM); + lastPtr[-1] = '\0'; + } + if (numLFNs) { + numLFNs--; + ptr = pDirent->FileName + (numLFNs * 13); + + /* + This section needs to extract the name and do the comparison + dependent on UNICODE settings in the ff_config.h file. + */ +#ifdef FF_UNICODE_SUPPORT + // Add UTF-16 Routine here + memcpy(ptr, &src[FF_FAT_LFN_NAME_1], 10); // Copy first 5 UTF-16 chars (10 bytes). + ptr += 5; // Increment Filename pointer 5 utf16 chars. + + memcpy(ptr, &src[FF_FAT_LFN_NAME_2], 12); //Copy next 6 chars (12 bytes). + ptr += 6; + + memcpy(ptr, &src[FF_FAT_LFN_NAME_3], 4); // You're getting the idea by now! + ptr += 2; + +#endif +#ifdef FF_UNICODE_UTF8_SUPPORT + // UTF-8 Routine here + for(i = 0; i < 5 && ptr < lastPtr; i++) { + // Was there a surrogate sequence? -- Add handling here. + utf8Error = FF_Utf16ctoUtf8c((FF_T_UINT8 *) ptr, (FF_T_UINT16 *) &src[FF_FAT_LFN_NAME_1 + (2*i)], lastPtr - ptr); + if(utf8Error > 0) { + ptr += utf8Error; + + } else { + if(utf8Error == FF_ERR_UNICODE_INVALID_SEQUENCE) { + // Handle potential surrogate sequence across entries. + + } + } + } + + for(i = 0; i < 6 && ptr < lastPtr; i++) { + // Was there a surrogate sequence? -- To add handling here. + utf8Error = FF_Utf16ctoUtf8c((FF_T_UINT8 *) ptr, (FF_T_UINT16 *) &src[FF_FAT_LFN_NAME_2 + (2*i)], lastPtr - ptr); + if(utf8Error > 0) { + ptr += utf8Error; + } else { + if(utf8Error == FF_ERR_UNICODE_INVALID_SEQUENCE) { + // Handle potential surrogate sequence across entries. + } + } + } + + for(i = 0; i < 2 && ptr < lastPtr; i++) { + // Was there a surrogate sequence? -- To add handling here. + utf8Error = FF_Utf16ctoUtf8c((FF_T_UINT8 *) ptr, (FF_T_UINT16 *) &src[FF_FAT_LFN_NAME_3 + (2*i)], lastPtr - ptr); + if(utf8Error > 0) { + ptr += utf8Error; + } else { + if(utf8Error == FF_ERR_UNICODE_INVALID_SEQUENCE) { + // Handle potential surrogate sequence across entries. + } + } + } + +#endif +#ifndef FF_UNICODE_SUPPORT +#ifndef FF_UNICODE_UTF8_SUPPORT + for(i = 0; i < 10 && ptr < lastPtr; i += 2) + *(ptr++) = src[FF_FAT_LFN_NAME_1 + i]; + + for(i = 0; i < 12 && ptr < lastPtr; i += 2) + *(ptr++) = src[FF_FAT_LFN_NAME_2 + i]; + + for(i = 0; i < 4 && ptr < lastPtr; i += 2) + *(ptr++) = src[FF_FAT_LFN_NAME_3 + i]; + + if (numLFNs == totalLFNs-1 && ptr < lastPtr) + *ptr = '\0'; // Important when name len is multiple of 13 +#endif +#endif + if (numLFNs == totalLFNs-1 && ptr < lastPtr) + *ptr = '\0'; // Important when name len is multiple of 13 + + } +#endif + continue; + } + if ((pDirent->Attrib & FF_FAT_ATTR_VOLID) == FF_FAT_ATTR_VOLID) { + totalLFNs = 0; + continue; + } +#ifdef FF_LFN_SUPPORT + if(!totalLFNs || CheckSum != FF_CreateChkSum(src)) +#endif + { +#ifdef FF_UNICODE_SUPPORT + for(i = 0; i < 11; i++) { + pDirent->FileName[i] = (FF_T_WCHAR) src[i]; + } + FF_ProcessShortName(pDirent->FileName); +#else + memcpy(pDirent->FileName, src, 11); + FF_ProcessShortName(pDirent->FileName); +#endif + totalLFNs = 0; + } + + if((pDirent->Attrib & pa_Attrib) == pa_Attrib){ +#ifdef FF_UNICODE_SUPPORT + if(!wcsicmp(name, pDirent->FileName)) { +#else + if (!FF_stricmp(name, pDirent->FileName)) { +#endif + // Finally get the complete information +#ifdef FF_LFN_SUPPORT + if (totalLFNs) { + FF_PopulateLongDirent(pIoman, pDirent, lfnItem, &FetchContext); + } else +#endif + { + FF_PopulateShortDirent(pIoman, pDirent, src); + } + // Object found! + FF_CleanupEntryFetch(pIoman, &FetchContext); + return pDirent->ObjectCluster; // Return the cluster number + } + } + totalLFNs = 0; } - } + } // for (src = FetchContext.pBuffer->pBuffer; src < lastSrc; src += 32, pDirent->CurrentItem++) + + FF_CleanupEntryFetch(pIoman, &FetchContext); + return 0; -}*/ +} + + /** * @private **/ - -FF_T_UINT32 FF_FindDir(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT16 pathLen) { +#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 FF_T_UINT32 dirCluster = pIoman->pPartition->RootDirCluster; - FF_T_INT8 mytoken[FF_MAX_FILENAME]; - FF_T_INT8 *token; +#ifdef FF_UNICODE_SUPPORT + FF_T_WCHAR mytoken[FF_MAX_FILENAME]; + FF_T_WCHAR *token; +#else + FF_T_INT8 mytoken[FF_MAX_FILENAME]; + FF_T_INT8 *token; +#endif + FF_T_UINT16 it = 0; // Re-entrancy Variables for FF_strtok() FF_T_BOOL last = FF_FALSE; FF_DIRENT MyDir; @@ -535,7 +456,9 @@ FF_T_UINT32 FF_FindDir(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT16 path FF_T_UINT32 i; #endif - if(pathLen == 1) { // Must be the root dir! (/ or \) + *pError = FF_ERR_NONE; + + if(pathLen <= 1) { // Must be the root dir! (/ or \) return pIoman->pPartition->RootDirCluster; } @@ -547,8 +470,14 @@ FF_T_UINT32 FF_FindDir(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT16 path FF_PendSemaphore(pIoman->pSemaphore); // Thread safety on shared object! { for(i = 0; i < FF_PATH_CACHE_DEPTH; i++) { +#ifdef FF_UNICODE_SUPPORT + if(wcslen(pIoman->pPartition->PathCache[i].Path) == pathLen) { + if(FF_strmatch(pIoman->pPartition->PathCache[i].Path, path, pathLen)) { +#else if(strlen(pIoman->pPartition->PathCache[i].Path) == pathLen) { if(FF_strmatch(pIoman->pPartition->PathCache[i].Path, path, pathLen)) { +#endif + FF_ReleaseSemaphore(pIoman->pSemaphore); return pIoman->pPartition->PathCache[i].DirCluster; } @@ -561,9 +490,13 @@ FF_T_UINT32 FF_FindDir(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT16 path token = FF_strtok(path, mytoken, &it, &last, pathLen); do{ - //lastDirCluster = dirCluster; MyDir.CurrentItem = 0; - dirCluster = FF_FindEntryInDir(pIoman, dirCluster, token, FF_FAT_ATTR_DIR, &MyDir); + dirCluster = FF_FindEntryInDir(pIoman, dirCluster, token, FF_FAT_ATTR_DIR, &MyDir, pError); + + if(*pError) { + return 0; + } + /*if(dirCluster == 0 && MyDir.CurrentItem == 2 && MyDir.FileName[0] == '.') { // .. Dir Entry pointing to root dir. dirCluster = pIoman->pPartition->RootDirCluster; }*/ @@ -575,7 +508,11 @@ FF_T_UINT32 FF_FindDir(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT16 path FF_PendSemaphore(pIoman->pSemaphore); { if(pathLen < FF_MAX_PATH) { // Ensure the PATH won't cause a buffer overrun. +#ifdef FF_UNICODE_SUPPORT + memcpy(pIoman->pPartition->PathCache[pIoman->pPartition->PCIndex].Path, path, pathLen * sizeof(FF_T_WCHAR)); +#else memcpy(pIoman->pPartition->PathCache[pIoman->pPartition->PCIndex].Path, path, pathLen); +#endif pIoman->pPartition->PathCache[pIoman->pPartition->PCIndex].Path[pathLen] = '\0'; pIoman->pPartition->PathCache[pIoman->pPartition->PCIndex].DirCluster = dirCluster; #ifdef FF_HASH_TABLE_SUPPORT @@ -594,132 +531,81 @@ FF_T_UINT32 FF_FindDir(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT16 path return dirCluster; } -/* -FF_T_UINT32 FF_FindDir(FF_IOMAN *pIoman, FF_T_INT8 *path, FF_T_UINT16 pathLen) { - FF_T_UINT32 dirCluster = pIoman->pPartition->RootDirCluster; - FF_T_INT8 mytoken[FF_MAX_FILENAME]; - FF_T_INT8 *token; - FF_T_UINT16 it = 0; // Re-entrancy Variables for FF_strtok() - FF_T_BOOL last = FF_FALSE; - FF_DIRENT MyDir; - if(pathLen == 1) { // Must be the root dir! (/ or \) - return pIoman->pPartition->RootDirCluster; - } - - if(path[pathLen-1] == '\\' || path[pathLen-1] == '/') { - pathLen--; - } - - token = FF_strtok(path, mytoken, &it, &last, pathLen); - - do{ - //lastDirCluster = dirCluster; - MyDir.CurrentItem = 0; - if(FF_FindEntry(pIoman, dirCluster, token, &MyDir, FF_TRUE)) { - return 0; - } else { - dirCluster = MyDir.ObjectCluster; - } - if(MyDir.Attrib != FF_FAT_ATTR_DIR) { - return 0; - } - if(dirCluster == 0 && MyDir.CurrentItem == 2 && MyDir.FileName[0] == '.') { // .. Dir Entry pointing to root dir. - dirCluster = pIoman->pPartition->RootDirCluster; - } - token = FF_strtok(path, mytoken, &it, &last, pathLen); - }while(token != NULL); - - return dirCluster; -} -*/ - -#ifdef FF_LFN_SUPPORT +#if defined(FF_SHORTNAME_CASE) /** * @private - **//* -FF_T_SINT8 FF_getLFN(FF_IOMAN *pIoman, FF_BUFFER *pBuffer, FF_DIRENT *pDirent, FF_T_INT8 *filename) { - - FF_T_UINT8 numLFNs; - FF_T_UINT16 lenlfn = 0; - FF_T_UINT8 tester; - FF_T_UINT16 i,y; - FF_T_UINT32 CurrentCluster; - FF_T_UINT32 fatEntry; - FF_T_UINT8 *buffer = pBuffer->pBuffer; - FF_T_UINT32 Sector = pBuffer->Sector; - FF_T_UINT32 Entry = FF_getMinorBlockEntry(pIoman, pDirent->CurrentItem, 32); - - tester = FF_getChar(pBuffer->pBuffer, (FF_T_UINT16)(Entry * 32)); - numLFNs = (FF_T_UINT8) (tester & ~0x40); - - while(numLFNs > 0) { - if(FF_getClusterChainNumber(pIoman, pDirent->CurrentItem, 32) > pDirent->CurrentCluster) { - FF_ReleaseBuffer(pIoman, pBuffer); - fatEntry = FF_getFatEntry(pIoman, pDirent->DirCluster); - if(fatEntry == (FF_T_UINT32) FF_ERR_DEVICE_DRIVER_FAILED) { - return FF_ERR_DEVICE_DRIVER_FAILED; - } - - if(FF_isEndOfChain(pIoman, fatEntry)) { - CurrentCluster = pDirent->DirCluster; - // ERROR THIS SHOULD NOT OCCUR! - } else { - CurrentCluster = fatEntry; - } - - pBuffer = FF_GetBuffer(pIoman, FF_getRealLBA(pIoman, FF_Cluster2LBA(pIoman, CurrentCluster)), FF_MODE_READ); - if(!pBuffer) { - return FF_ERR_DEVICE_DRIVER_FAILED; - } - Entry = 0; + * For short-name entries, NT/XP etc store case information in byte 0x0c + * Use this to show proper case of "README.txt" or "source.H" + **/ +#ifdef FF_UNICODE_SUPPORT +static void FF_CaseShortName(FF_T_WCHAR *name, FF_T_UINT8 attrib) { +#else +static void FF_CaseShortName(FF_T_INT8 *name, FF_T_UINT8 attrib) { +#endif + FF_T_UINT8 testAttrib = FF_FAT_CASE_ATTR_BASE; + for (; *name; name++) { + if (*name == '.') { + testAttrib = FF_FAT_CASE_ATTR_EXT; + } else if ((attrib & testAttrib)) { + if (*name >= 'A' && *name <= 'Z') + *name += 0x20; + } else if (*name >= 'a' && *name <= 'z') { + *name -= 0x20; } - - if(Entry > 15) { - FF_ReleaseBuffer(pIoman, pBuffer); - Sector += 1; - pBuffer = FF_GetBuffer(pIoman, Sector, FF_MODE_READ); - if(!pBuffer) { - return FF_ERR_DEVICE_DRIVER_FAILED; - } - buffer = pBuffer->pBuffer; - Entry = 0; - } - - for(i = 0, y = 0; i < 5; i++, y += 2) { - filename[i + ((numLFNs - 1) * 13)] = buffer[(Entry * 32) + FF_FAT_LFN_NAME_1 + y]; - lenlfn++; - } - - for(i = 0, y = 0; i < 6; i++, y += 2) { - filename[i + ((numLFNs - 1) * 13) + 5] = buffer[(Entry * 32) + FF_FAT_LFN_NAME_2 + y]; - lenlfn++; - } - - for(i = 0, y = 0; i < 2; i++, y += 2) { - filename[i + ((numLFNs - 1) * 13) + 11] = buffer[(Entry * 32) + FF_FAT_LFN_NAME_3 + y]; - lenlfn++; - } - - numLFNs--; - - Entry++; - pDirent->CurrentItem += 1; } - - filename[lenlfn] = '\0'; - - return 0; -}*/ +} #endif /** * @private **/ + +#ifdef FF_UNICODE_SUPPORT +static void FF_ProcessShortName(FF_T_WCHAR *name) { + FF_T_WCHAR shortName[13]; + FF_T_WCHAR *ptr = name; +#else static void FF_ProcessShortName(FF_T_INT8 *name) { FF_T_INT8 shortName[13]; + FF_T_INT8 *ptr = name; +#endif FF_T_UINT8 i; +#ifdef FF_UNICODE_SUPPORT + memcpy(shortName, name, 11 * sizeof(FF_T_WCHAR)); +#else memcpy(shortName, name, 11); +#endif + + for(i = 0; i < 11; i++) { + if(shortName[i] == 0x20) { + if (i >= 8) + break; + i = 7; + } else { + if (i == 8) + *(ptr++) = '.'; + *(ptr++) = shortName[i]; + } + } + *ptr = '\0'; +} + +/* +#ifdef FF_UNICODE_SUPPORT +static void FF_ProcessShortName(FF_T_WCHAR *name) { + FF_T_WCHAR shortName[13]; +#else +static void FF_ProcessShortName(FF_T_INT8 *name) { + FF_T_INT8 shortName[13]; +#endif + + FF_T_UINT8 i; +#ifdef FF_UNICODE_SUPPORT + memcpy(shortName, name, 11 * sizeof(FF_T_WCHAR)); +#else + memcpy(shortName, name, 11); +#endif for(i = 0; i < 8; i++) { if(shortName[i] == 0x20) { @@ -745,7 +631,7 @@ static void FF_ProcessShortName(FF_T_INT8 *name) { name[i] = '\0'; } -} +}*/ #ifdef FF_TIME_SUPPORT static void FF_PlaceTime(FF_T_UINT8 *EntryBuffer, FF_T_UINT32 Offset) { @@ -790,28 +676,40 @@ static void FF_GetDate(FF_SYSTEMTIME *pTime, FF_T_UINT8 *EntryBuffer, FF_T_UINT3 pTime->Month = (((myShort & 0x01E0) >> 5) & 0x000F); pTime->Day = myShort & 0x01F; } - - - #endif void FF_PopulateShortDirent(FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_T_UINT8 *EntryBuffer) { FF_T_UINT16 myShort; - +#ifdef FF_UNICODE_SUPPORT + FF_T_WCHAR UTF16EntryBuffer[12]; + FF_cstrntowcs(UTF16EntryBuffer, (FF_T_INT8 *) EntryBuffer, 11); + memcpy(pDirent->FileName, UTF16EntryBuffer, 11 * sizeof(FF_T_WCHAR)); +#else memcpy(pDirent->FileName, EntryBuffer, 11); // Copy the filename into the Dirent object. +#endif +#if defined(FF_LFN_SUPPORT) && defined(FF_INCLUDE_SHORT_NAME) + memcpy(pDirent->ShortName, EntryBuffer, 11); + pDirent->ShortName[11] = '\0'; + FF_ProcessShortName(pDirent->ShortName); // Format the shortname, for pleasant viewing. + +#endif FF_ProcessShortName(pDirent->FileName); // Format the shortname, for pleasant viewing. #ifdef FF_HASH_TABLE_SUPPORT -#if FF_HASH_FUNCTION == CRC16 +/*#if FF_HASH_FUNCTION == CRC16 FF_AddDirentHash(pIoman, pDirent->DirCluster, (FF_T_UINT32)FF_GetCRC16((FF_T_UINT8 *) pDirent->FileName, strlen(pDirent->FileName))); #elif FF_HASH_FUNCTION == CRC8 FF_AddDirentHash(pIoman, pDirent->DirCluster, (FF_T_UINT32)FF_GetCRC8((FF_T_UINT8 *) pDirent->FileName, strlen(pDirent->FileName))); -#endif +#endif*/ #else - pIoman = NULL; + pIoman = NULL; // Silence a compiler warning, about not referencing pIoman. #endif +#ifdef FF_UNICODE_SUPPORT + FF_tolower(pDirent->FileName, (FF_T_UINT32)wcslen(pDirent->FileName)); +#else FF_tolower(pDirent->FileName, (FF_T_UINT32)strlen(pDirent->FileName)); +#endif // Get the item's Cluster address. myShort = FF_getShort(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_HIGH)); @@ -837,68 +735,167 @@ void FF_PopulateShortDirent(FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_T_UINT8 *En pDirent->Attrib = FF_getChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB)); } -FF_T_SINT8 FF_FetchEntry(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT16 nEntry, FF_T_UINT8 *buffer) { - FF_BUFFER *pBuffer; - FF_T_UINT32 itemLBA; - FF_T_UINT32 chainLength = FF_GetChainLength(pIoman, DirCluster, NULL); // BottleNeck - FF_T_UINT32 clusterNum = FF_getClusterChainNumber (pIoman, nEntry, (FF_T_UINT16)32); - FF_T_UINT32 relItem = FF_getMinorBlockEntry (pIoman, nEntry, (FF_T_UINT16)32); - FF_T_UINT32 clusterAddress = FF_TraverseFAT(pIoman, DirCluster, clusterNum); // BottleNeck +/* + Initialises a context object for FF_FetchEntryWithContext() +*/ +FF_ERROR FF_InitEntryFetch(FF_IOMAN *pIoman, FF_T_UINT32 ulDirCluster, FF_FETCH_CONTEXT *pContext) { + + FF_ERROR Error; + + memset(pContext, 0, sizeof(FF_FETCH_CONTEXT)); + + pContext->ulChainLength = FF_GetChainLength(pIoman, ulDirCluster, NULL, &Error); // Get the total length of the chain. + if(Error) { + return Error; + } + pContext->ulDirCluster = ulDirCluster; + pContext->ulCurrentClusterLCN = ulDirCluster; + pContext->ulCurrentClusterNum = 0; + pContext->ulCurrentEntry = 0; if(pIoman->pPartition->Type != FF_T_FAT32) { - if(DirCluster == pIoman->pPartition->RootDirCluster) { - chainLength = pIoman->pPartition->RootDirSectors / pIoman->pPartition->SectorsPerCluster; - if(!chainLength) { // Some media has RootDirSectors < SectorsPerCluster. This is wrong, as it should be atleast 1 cluster! - chainLength = 1; + // Handle Root Dirs that don't have cluster chains! + if(pContext->ulDirCluster == pIoman->pPartition->RootDirCluster) { + // This is a RootDIR, special consideration needs to be made, because it doesn't have a Cluster chain! + pContext->ulChainLength = pIoman->pPartition->RootDirSectors / pIoman->pPartition->SectorsPerCluster; + if(!pContext->ulChainLength) { // Some media has RootDirSectors < SectorsPerCluster. This is wrong, as it should be atleast 1 cluster! + pContext->ulChainLength = 1; } - clusterAddress = DirCluster; - clusterNum = 0; - if(nEntry > ((pIoman->pPartition->RootDirSectors * pIoman->pPartition->BlkSize) / 32)) { + } + } + + return FF_ERR_NONE; +} + +void FF_CleanupEntryFetch(FF_IOMAN *pIoman, FF_FETCH_CONTEXT *pContext) { + if(pContext->pBuffer) { + FF_ReleaseBuffer(pIoman, pContext->pBuffer); + pContext->pBuffer = NULL; + } +} + +FF_ERROR FF_FetchEntryWithContext(FF_IOMAN *pIoman, FF_T_UINT32 ulEntry, FF_FETCH_CONTEXT *pContext, FF_T_UINT8 *pEntryBuffer) { + + FF_T_UINT32 ulItemLBA; + FF_T_UINT32 ulRelItem; + FF_T_UINT32 ulClusterNum; + FF_ERROR Error; + + ulClusterNum = FF_getClusterChainNumber(pIoman, ulEntry, (FF_T_UINT16)32); + ulRelItem = FF_getMinorBlockEntry (pIoman, ulEntry, (FF_T_UINT16)32); + + if(ulClusterNum != pContext->ulCurrentClusterNum) { + // Traverse the fat gently! + if(ulClusterNum > pContext->ulCurrentClusterNum) { + pContext->ulCurrentClusterLCN = FF_TraverseFAT(pIoman, pContext->ulCurrentClusterLCN, (ulClusterNum - pContext->ulCurrentClusterNum), &Error); + if(Error) { + return Error; + } + } else { + pContext->ulCurrentClusterLCN = FF_TraverseFAT(pIoman, pContext->ulDirCluster, ulClusterNum, &Error); + if(Error) { + return Error; + } + } + pContext->ulCurrentClusterNum = ulClusterNum; + } + + if(pIoman->pPartition->Type != FF_T_FAT32) { + // Handle Root Dirs that don't have cluster chains! + if(pContext->ulDirCluster == pIoman->pPartition->RootDirCluster) { + // This is a RootDIR, special consideration needs to be made, because it doesn't have a Cluster chain! + pContext->ulCurrentClusterLCN = pContext->ulDirCluster; + ulClusterNum = 0; + if(ulEntry > ((pIoman->pPartition->RootDirSectors * pIoman->pPartition->BlkSize) / 32)) { return FF_ERR_DIR_END_OF_DIR; } } } - - if((clusterNum + 1) > chainLength) { + + if((ulClusterNum + 1) > pContext->ulChainLength) { return FF_ERR_DIR_END_OF_DIR; // End of Dir was reached! } - itemLBA = FF_Cluster2LBA(pIoman, clusterAddress) + FF_getMajorBlockNumber(pIoman, nEntry, (FF_T_UINT16)32); - itemLBA = FF_getRealLBA (pIoman, itemLBA) + FF_getMinorBlockNumber(pIoman, relItem, (FF_T_UINT16)32); - - pBuffer = FF_GetBuffer(pIoman, itemLBA, FF_MODE_READ); - { - memcpy(buffer, (pBuffer->pBuffer + (relItem*32)), 32); - pBuffer->Persistance = 1; + ulItemLBA = FF_Cluster2LBA (pIoman, pContext->ulCurrentClusterLCN) + FF_getMajorBlockNumber(pIoman, ulEntry, (FF_T_UINT16)32); + ulItemLBA = FF_getRealLBA (pIoman, ulItemLBA) + FF_getMinorBlockNumber(pIoman, ulRelItem, (FF_T_UINT16)32); + + if(!pContext->pBuffer || (pContext->pBuffer->Sector != ulItemLBA)) { + if(pContext->pBuffer) { + FF_ReleaseBuffer(pIoman, pContext->pBuffer); + } + pContext->pBuffer = FF_GetBuffer(pIoman, ulItemLBA, FF_MODE_READ); + if(!pContext->pBuffer) { + return FF_ERR_DEVICE_DRIVER_FAILED; + } } - FF_ReleaseBuffer(pIoman, pBuffer); - + + if (pEntryBuffer) { // HT Because it might be called with NULL + memcpy(pEntryBuffer, (pContext->pBuffer->pBuffer + (ulRelItem*32)), 32); + } + return FF_ERR_NONE; } -FF_T_SINT8 FF_PushEntry(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT16 nEntry, FF_T_UINT8 *buffer) { - FF_BUFFER *pBuffer; - FF_T_UINT32 itemLBA; - FF_T_UINT32 chainLength = FF_GetChainLength(pIoman, DirCluster, NULL); // BottleNeck - FF_T_UINT32 clusterNum = FF_getClusterChainNumber (pIoman, nEntry, (FF_T_UINT16)32); - FF_T_UINT32 relItem = FF_getMinorBlockEntry (pIoman, nEntry, (FF_T_UINT16)32); - FF_T_UINT32 clusterAddress = FF_TraverseFAT(pIoman, DirCluster, clusterNum); // BottleNeck - - if((clusterNum + 1) > chainLength) { +FF_ERROR FF_PushEntryWithContext(FF_IOMAN *pIoman, FF_T_UINT32 ulEntry, FF_FETCH_CONTEXT *pContext, FF_T_UINT8 *pEntryBuffer) { + FF_T_UINT32 ulItemLBA; + FF_T_UINT32 ulRelItem; + FF_T_UINT32 ulClusterNum; + FF_ERROR Error; + + ulClusterNum = FF_getClusterChainNumber(pIoman, ulEntry, (FF_T_UINT16)32); + ulRelItem = FF_getMinorBlockEntry (pIoman, ulEntry, (FF_T_UINT16)32); + + if(ulClusterNum != pContext->ulCurrentClusterNum) { + // Traverse the fat gently! + if(ulClusterNum > pContext->ulCurrentClusterNum) { + pContext->ulCurrentClusterLCN = FF_TraverseFAT(pIoman, pContext->ulCurrentClusterLCN, (ulClusterNum - pContext->ulCurrentClusterNum), &Error); + if(Error) { + return Error; + } + } else { + pContext->ulCurrentClusterLCN = FF_TraverseFAT(pIoman, pContext->ulDirCluster, ulClusterNum, &Error); + if(Error) { + return Error; + } + } + pContext->ulCurrentClusterNum = ulClusterNum; + } + + if(pIoman->pPartition->Type != FF_T_FAT32) { + // Handle Root Dirs that don't have cluster chains! + if(pContext->ulDirCluster == pIoman->pPartition->RootDirCluster) { + // This is a RootDIR, special consideration needs to be made, because it doesn't have a Cluster chain! + pContext->ulCurrentClusterLCN = pContext->ulDirCluster; + ulClusterNum = 0; + if(ulEntry > ((pIoman->pPartition->RootDirSectors * pIoman->pPartition->BlkSize) / 32)) { + return FF_ERR_DIR_END_OF_DIR; + } + } + } + + if((ulClusterNum + 1) > pContext->ulChainLength) { return FF_ERR_DIR_END_OF_DIR; // End of Dir was reached! } - itemLBA = FF_Cluster2LBA(pIoman, clusterAddress) + FF_getMajorBlockNumber(pIoman, nEntry, (FF_T_UINT16)32); - itemLBA = FF_getRealLBA (pIoman, itemLBA) + FF_getMinorBlockNumber(pIoman, relItem, (FF_T_UINT16)32); - - pBuffer = FF_GetBuffer(pIoman, itemLBA, FF_MODE_WRITE); - { - memcpy((pBuffer->pBuffer + (relItem*32)), buffer, 32); + ulItemLBA = FF_Cluster2LBA (pIoman, pContext->ulCurrentClusterLCN) + FF_getMajorBlockNumber(pIoman, ulEntry, (FF_T_UINT16)32); + ulItemLBA = FF_getRealLBA (pIoman, ulItemLBA) + FF_getMinorBlockNumber(pIoman, ulRelItem, (FF_T_UINT16)32); + + if(!pContext->pBuffer || (pContext->pBuffer->Sector != ulItemLBA)) { + if(pContext->pBuffer) { + FF_ReleaseBuffer(pIoman, pContext->pBuffer); + } + pContext->pBuffer = FF_GetBuffer(pIoman, ulItemLBA, FF_MODE_READ); + if(!pContext->pBuffer) { + return FF_ERR_DEVICE_DRIVER_FAILED; + } } - FF_ReleaseBuffer(pIoman, pBuffer); - - return 0; + + memcpy((pContext->pBuffer->pBuffer + (ulRelItem*32)), pEntryBuffer, 32); + pContext->pBuffer->Mode = FF_MODE_WRITE; + pContext->pBuffer->Modified = FF_TRUE; + + return FF_ERR_NONE; } @@ -906,14 +903,24 @@ FF_T_SINT8 FF_PushEntry(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT16 nE * @private **/ FF_ERROR FF_GetEntry(FF_IOMAN *pIoman, FF_T_UINT16 nEntry, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent) { - FF_T_UINT8 EntryBuffer[32]; - FF_T_UINT8 numLFNs; + FF_T_UINT8 EntryBuffer[32]; + FF_T_UINT8 numLFNs; + FF_FETCH_CONTEXT FetchContext; + FF_ERROR Error; + + Error = FF_InitEntryFetch(pIoman, DirCluster, &FetchContext); + if(Error) { + return Error; + } - if(FF_FetchEntry(pIoman, DirCluster, nEntry, EntryBuffer)) { - return FF_ERR_DIR_END_OF_DIR; + Error = FF_FetchEntryWithContext(pIoman, nEntry, &FetchContext, EntryBuffer); + if(Error) { + FF_CleanupEntryFetch(pIoman, &FetchContext); + return Error; } if(EntryBuffer[0] != 0xE5) { if(FF_isEndOfDir(EntryBuffer)){ + FF_CleanupEntryFetch(pIoman, &FetchContext); return FF_ERR_DIR_END_OF_DIR; } @@ -923,8 +930,12 @@ FF_ERROR FF_GetEntry(FF_IOMAN *pIoman, FF_T_UINT16 nEntry, FF_T_UINT32 DirCluste // LFN Processing numLFNs = (FF_T_UINT8)(EntryBuffer[0] & ~0x40); #ifdef FF_LFN_SUPPORT - FF_PopulateLongDirent(pIoman, pDirent, DirCluster, nEntry); - return 0; + Error = FF_PopulateLongDirent(pIoman, pDirent, nEntry, &FetchContext); + FF_CleanupEntryFetch(pIoman, &FetchContext); + if(Error) { + return Error; + } + return FF_ERR_NONE; #else pDirent->CurrentItem += (numLFNs - 1); #endif @@ -934,9 +945,12 @@ FF_ERROR FF_GetEntry(FF_IOMAN *pIoman, FF_T_UINT16 nEntry, FF_T_UINT32 DirCluste } else { FF_PopulateShortDirent(pIoman, pDirent, EntryBuffer); pDirent->CurrentItem += 1; + FF_CleanupEntryFetch(pIoman, &FetchContext); return 0; } } + + FF_CleanupEntryFetch(pIoman, &FetchContext); return FF_ERR_NONE; } @@ -947,55 +961,123 @@ FF_T_BOOL FF_isEndOfDir(FF_T_UINT8 *EntryBuffer) { return FF_FALSE; } -#ifdef FF_HASH_TABLE_SUPPORT -FF_ERROR FF_AddDirentHash(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT32 nHash) { +#ifdef FF_HASH_CACHE +FF_ERROR FF_AddDirentHash(FF_IOMAN *pIoman, FF_T_UINT32 ulDirCluster, FF_T_UINT32 ulHash) { FF_T_UINT32 i; FF_HASH_TABLE pHash = NULL; - for(i = 0; i < FF_PATH_CACHE_DEPTH; i++) { - if(pIoman->pPartition->PathCache[i].DirCluster == DirCluster) { - pHash = pIoman->pPartition->PathCache[i].pHashTable; + for(i = 0; i < FF_HASH_CACHE_DEPTH; i++) { + if(pIoman->HashCache[i].ulDirCluster == ulDirCluster) { + pHash = pIoman->HashCache[i].pHashTable; break; } } if(pHash) { - FF_SetHash(pHash, nHash); + FF_SetHash(pHash, ulHash); } return FF_ERR_NONE; } -FF_T_BOOL FF_CheckDirentHash(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT32 nHash) { +FF_T_BOOL FF_CheckDirentHash(FF_IOMAN *pIoman, FF_T_UINT32 ulDirCluster, FF_T_UINT32 ulHash) { FF_T_UINT32 i; FF_HASH_TABLE pHash = NULL; - for(i = 0; i < FF_PATH_CACHE_DEPTH; i++) { - if(pIoman->pPartition->PathCache[i].DirCluster == DirCluster) { - pHash = pIoman->pPartition->PathCache[i].pHashTable; + for(i = 0; i < FF_HASH_CACHE_DEPTH; i++) { + if(pIoman->HashCache[i].ulDirCluster == ulDirCluster) { + pHash = pIoman->HashCache[i].pHashTable; break; } } if(pHash) { - return FF_isHashSet(pHash, nHash); + return FF_isHashSet(pHash, ulHash); } return FF_FALSE; } -FF_T_BOOL FF_DirHashed(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster) { +FF_T_BOOL FF_DirHashed(FF_IOMAN *pIoman, FF_T_UINT32 ulDirCluster) { FF_T_UINT32 i; - for(i = 0; i < FF_PATH_CACHE_DEPTH; i++) { - if(pIoman->pPartition->PathCache[i].DirCluster == DirCluster) { - if(pIoman->pPartition->PathCache[i].bHashed) { - return FF_TRUE; - } + for(i = 0; i < FF_HASH_CACHE_DEPTH; i++) { + if(pIoman->HashCache[i].ulDirCluster == ulDirCluster) { + return FF_TRUE; } } return FF_FALSE; } -void FF_SetDirHashed(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster) { +FF_ERROR FF_HashDir(FF_IOMAN *pIoman, FF_T_UINT32 ulDirCluster) { + // Find most suitable Hash Table to replace! + FF_T_UINT32 i; + FF_HASHCACHE *pHashCache = NULL; + FF_FETCH_CONTEXT FetchContext; + FF_T_UINT8 EntryBuffer[32], ucAttrib; + FF_T_UINT32 ulHash; + + if(FF_DirHashed(pIoman, ulDirCluster)) { + return FF_ERR_NONE; // Don't wastefully re-hash a dir! + } + + //printf("----- Hashing Directory\n"); + + for(i = 0; i < FF_HASH_CACHE_DEPTH; i++) { + if(!pIoman->HashCache[i].ulNumHandles) { + if(!pHashCache) { + pHashCache = &pIoman->HashCache[i]; + } else { + if((pIoman->HashCache[i].ulMisses > pHashCache->ulMisses)) { + pHashCache = &pIoman->HashCache[i]; + } + } + } + } + + if(pHashCache) { + // Clear the hash table! + FF_ClearHashTable(pHashCache->pHashTable); + pHashCache->ulDirCluster = ulDirCluster; + pHashCache->ulMisses = 0; + + // Hash the directory! + + FF_InitEntryFetch(pIoman, ulDirCluster, &FetchContext); + + for(i = 0; i < 0xFFFF; i++) { + if(FF_FetchEntryWithContext(pIoman, i, &FetchContext, EntryBuffer)) { + break; // HT addition + } + ucAttrib = FF_getChar(EntryBuffer, FF_FAT_DIRENT_ATTRIB); + if(FF_getChar(EntryBuffer, 0x00) != 0xE5) { + if(ucAttrib != FF_FAT_ATTR_LFN) { + FF_ProcessShortName((FF_T_INT8 *)EntryBuffer); + if(FF_isEndOfDir(EntryBuffer)) { + // HT uncommented + FF_CleanupEntryFetch(pIoman, &FetchContext); + return FF_ERR_NONE; + } + + // Generate the Hash +#if FF_HASH_FUNCTION == CRC16 + ulHash = FF_GetCRC16(EntryBuffer, strlen((const FF_T_INT8 *) EntryBuffer)); +#elif FF_HASH_FUNCTION == CRC8 + ulHash = FF_GetCRC8(EntryBuffer, strlen((const FF_T_INT8 *) EntryBuffer)); +#endif + FF_SetHash(pHashCache->pHashTable, ulHash); + + } + } + } + + FF_CleanupEntryFetch(pIoman, &FetchContext); + + return FF_ERR_NONE; + } + + return -1; +} + +/*void FF_SetDirHashed(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster) { int i; for(i = 0; i < FF_PATH_CACHE_DEPTH; i++) { if(pIoman->pPartition->PathCache[i].DirCluster == DirCluster) { @@ -1003,27 +1085,273 @@ void FF_SetDirHashed(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster) { return; } } -} +}*/ #endif +FF_ERROR FF_PopulateLongDirent(FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_T_UINT16 nEntry, FF_FETCH_CONTEXT *pFetchContext) { + // First get the entire name as UTF-16 from the LFN's. + // Then transform into the API's native string format. + + FF_ERROR Error; + FF_T_UINT uiNumLFNs; + FF_T_UINT uiLfnLength = 0; + FF_T_UINT i,y; +#ifdef FF_UNICODE_UTF8_SUPPORT +// FF_T_SINT32 slRetVal; + FF_T_UINT16 nLfnBegin; + FF_T_UINT16 usUtf8Len = 0; +#endif + FF_T_UINT16 myShort; + FF_T_UINT8 ucCheckSum; -FF_T_SINT8 FF_PopulateLongDirent(FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_T_UINT32 DirCluster, FF_T_UINT16 nEntry) { FF_T_UINT8 EntryBuffer[32]; + //FF_T_UINT16 UTF16Name[FF_MAX_FILENAME]; + +#ifdef FF_UNICODE_SUPPORT + FF_T_WCHAR WCEntryBuffer[32]; + FF_T_WCHAR ShortName[13]; +#else FF_T_INT8 ShortName[13]; +#endif + + Error = FF_FetchEntryWithContext(pIoman, nEntry++, pFetchContext, EntryBuffer); + if(Error) { + return Error; + } + + uiNumLFNs = (FF_T_UINT)(EntryBuffer[0] & ~0x40); + ucCheckSum = FF_getChar(EntryBuffer, FF_FAT_LFN_CHECKSUM); + +#ifdef FF_UNICODE_SUPPORT // UTF-16 Can simply get segments of the UTF-16 sequence going forward + // in the dirents. (I.e. reversed order). + + while(uiNumLFNs) { // Avoid stack intensive use of a UTF-16 buffer. Stream direct to FileName dirent field in correct format. + + // memcopy direct!-UTF-16 support + memcpy(pDirent->FileName + ((uiNumLFNs - 1) * 13) + 0, &EntryBuffer[FF_FAT_LFN_NAME_1], 10); + memcpy(pDirent->FileName + ((uiNumLFNs - 1) * 13) + 5, &EntryBuffer[FF_FAT_LFN_NAME_2], 12); + memcpy(pDirent->FileName + ((uiNumLFNs - 1) * 13) + 11, &EntryBuffer[FF_FAT_LFN_NAME_3], 4); + + + uiLfnLength += 13; + + Error = FF_FetchEntryWithContext(pIoman, nEntry++, pFetchContext, EntryBuffer); + if(Error) { + return Error; + } + uiNumLFNs--; + } + + pDirent->FileName[uiLfnLength] = '\0'; +#endif + +#ifdef FF_UNICODE_UTF8_SUPPORT + // UTF-8 Sequence, we can only convert this from the beginning, must receive entries in reverse. + nLfnBegin = nEntry - 1; + + for(i = 0; i < uiNumLFNs; i++) { + Error = FF_FetchEntryWithContext(pIoman, (nLfnBegin + (uiNumLFNs - 1) - i), pFetchContext, EntryBuffer); + if(Error) { + return Error; + } + + // Now have the first part of the UTF-16 sequence. Stream into a UTF-8 sequence. + for(y = 0; y < 5; y++) { + Error = FF_Utf16ctoUtf8c((FF_T_UINT8 *) &pDirent->FileName[usUtf8Len], (FF_T_UINT16 *) &EntryBuffer[FF_FAT_LFN_NAME_1 + (y*2)], sizeof(pDirent->FileName) - usUtf8Len); + if(Error > 0) { + usUtf8Len += (FF_T_UINT16) Error; + } + } + + for(y = 0; y < 6; y++) { + Error = FF_Utf16ctoUtf8c((FF_T_UINT8 *) &pDirent->FileName[usUtf8Len], (FF_T_UINT16 *) &EntryBuffer[FF_FAT_LFN_NAME_2 + (y*2)], sizeof(pDirent->FileName) - usUtf8Len); + if(Error > 0) { + usUtf8Len += (FF_T_UINT16) Error; + } + } + + for(y = 0; y < 2; y++) { + Error = FF_Utf16ctoUtf8c((FF_T_UINT8 *) &pDirent->FileName[usUtf8Len], (FF_T_UINT16 *) &EntryBuffer[FF_FAT_LFN_NAME_3 + (y*2)], sizeof(pDirent->FileName) - usUtf8Len); + if(Error > 0) { + usUtf8Len += (FF_T_UINT16) Error; + } + } + nEntry++; + } + + pDirent->FileName[usUtf8Len] = '\0'; + + // Put Entry context to correct position. + Error = FF_FetchEntryWithContext(pIoman, nEntry-1, pFetchContext, EntryBuffer); + if(Error) { + return Error; + } + +#endif + +#ifndef FF_UNICODE_SUPPORT +#ifndef FF_UNICODE_UTF8_SUPPORT // No Unicode, simple ASCII. + while(uiNumLFNs) { // Avoid stack intensive use of a UTF-16 buffer. Stream direct to FileName dirent field in correct format. + + for(i = 0; i < 5; i++) { + pDirent->FileName[((uiNumLFNs - 1) * 13) + i] = EntryBuffer[FF_FAT_LFN_NAME_1 + (i*2)]; + } + + for(i = 0; i < 6; i++) { + pDirent->FileName[((uiNumLFNs - 1) * 13) + i + 5] = EntryBuffer[FF_FAT_LFN_NAME_2 + (i*2)]; + } + + for(i = 0; i < 2; i++) { + pDirent->FileName[((uiNumLFNs - 1) * 13) + i + 11] = EntryBuffer[FF_FAT_LFN_NAME_3 + (i*2)]; + } + + uiLfnLength += 13; + + Error = FF_FetchEntryWithContext(pIoman, nEntry++, pFetchContext, EntryBuffer); + if(Error) { + return Error; + } + uiNumLFNs--; + } + + pDirent->FileName[uiLfnLength] = '\0'; + + +#endif +#endif + // Process the Shortname. -- LFN Transformation is now complete. + // Process the ShortName Entry + + // if SHORTNAMES must be included, simple byte copy into shortname buffer. +#if defined(FF_LFN_SUPPORT) && defined(FF_INCLUDE_SHORT_NAME) + memcpy(pDirent->ShortName, EntryBuffer, 11); + pDirent->ShortName[11] = '\0'; + FF_ProcessShortName(pDirent->ShortName); +#endif + +#ifdef FF_UNICODE_SUPPORT + FF_cstrntowcs(WCEntryBuffer, (FF_T_INT8 *) EntryBuffer, 32); + memcpy(ShortName, WCEntryBuffer, 11 * sizeof(FF_T_WCHAR)); +#else + memcpy(ShortName, EntryBuffer, 11); +#endif + FF_ProcessShortName(ShortName); + if(ucCheckSum != FF_CreateChkSum(EntryBuffer)) { +#ifdef FF_UNICODE_SUPPORT + wcscpy(pDirent->FileName, ShortName); +#else + strcpy(pDirent->FileName, ShortName); +#endif + } + + // Finally fill in the other details + myShort = FF_getShort(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_HIGH)); + pDirent->ObjectCluster = (FF_T_UINT32) (myShort << 16); + myShort = FF_getShort(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_LOW)); + pDirent->ObjectCluster |= myShort; + +#ifdef FF_TIME_SUPPORT + // Get the creation Time & Date + FF_GetTime(&pDirent->CreateTime, EntryBuffer, FF_FAT_DIRENT_CREATE_TIME); + FF_GetDate(&pDirent->CreateTime, EntryBuffer, FF_FAT_DIRENT_CREATE_DATE); + // Get the modified Time & Date + FF_GetTime(&pDirent->CreateTime, EntryBuffer, FF_FAT_DIRENT_LASTMOD_TIME); + FF_GetDate(&pDirent->CreateTime, EntryBuffer, FF_FAT_DIRENT_LASTMOD_DATE); + // Get the last accessed Date. + FF_GetDate(&pDirent->AccessedTime, EntryBuffer, FF_FAT_DIRENT_LASTACC_DATE); + pDirent->AccessedTime.Hour = 0; + pDirent->AccessedTime.Minute = 0; + pDirent->AccessedTime.Second = 0; +#endif + + // Get the filesize. + pDirent->Filesize = FF_getLong(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_FILESIZE)); + // Get the attribute. + pDirent->Attrib = FF_getChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB)); + + pDirent->CurrentItem = nEntry; + //return x; + return FF_ERR_NONE; +} + +/* +FF_ERROR FF_PopulateLongDirent(FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_T_UINT16 nEntry, FF_FETCH_CONTEXT *pFetchContext) { + FF_T_UINT8 EntryBuffer[32]; +#ifdef FF_UNICODE_SUPPORT + FF_T_WCHAR UTF16EntryBuffer[32]; + FF_T_WCHAR ShortName[13]; +#if WCHAR_MAX > 0xFFFF + FF_T_UINT16 i,y; +#endif +#else + FF_T_INT8 ShortName[13]; +#ifdef FF_UNICODE_UTF8_SUPPORT + FF_T_SINT32 i, y; +#else + FF_T_UINT16 i, y; +#endif +#endif + +#ifdef FF_UNICODE_UTF8_SUPPORT + FF_T_UINT16 UTF16Name[FF_MAX_FILENAME]; // Read in the entire UTF-16 name into this buffer. + FF_T_UINT16 *UTF16cptr; +#endif FF_T_UINT8 numLFNs; FF_T_UINT8 x; FF_T_UINT8 CheckSum = 0; - FF_T_UINT16 i,y; + FF_T_UINT16 lenlfn = 0; FF_T_UINT16 myShort; + FF_ERROR Error; - FF_FetchEntry(pIoman, DirCluster, nEntry++, EntryBuffer); + Error = FF_FetchEntryWithContext(pIoman, nEntry++, pFetchContext, EntryBuffer); + if(Error) { + return Error; + } + numLFNs = (FF_T_UINT8)(EntryBuffer[0] & ~0x40); // Handle the name CheckSum = FF_getChar(EntryBuffer, FF_FAT_LFN_CHECKSUM); x = numLFNs; while(numLFNs) { + if(numLFNs > 1) { + numLFNs = numLFNs; + } + +#ifdef FF_UNICODE_SUPPORT + // Simply fill the FileName buffer with UTF-16 Filename! +#if WCHAR_MAX <= 0xFFFF // System works in UTF-16 so we can trust it if we just copy the UTF-16 strings directly. + memcpy(pDirent->FileName + ((numLFNs - 1) * 13) + 0, &EntryBuffer[FF_FAT_LFN_NAME_1], (5 * 2)); + memcpy(pDirent->FileName + ((numLFNs - 1) * 13) + 5, &EntryBuffer[FF_FAT_LFN_NAME_2], (6 * 2)); + memcpy(pDirent->FileName + ((numLFNs - 1) * 13) + 11, &EntryBuffer[FF_FAT_LFN_NAME_3], (2 * 2)); + lenlfn += 13; +#else + for(i = 0, y = 0; i < 5; i++, y += 2) { + FF_Utf16ctoUtf32c((FF_T_UINT32 *)&pDirent->FileName[i + ((numLFNs - 1) * 13)], (FF_T_UINT16 *) &EntryBuffer[FF_FAT_LFN_NAME_1 + y]); + //pDirent->FileName[i + ((numLFNs - 1) * 13)] = (FF_T_WCHAR) ((FF_T_WCHAR) EntryBuffer[FF_FAT_LFN_NAME_1 + y] | ((FF_T_WCHAR) EntryBuffer[FF_FAT_LFN_NAME_1 + y + 1] >> 8)); + lenlfn++; + } + for(i = 0, y = 0; i < 6; i++, y += 2) { + FF_Utf16ctoUtf32c((FF_T_UINT32 *)&pDirent->FileName[i + ((numLFNs - 1) * 13) + 5], (FF_T_UINT16 *) &EntryBuffer[FF_FAT_LFN_NAME_2 + y]); + //pDirent->FileName[i + ((numLFNs - 1) * 13) + 5] = (FF_T_WCHAR) ((FF_T_WCHAR) EntryBuffer[FF_FAT_LFN_NAME_2 + y] | ((FF_T_WCHAR) EntryBuffer[FF_FAT_LFN_NAME_2 + y + 1] >> 8)); + lenlfn++; + } + for(i = 0, y = 0; i < 2; i++, y += 2) { + FF_Utf16ctoUtf32c((FF_T_UINT32 *)&pDirent->FileName[i + ((numLFNs - 1) * 13) + 11], (FF_T_UINT16 *) &EntryBuffer[FF_FAT_LFN_NAME_3 + y]); + //pDirent->FileName[i + ((numLFNs - 1) * 13) + 11] = (FF_T_WCHAR) ((FF_T_WCHAR) EntryBuffer[FF_FAT_LFN_NAME_3 + y] | ((FF_T_WCHAR)EntryBuffer[FF_FAT_LFN_NAME_3 + y + 1] >> 8)); + lenlfn++; + } +#endif + // Copy each part of the LFNS +#else +#ifdef FF_UNICODE_UTF8_SUPPORT + memcpy(UTF16Name + ((numLFNs - 1) * 13) + 0, &EntryBuffer[FF_FAT_LFN_NAME_1], (5 * 2)); + memcpy(UTF16Name + ((numLFNs - 1) * 13) + 5, &EntryBuffer[FF_FAT_LFN_NAME_2], (6 * 2)); + memcpy(UTF16Name + ((numLFNs - 1) * 13) + 11, &EntryBuffer[FF_FAT_LFN_NAME_3], (2 * 2)); + lenlfn += 13; +#else + // Attempts to pull ASCII from UTF-8 encoding. for(i = 0, y = 0; i < 5; i++, y += 2) { pDirent->FileName[i + ((numLFNs - 1) * 13)] = EntryBuffer[FF_FAT_LFN_NAME_1 + y]; lenlfn++; @@ -1038,28 +1366,56 @@ FF_T_SINT8 FF_PopulateLongDirent(FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_T_UINT pDirent->FileName[i + ((numLFNs - 1) * 13) + 11] = EntryBuffer[FF_FAT_LFN_NAME_3 + y]; lenlfn++; } +#endif +#endif - FF_FetchEntry(pIoman, DirCluster, nEntry++, EntryBuffer); + Error = FF_FetchEntryWithContext(pIoman, nEntry++, pFetchContext, EntryBuffer); + if(Error) { + return Error; + } numLFNs--; } +#ifdef FF_UNICODE_UTF8_SUPPORT + UTF16cptr = UTF16Name; + UTF16Name[lenlfn] = '\0'; + i = 0; // Keep tabs of the current char position in the UTF-8 sequence. + while(*UTF16cptr) { + y = FF_Utf16ctoUtf8c((FF_T_UINT8 *)&pDirent->FileName[i], UTF16cptr, (FF_MAX_FILENAME - i)); + i += y; + if(FF_GetUtf16SequenceLen(*UTF16cptr++) == 2) { // IF this is a surrogate, then bump the UTF16 Pointer. + UTF16cptr++; + } + } + pDirent->FileName[i] = '\0'; +#else pDirent->FileName[lenlfn] = '\0'; +#endif // Process the ShortName Entry +#ifdef FF_UNICODE_SUPPORT + FF_cstrntowcs(UTF16EntryBuffer, (FF_T_INT8 *) EntryBuffer, 32); + memcpy(ShortName, UTF16EntryBuffer, 11 * sizeof(FF_T_WCHAR)); +#else memcpy(ShortName, EntryBuffer, 11); +#endif if(CheckSum != FF_CreateChkSum(EntryBuffer)) { FF_ProcessShortName(ShortName); +#ifdef FF_UNICODE_SUPPORT + wcscpy(pDirent->FileName, ShortName); +#else strcpy(pDirent->FileName, ShortName); +#endif } else { FF_ProcessShortName(ShortName); } -#ifdef FF_HASH_TABLE_SUPPORT -#if FF_HASH_FUNCTION == CRC16 - FF_AddDirentHash(pIoman, DirCluster, (FF_T_UINT32)FF_GetCRC16((FF_T_UINT8 *) ShortName, strlen(ShortName))); +#ifdef FF_HASH_TABLE_SUPPORT*/ +/*#if FF_HASH_FUNCTION == CRC16 + FF_AddDirentHash(pIoman, pFetchContext->ulDirCluster, (FF_T_UINT32)FF_GetCRC16((FF_T_UINT8 *) ShortName, strlen(ShortName))); #elif FF_HASH_FUNCTION == CRC8 FF_AddDirentHash(pIoman, DirCluster, (FF_T_UINT32)FF_GetCRC8((FF_T_UINT8 *) ShortName, strlen(ShortName))); -#endif +#endif*//* #endif myShort = FF_getShort(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_HIGH)); @@ -1087,9 +1443,10 @@ FF_T_SINT8 FF_PopulateLongDirent(FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_T_UINT pDirent->Attrib = FF_getChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB)); pDirent->CurrentItem = nEntry; - return x; + //return x; + return FF_ERR_NONE; } - +*/ /** * @public * @brief Find's the first directory entry for the provided path. @@ -1097,6 +1454,22 @@ FF_T_SINT8 FF_PopulateLongDirent(FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_T_UINT * All values recorded in pDirent must be preserved to and between calls to * FF_FindNext(). * + * If FF_FINDAPI_ALLOW_WILDCARDS is defined, then path will have the following behaviour: + * + * path = "\" - Open the root dir, and iterate through all items. + * path = "\*.c" - Open the root dir, showing only files matching *.c wildcard. + * path = "\sub1\newdir" - Get the DIRENT for the newdir directory in /sub1/ if one exists. + * path = "\sub1\newdir\" - Open the directory /sub1/newdir/ and iterate through all items. + * path = "\sub1\newdir\*.c" - Open the directory /sub1/newdir/ and iterate through all items matching the *.c wildcard. + * + * It is important to distinguish the differences in behaviour between opening a Find operation + * on a path like /sub1 and /sub1/. (/sub1 gets the sub1 dirent from the / dir, whereas /sub/ opens the sub1 dir). + * + * Note, as compatible with other similar APIs, FullFAT also accepts \sub1\* for the same behaviour as + * /sub1/. + * + * For more up-to-date information please see the FullFAT wiki pages. + * * @param pIoman FF_IOMAN object that was created by FF_CreateIOMAN(). * @param pDirent FF_DIRENT object to store the entry information. * @param path String to of the path to the Dir being listed. @@ -1106,60 +1479,78 @@ FF_T_SINT8 FF_PopulateLongDirent(FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_T_UINT * @return -2 if Dir was not found. * **/ +#ifdef FF_UNICODE_SUPPORT +FF_ERROR FF_FindFirst(FF_IOMAN *pIoman, FF_DIRENT *pDirent, const FF_T_WCHAR *path) { +#else FF_ERROR FF_FindFirst(FF_IOMAN *pIoman, FF_DIRENT *pDirent, const FF_T_INT8 *path) { - FF_T_UINT8 numLFNs; - FF_T_UINT8 EntryBuffer[32]; +#endif +#ifdef FF_UNICODE_SUPPORT + FF_T_UINT16 PathLen = (FF_T_UINT16) wcslen(path); +#else FF_T_UINT16 PathLen = (FF_T_UINT16) strlen(path); +#endif + FF_ERROR Error; + +#ifdef FF_FINDAPI_ALLOW_WILDCARDS + FF_T_UINT16 i = 0; +#ifdef FF_UNICODE_SUPPORT + const FF_T_WCHAR *szWildCard; // Check for a Wild-card. +#else + const FF_T_INT8 *szWildCard; // Check for a Wild-card. +#endif +#endif if(!pIoman) { return FF_ERR_NULL_POINTER; } + // Detect a Wild-Card on the End, or Filename, as apposed to a complete path. +#ifndef FF_FINDAPI_ALLOW_WILDCARDS pDirent->DirCluster = FF_FindDir(pIoman, path, PathLen); // Get the directory cluster, if it exists. +#endif + +#ifdef FF_FINDAPI_ALLOW_WILDCARDS + pDirent->szWildCard[0] = '\0'; // WildCard blank if its not a wildCard. + + szWildCard = &path[PathLen - 1]; + + if(PathLen) { + while(*szWildCard != '\\' && *szWildCard != '/') { // Open the dir of the last token. + i++; + szWildCard--; + if(!(PathLen - i)) { + break; + } + } + } + + pDirent->DirCluster = FF_FindDir(pIoman, path, PathLen - i, &Error); + if(Error) { + return Error; + } + if(pDirent->DirCluster) { + // Valid Dir found, copy the wildCard to filename! +#ifdef FF_UNICODE_SUPPORT + wcsncpy(pDirent->szWildCard, ++szWildCard, FF_MAX_FILENAME); +#else + strncpy(pDirent->szWildCard, ++szWildCard, FF_MAX_FILENAME); +#endif + } +#endif if(pDirent->DirCluster == 0) { return FF_ERR_DIR_INVALID_PATH; } - - for(pDirent->CurrentItem = 0; pDirent->CurrentItem < 0xFFFF; pDirent->CurrentItem += 1) { - if(FF_FetchEntry(pIoman, pDirent->DirCluster, pDirent->CurrentItem, EntryBuffer)) { - return FF_ERR_DIR_END_OF_DIR; - } - if(EntryBuffer[0] != FF_FAT_DELETED) { - if(FF_isEndOfDir(EntryBuffer)){ - return FF_ERR_DIR_END_OF_DIR; - } - pDirent->Attrib = FF_getChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB)); - if((pDirent->Attrib & FF_FAT_ATTR_LFN) == FF_FAT_ATTR_LFN) { - // LFN Processing - numLFNs = (FF_T_UINT8)(EntryBuffer[0] & ~0x40); - // Get the shortname and check if it is marked deleted. -#ifdef FF_LFN_SUPPORT - // Fetch the shortname, and get it's checksum, or for a deleted item with - // orphaned LFN entries. - if(FF_FetchEntry(pIoman, pDirent->DirCluster, (pDirent->CurrentItem + numLFNs), EntryBuffer)) { - return FF_ERR_DIR_END_OF_DIR; - } - - if(EntryBuffer[0] != FF_FAT_DELETED) { - FF_PopulateLongDirent(pIoman, pDirent, pDirent->DirCluster, pDirent->CurrentItem); - return FF_ERR_NONE; - } -#else - pDirent->CurrentItem += (numLFNs - 1); -#endif - } else if((pDirent->Attrib & FF_FAT_ATTR_VOLID) == FF_FAT_ATTR_VOLID) { - // Do Nothing - - } else { - FF_PopulateShortDirent(pIoman, pDirent, EntryBuffer); - pDirent->CurrentItem += 1; - return FF_ERR_NONE; - } - } - } - return FF_ERR_DIR_END_OF_DIR; + // Initialise the Fetch Context + Error = FF_InitEntryFetch(pIoman, pDirent->DirCluster, &pDirent->FetchContext); + if(Error) { + return Error; + } + + pDirent->CurrentItem = 0; + + return FF_FindNext(pIoman, pDirent); } /** @@ -1167,16 +1558,17 @@ FF_ERROR FF_FindFirst(FF_IOMAN *pIoman, FF_DIRENT *pDirent, const FF_T_INT8 *pat * @brief Get's the next Entry based on the data recorded in the FF_DIRENT object. * * All values recorded in pDirent must be preserved to and between calls to - * FF_FindNext(). + * FF_FindNext(). Please see @see FF_FindFirst() for find initialisation. * * @param pIoman FF_IOMAN object that was created by FF_CreateIOMAN(). - * @param pDirent FF_DIRENT object to store the entry information. + * @param pDirent FF_DIRENT object to store the entry information. (As initialised by FF_FindFirst()). * * @return FF_ERR_DEVICE_DRIVER_FAILED is device access failed. * **/ FF_ERROR FF_FindNext(FF_IOMAN *pIoman, FF_DIRENT *pDirent) { + FF_ERROR Error; FF_T_UINT8 numLFNs; FF_T_UINT8 EntryBuffer[32]; @@ -1185,11 +1577,14 @@ FF_ERROR FF_FindNext(FF_IOMAN *pIoman, FF_DIRENT *pDirent) { } for(; pDirent->CurrentItem < 0xFFFF; pDirent->CurrentItem += 1) { - if(FF_FetchEntry(pIoman, pDirent->DirCluster, pDirent->CurrentItem, EntryBuffer)) { - return FF_ERR_DIR_END_OF_DIR; + Error = FF_FetchEntryWithContext(pIoman, pDirent->CurrentItem, &pDirent->FetchContext, EntryBuffer); + if(Error) { + FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); + return Error; } if(EntryBuffer[0] != FF_FAT_DELETED) { if(FF_isEndOfDir(EntryBuffer)){ + FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); return FF_ERR_DIR_END_OF_DIR; } pDirent->Attrib = FF_getChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB)); @@ -1200,13 +1595,41 @@ FF_ERROR FF_FindNext(FF_IOMAN *pIoman, FF_DIRENT *pDirent) { #ifdef FF_LFN_SUPPORT // Fetch the shortname, and get it's checksum, or for a deleted item with // orphaned LFN entries. - if(FF_FetchEntry(pIoman, pDirent->DirCluster, (pDirent->CurrentItem + numLFNs), EntryBuffer)) { - return FF_ERR_DIR_END_OF_DIR; + Error = FF_FetchEntryWithContext(pIoman, (pDirent->CurrentItem + numLFNs), &pDirent->FetchContext, EntryBuffer); + if(Error) { + FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); + return Error; } if(EntryBuffer[0] != FF_FAT_DELETED) { - FF_PopulateLongDirent(pIoman, pDirent, pDirent->DirCluster, pDirent->CurrentItem); + Error = FF_PopulateLongDirent(pIoman, pDirent, pDirent->CurrentItem, &pDirent->FetchContext); + if(Error) { + FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); + return Error; + } +#ifdef FF_INCLUDE_SHORT_NAME + pDirent->Attrib |= FF_FAT_ATTR_IS_LFN; +#endif + +#ifdef FF_FINDAPI_ALLOW_WILDCARDS +#ifdef FF_UNICODE_SUPPORT + if(wcscmp(pDirent->szWildCard, L"")) { +#else + if(strcmp(pDirent->szWildCard, "")) { +#endif + if(FF_wildcompare(pDirent->szWildCard, pDirent->FileName)) { + FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); + return FF_ERR_NONE; + } + pDirent->CurrentItem -= 1; + } else { + FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); + return FF_ERR_NONE; + } +#else + FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); return FF_ERR_NONE; +#endif } #else pDirent->CurrentItem += (numLFNs - 1); @@ -1216,11 +1639,37 @@ FF_ERROR FF_FindNext(FF_IOMAN *pIoman, FF_DIRENT *pDirent) { } else { FF_PopulateShortDirent(pIoman, pDirent, EntryBuffer); +#if defined(FF_SHORTNAME_CASE) + // Apply NT/XP+ bits to get correct case + FF_CaseShortName(pDirent->FileName, FF_getChar(EntryBuffer, FF_FAT_CASE_OFFS)); +#endif +#ifdef FF_FINDAPI_ALLOW_WILDCARDS +#ifdef FF_UNICODE_SUPPORT + if(wcscmp(pDirent->szWildCard, L"")) { +#else + if(strcmp(pDirent->szWildCard, "")) { +#endif + if(FF_wildcompare(pDirent->szWildCard, pDirent->FileName)) { + FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); + pDirent->CurrentItem += 1; + return FF_ERR_NONE; + } + } else { + FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); + pDirent->CurrentItem += 1; + return FF_ERR_NONE; + } +#else + + FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); pDirent->CurrentItem += 1; return FF_ERR_NONE; +#endif } } } + + FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); return FF_ERR_DIR_END_OF_DIR; } @@ -1234,30 +1683,55 @@ FF_T_SINT8 FF_RewindFind(FF_IOMAN *pIoman, FF_DIRENT *pDirent) { return 0; } +/* + Returns >= 0 for a free dirent entry. + Returns < 0 with and Error code if anything goes wrong. +*/ +static FF_T_SINT32 FF_FindFreeDirent(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT16 Sequential) { -FF_T_SINT32 FF_FindFreeDirent(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT16 Sequential) { + FF_T_UINT8 EntryBuffer[32]; + FF_T_UINT16 i = 0; + FF_T_UINT16 nEntry; + FF_ERROR Error; + FF_T_UINT32 DirLength; + FF_FETCH_CONTEXT FetchContext; - FF_T_UINT8 EntryBuffer[32]; - FF_T_UINT16 i = 0; - FF_T_UINT16 nEntry; - FF_T_SINT8 RetVal; - FF_T_UINT32 DirLength; - FF_T_UINT32 iEndOfChain; + Error = FF_InitEntryFetch(pIoman, DirCluster, &FetchContext); + if(Error) { + return Error; + } for(nEntry = 0; nEntry < 0xFFFF; nEntry++) { - if(FF_FetchEntry(pIoman, DirCluster, nEntry, EntryBuffer) == FF_ERR_DIR_END_OF_DIR) { - RetVal = FF_ExtendDirectory(pIoman, DirCluster); - if(RetVal != FF_ERR_NONE) { - return RetVal; + Error = FF_FetchEntryWithContext(pIoman, nEntry, &FetchContext, EntryBuffer); + if(Error == FF_ERR_DIR_END_OF_DIR) { + + Error = FF_ExtendDirectory(pIoman, DirCluster); + FF_CleanupEntryFetch(pIoman, &FetchContext); + + if(Error) { + return Error; } + return nEntry; + } else { + if(Error) { + FF_CleanupEntryFetch(pIoman, &FetchContext); + return Error; + } } if(FF_isEndOfDir(EntryBuffer)) { // If its the end of the Dir, then FreeDirents from here. // Check Dir is long enough! - DirLength = FF_GetChainLength(pIoman, DirCluster, &iEndOfChain); + DirLength = FetchContext.ulChainLength;//FF_GetChainLength(pIoman, DirCluster, &iEndOfChain); if((nEntry + Sequential) > (FF_T_UINT16)(((pIoman->pPartition->SectorsPerCluster * pIoman->pPartition->BlkSize) * DirLength) / 32)) { - FF_ExtendDirectory(pIoman, DirCluster); + Error = FF_ExtendDirectory(pIoman, DirCluster); } + + FF_CleanupEntryFetch(pIoman, &FetchContext); + + if(Error) { + return Error; + } + return nEntry; } if(EntryBuffer[0] == 0xE5) { @@ -1267,36 +1741,48 @@ FF_T_SINT32 FF_FindFreeDirent(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UIN } if(i == Sequential) { + FF_CleanupEntryFetch(pIoman, &FetchContext); return (nEntry - (Sequential - 1));// Return the beginning entry in the sequential sequence. } } - return FF_ERR_DIR_DIRECTORY_FULL; + FF_CleanupEntryFetch(pIoman, &FetchContext); + + return FF_ERR_DIR_DIRECTORY_FULL; } -FF_T_SINT8 FF_PutEntry(FF_IOMAN *pIoman, FF_T_UINT16 Entry, 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_BUFFER *pBuffer; + FF_ERROR Error; FF_T_UINT32 itemLBA; FF_T_UINT32 clusterNum = FF_getClusterChainNumber (pIoman, Entry, (FF_T_UINT16)32); FF_T_UINT32 relItem = FF_getMinorBlockEntry (pIoman, Entry, (FF_T_UINT16)32); - FF_T_UINT32 clusterAddress = FF_TraverseFAT(pIoman, DirCluster, clusterNum); + FF_T_UINT32 clusterAddress = FF_TraverseFAT(pIoman, DirCluster, clusterNum, &Error); + + if(Error) { + return Error; + } itemLBA = FF_Cluster2LBA(pIoman, clusterAddress) + FF_getMajorBlockNumber(pIoman, Entry, (FF_T_UINT16)32); itemLBA = FF_getRealLBA (pIoman, itemLBA) + FF_getMinorBlockNumber(pIoman, relItem, (FF_T_UINT16)32); pBuffer = FF_GetBuffer(pIoman, itemLBA, FF_MODE_WRITE); { + if(!pBuffer) { + return FF_ERR_DEVICE_DRIVER_FAILED; + } // Modify the Entry! //memcpy((pBuffer->pBuffer + (32*relItem)), pDirent->FileName, 11); - FF_putChar(pBuffer->pBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB + (32 * relItem)), pDirent->Attrib); - FF_putShort(pBuffer->pBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_HIGH + (32 * relItem)), (FF_T_UINT16)(pDirent->ObjectCluster >> 16)); - FF_putShort(pBuffer->pBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_LOW + (32 * relItem)), (FF_T_UINT16)(pDirent->ObjectCluster)); - FF_putLong(pBuffer->pBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_FILESIZE + (32 * relItem)), pDirent->Filesize); + relItem *= 32; + FF_putChar(pBuffer->pBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB + relItem), pDirent->Attrib); + FF_putShort(pBuffer->pBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_HIGH + relItem), (FF_T_UINT16)(pDirent->ObjectCluster >> 16)); + FF_putShort(pBuffer->pBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_LOW + relItem), (FF_T_UINT16)(pDirent->ObjectCluster)); + FF_putLong(pBuffer->pBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_FILESIZE + relItem), pDirent->Filesize); #ifdef FF_TIME_SUPPORT - FF_PlaceDate((pBuffer->pBuffer + (32 * relItem)), FF_FAT_DIRENT_LASTACC_DATE); // Last accessed date. + FF_PlaceDate((pBuffer->pBuffer + relItem), FF_FAT_DIRENT_LASTACC_DATE); // Last accessed date. #endif } FF_ReleaseBuffer(pIoman, pBuffer); @@ -1304,143 +1790,200 @@ FF_T_SINT8 FF_PutEntry(FF_IOMAN *pIoman, FF_T_UINT16 Entry, FF_T_UINT32 DirClust return 0; } +FF_T_BOOL FF_ValidShortChar (FF_T_INT8 Chr) +{ + return (Chr >= 'A' && Chr <= 'Z') || +#if defined(FF_SHORTNAME_CASE) + (Chr >= 'a' && Chr <= 'z') || // lower-case can be stored using NT/XP attribute +#endif + (Chr >= '0' && Chr <= '9') || + strchr ("$%-_@~`!(){}^#&", Chr) != NULL; +} -/*static FF_T_BOOL FF_isShortName(const FF_T_UINT8 *Name, FF_T_UINT16 StrLen) { - FF_T_UINT16 i; - for(i = 0; i < StrLen; i++) { - if(Name[i] == '.') { - i--; - } - } - if(i < 11) { - return FF_TRUE; - } - return FF_FALSE; -}*/ +FF_T_BOOL FF_ValidLongChar (FF_T_INT8 Chr) +{ + return Chr >= 0x20 && strchr ("/\\:*?\"<>|", Chr) == NULL; +} +#ifdef FF_UNICODE_SUPPORT +FF_T_SINT8 FF_CreateShortName(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_WCHAR *ShortName, FF_T_WCHAR *LongName) { +#else FF_T_SINT8 FF_CreateShortName(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *ShortName, FF_T_INT8 *LongName) { - FF_T_UINT16 i,x,y; - FF_T_INT8 TempName[FF_MAX_FILENAME]; +#endif + FF_T_UINT8 caseAttrib = 0; +#if defined(FF_SHORTNAME_CASE) + FF_T_UINT8 testAttrib = FF_FAT_CASE_ATTR_BASE; +#endif + + FF_T_UINT16 i,x,y,last_dot; + FF_T_UINT16 first_tilde = 6; +#ifdef FF_UNICODE_SUPPORT + FF_T_WCHAR MyShortName[13]; +#else FF_T_INT8 MyShortName[13]; - FF_T_UINT16 NameLen; - FF_T_BOOL FitsShort = FF_FALSE; +#endif + FF_T_UINT16 NameLen; + FF_T_BOOL FitsShort = FF_TRUE; FF_DIRENT MyDir; + FF_T_BOOL found; //FF_T_SINT8 RetVal = 0; FF_T_INT8 NumberBuf[6]; - // Create a Short Name - strncpy(TempName, LongName, FF_MAX_FILENAME); - NameLen = (FF_T_UINT16) strlen(TempName); - FF_toupper(TempName, NameLen); + FF_ERROR Error; - // Initialise Shortname - - for(i = 0; i < 11; i++) { - ShortName[i] = 0x20; - } +#ifdef FF_UNICODE_SUPPORT + NameLen = (FF_T_UINT16) wcslen(LongName); +#else + NameLen = (FF_T_UINT16) strlen(LongName); +#endif // Does LongName fit a shortname? - for(i = 0, x = 0; i < NameLen; i++) { - if(TempName[i] != '.') { + for(i = 0, x = 0, last_dot = NameLen; i < NameLen; i++) { + if(LongName[i] != '.') { x++; - } - } - - if(x <= 11) { - //FitsShort = FF_TRUE; - } - - // Main part of the name - for(i = 0, x = 0; i < 8; i++, x++) { - if(i == 0 && TempName[x] == '.') { - i--; } else { - if(TempName[x] == '.') { - break; - } else if(TempName[x] == ' ') { - i--; - } else { - ShortName[i] = TempName[x]; - if(ShortName[i] == 0x00) { - ShortName[i] = 0x20; - } - } - } - } - - for(i = NameLen; i > x; i--) { - if(TempName[i] == '.') { - break; + last_dot = i; } } - if(TempName[i] == '.') { - x = i + 1; - for(i = 0; i < 3; i++) { - if(x < NameLen) { - ShortName[8 + i] = TempName[x++]; + if (NameLen > 12 || NameLen-x > 1 || NameLen-last_dot > 4 || last_dot > 8) { + FitsShort = FF_FALSE; + } + + for(i = 0, x = 0; i < 11; x++) { + FF_T_INT8 ch = (FF_T_INT8) LongName[x]; + if (!ch) + break; + if (x == last_dot) { + while (i < 8) + ShortName[i++] = 0x20; +#if defined(FF_SHORTNAME_CASE) + testAttrib = FF_FAT_CASE_ATTR_EXT; +#endif + } else { + if (i == 8) { + x = last_dot; + ch = (FF_T_INT8) LongName[x]; + if (ch) + ch = (FF_T_INT8) LongName[++x]; +#if defined(FF_SHORTNAME_CASE) + testAttrib = FF_FAT_CASE_ATTR_EXT; +#endif } + if (!FF_ValidShortChar (ch)) { + FitsShort = FF_FALSE; + continue; + } + if (ch >= 'a' && ch <= 'z') { + ch -= 0x20; +#if defined(FF_SHORTNAME_CASE) + if (testAttrib) + caseAttrib |= testAttrib; + else + FitsShort = FF_FALSE; // We had capital: does not fit + } else if (ch >= 'A' && ch <= 'Z') { + if (caseAttrib & testAttrib) + FitsShort = FF_FALSE; // We had lower-case: does not fit + testAttrib = 0; +#endif + } + ShortName[i++] = ch; } } + while (i < 11) + ShortName[i++] = 0x20; + if (last_dot < first_tilde) + first_tilde = last_dot; + if (NameLen < first_tilde) // Names like "Abc" will become "~Abc" + first_tilde = NameLen; // Tail : memcpy(MyShortName, ShortName, 11); FF_ProcessShortName(MyShortName); - - if(!FF_FindEntryInDir(pIoman, DirCluster, MyShortName, 0x00, &MyDir) && FitsShort) { - return 0; - } else { - if(FitsShort) { - return FF_ERR_DIR_OBJECT_EXISTS; - } - for(i = 1; i < 0x0000FFFF; i++) { // Max Number of Entries in a DIR! - sprintf(NumberBuf, "%d", i); - NameLen = (FF_T_UINT16) strlen(NumberBuf); - x = 7 - NameLen; - ShortName[x++] = '~'; - for(y = 0; y < NameLen; y++) { - ShortName[x+y] = NumberBuf[y]; - } - memcpy(MyShortName, ShortName, 11); - FF_ProcessShortName(MyShortName); - if(!FF_ShortNameExists(pIoman, DirCluster, MyShortName)) { - return 0; - } - } - // Add a tail and special number until we're happy :D + found = (FF_T_BOOL) FF_FindEntryInDir(pIoman, DirCluster, MyShortName, 0x00, &MyDir, &Error); +#ifdef Hein_Tibosch + if (verboseLevel >= 1) logPrintf ("Long Name: %-14.14s Short '%s' (%s) Fit '%d' Found %d\n", LongName, ShortName, MyShortName, FitsShort, found); +#endif + if(FitsShort && !found) { + return caseAttrib | 0x01; } + if(FitsShort) { + return FF_ERR_DIR_OBJECT_EXISTS; + } + for(i = 1; i < 0x0000FFFF; i++) { // Max Number of Entries in a DIR! + sprintf(NumberBuf, "%d", i); + NameLen = (FF_T_UINT16) strlen(NumberBuf); + x = 7 - NameLen; + if (x > first_tilde) + x = first_tilde; + ShortName[x++] = '~'; + for(y = 0; y < NameLen; y++) { + ShortName[x+y] = NumberBuf[y]; + } + memcpy(MyShortName, ShortName, 11); + FF_ProcessShortName(MyShortName); + found = FF_ShortNameExists(pIoman, DirCluster, MyShortName, &Error); +#ifdef Hein_Tibosch + if (verboseLevel >= 1) logPrintf ("Long Name: %-14.14s Short '%s' (%s) Fit '%d' Found %d\n", LongName, ShortName, MyShortName, FitsShort, found); +#endif + if(!found) { +#ifdef FF_HASH_CACHE +#if FF_HASH_FUNCTION == CRC16 + FF_AddDirentHash(pIoman, DirCluster, (FF_T_UINT32) FF_GetCRC16((FF_T_UINT8*)MyShortName, strlen(MyShortName))); +#elif FF_HASH_FUNCTION == CRC8 + FF_AddDirentHash(pIoman, DirCluster, (FF_T_UINT32) FF_GetCRC8((FF_T_UINT8*)MyShortName, strlen(MyShortName))); +#endif +#endif + return 0; + } + } + // Add a tail and special number until we're happy :D return FF_ERR_DIR_DIRECTORY_FULL; } + + #ifdef FF_LFN_SUPPORT -static FF_T_SINT8 FF_CreateLFNEntry(FF_T_UINT8 *EntryBuffer, FF_T_INT8 *Name, FF_T_UINT8 NameLen, FF_T_UINT8 nLFN, FF_T_UINT8 CheckSum) { +static FF_T_SINT8 FF_CreateLFNEntry(FF_T_UINT8 *EntryBuffer, FF_T_UINT16 *Name, FF_T_UINT uiNameLen, FF_T_UINT uiLFN, FF_T_UINT8 CheckSum) { - FF_T_UINT8 i, x; + FF_T_UINT i, x; memset(EntryBuffer, 0, 32); - FF_putChar(EntryBuffer, FF_FAT_LFN_ORD, (FF_T_UINT8) ((nLFN & ~0x40))); + FF_putChar(EntryBuffer, FF_FAT_LFN_ORD, (FF_T_UINT8) ((uiLFN & ~0x40))); FF_putChar(EntryBuffer, FF_FAT_DIRENT_ATTRIB, (FF_T_UINT8) FF_FAT_ATTR_LFN); FF_putChar(EntryBuffer, FF_FAT_LFN_CHECKSUM, (FF_T_UINT8) CheckSum); // Name_1 for(i = 0, x = 0; i < 5; i++, x += 2) { - if(i < NameLen) { - EntryBuffer[FF_FAT_LFN_NAME_1 + x] = Name[i]; - } else if (i == NameLen) { - EntryBuffer[FF_FAT_LFN_NAME_1 + x] = '\0'; - }else { - EntryBuffer[FF_FAT_LFN_NAME_1 + x] = 0xFF; - EntryBuffer[FF_FAT_LFN_NAME_1 + x + 1] = 0xFF; + if(i < uiNameLen) + { + memcpy(&EntryBuffer[FF_FAT_LFN_NAME_1 + x], &Name[i], sizeof(FF_T_UINT16)); + //bobtntfullfat *((FF_T_UINT16 *) &EntryBuffer[FF_FAT_LFN_NAME_1 + x]) = Name[i]; } + else + if (i == uiNameLen) + { + EntryBuffer[FF_FAT_LFN_NAME_1 + x] = '\0'; + EntryBuffer[FF_FAT_LFN_NAME_1 + x + 1] = '\0'; + } + else + { + EntryBuffer[FF_FAT_LFN_NAME_1 + x] = 0xFF; + EntryBuffer[FF_FAT_LFN_NAME_1 + x + 1] = 0xFF; + } } // Name_2 for(i = 0, x = 0; i < 6; i++, x += 2) { - if((i + 5) < NameLen) { - EntryBuffer[FF_FAT_LFN_NAME_2 + x] = Name[i+5]; - } else if ((i + 5) == NameLen) { - EntryBuffer[FF_FAT_LFN_NAME_2 + x] = '\0'; + if((i + 5) < uiNameLen) + { + memcpy(&EntryBuffer[FF_FAT_LFN_NAME_2 + x], &Name[i+5], sizeof(FF_T_UINT16)); + //EntryBuffer[FF_FAT_LFN_NAME_2 + x] = Name[i+5]; + //bobtntfullfat *((FF_T_UINT16 *) &EntryBuffer[FF_FAT_LFN_NAME_2 + x]) = Name[i+5]; + } else if ((i + 5) == uiNameLen) { + EntryBuffer[FF_FAT_LFN_NAME_2 + x] = '\0'; + EntryBuffer[FF_FAT_LFN_NAME_2 + x + 1] = '\0'; }else { EntryBuffer[FF_FAT_LFN_NAME_2 + x] = 0xFF; EntryBuffer[FF_FAT_LFN_NAME_2 + x + 1] = 0xFF; @@ -1449,10 +1992,14 @@ static FF_T_SINT8 FF_CreateLFNEntry(FF_T_UINT8 *EntryBuffer, FF_T_INT8 *Name, FF // Name_3 for(i = 0, x = 0; i < 2; i++, x += 2) { - if((i + 11) < NameLen) { - EntryBuffer[FF_FAT_LFN_NAME_3 + x] = Name[i+11]; - } else if ((i + 11) == NameLen) { - EntryBuffer[FF_FAT_LFN_NAME_3 + x] = '\0'; + if((i + 11) < uiNameLen) + { + memcpy(&EntryBuffer[FF_FAT_LFN_NAME_3 + x], &Name[i+11], sizeof(FF_T_UINT16)); + //EntryBuffer[FF_FAT_LFN_NAME_3 + x] = Name[i+11]; + //bobtntfullfat *((FF_T_UINT16 *) &EntryBuffer[FF_FAT_LFN_NAME_3 + x]) = Name[i+11]; + } else if ((i + 11) == uiNameLen) { + EntryBuffer[FF_FAT_LFN_NAME_3 + x] = '\0'; + EntryBuffer[FF_FAT_LFN_NAME_3 + x + 1] = '\0'; }else { EntryBuffer[FF_FAT_LFN_NAME_3 + x] = 0xFF; EntryBuffer[FF_FAT_LFN_NAME_3 + x + 1] = 0xFF; @@ -1461,13 +2008,26 @@ static FF_T_SINT8 FF_CreateLFNEntry(FF_T_UINT8 *EntryBuffer, FF_T_INT8 *Name, FF return FF_ERR_NONE; } +#endif -static FF_T_SINT8 FF_CreateLFNs(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *Name, FF_T_UINT8 CheckSum, FF_T_UINT16 nEntry) { +/* +#ifdef FF_UNICODE_SUPPORT +static FF_ERROR FF_CreateLFNs(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_WCHAR *Name, FF_T_UINT8 CheckSum, FF_T_UINT16 nEntry) { +#else +static FF_ERROR FF_CreateLFNs(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *Name, FF_T_UINT8 CheckSum, FF_T_UINT16 nEntry) { +#endif FF_T_UINT8 EntryBuffer[32]; +#ifdef FF_UNICODE_SUPPORT + FF_T_UINT16 NameLen = (FF_T_UINT16) wcslen(Name); +#else FF_T_UINT16 NameLen = (FF_T_UINT16) strlen(Name); +#endif FF_T_UINT8 NumLFNs = (FF_T_UINT8) (NameLen / 13); FF_T_UINT8 i; FF_T_UINT8 EndPos = (NameLen % 13); + FF_ERROR Error; + + FF_FETCH_CONTEXT FetchContext; if(EndPos) { NumLFNs ++; @@ -1475,6 +2035,11 @@ static FF_T_SINT8 FF_CreateLFNs(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_I EndPos = 13; } + Error = FF_InitEntryFetch(pIoman, DirCluster, &FetchContext); + if(Error) { + return Error; + } + for(i = NumLFNs; i > 0; i--) { if(i == NumLFNs) { FF_CreateLFNEntry(EntryBuffer, (Name + (13 * (i - 1))), EndPos, i, CheckSum); @@ -1482,16 +2047,143 @@ static FF_T_SINT8 FF_CreateLFNs(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_I } else { FF_CreateLFNEntry(EntryBuffer, (Name + (13 * (i - 1))), 13, i, CheckSum); } - FF_PushEntry(pIoman, DirCluster, nEntry + (NumLFNs - i), EntryBuffer); + + Error = FF_PushEntryWithContext(pIoman, nEntry + (NumLFNs - i), &FetchContext, EntryBuffer); + if(Error) { + FF_CleanupEntryFetch(pIoman, &FetchContext); + return Error; + } } + FF_CleanupEntryFetch(pIoman, &FetchContext); + return FF_ERR_NONE; } #endif +*/ -FF_T_SINT8 FF_ExtendDirectory(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster) { + +#ifdef FF_UNICODE_SUPPORT +static FF_ERROR FF_CreateLFNs(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_WCHAR *Name, FF_T_UINT8 CheckSum, FF_T_UINT16 nEntry) { +#else +static FF_ERROR FF_CreateLFNs(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *Name, FF_T_UINT8 CheckSum, FF_T_UINT16 nEntry) { +#endif + FF_ERROR Error; + FF_T_UINT uiNumLFNs; + FF_T_UINT uiEndPos; + FF_T_UINT i,y; + +#ifdef FF_UNICODE_UTF8_SUPPORT + FF_T_SINT32 slRetVal; +#endif + +#ifndef FF_UNICODE_SUPPORT +#ifndef FF_UNICODE_UTF8_SUPPORT + FF_T_UINT16 *pUtf16; +#endif +#endif + + FF_FETCH_CONTEXT FetchContext; + + FF_T_UINT8 EntryBuffer[32]; + FF_T_UINT16 usUtf16Name[FF_MAX_FILENAME + 1]; + + +#ifdef FF_UNICODE_SUPPORT +#if WCHAR_MAX <= 0xFFFF + y = wcslen(Name); + if(y > FF_MAX_FILENAME) { + return FF_ERR_DIR_NAME_TOO_LONG; + } + wcsncpy(usUtf16Name, Name, FF_MAX_FILENAME); +#else + i = 0; + y = 0; + while(Name[i]) { + FF_Utf32ctoUtf16c(&usUtf16Name[y], (FF_T_UINT32) Name[i], FF_MAX_FILENAME - i); + y += FF_GetUtf16SequenceLen(usUtf16Name[y]); + i++; + if(y > FF_MAX_FILENAME) { + return FF_ERR_DIR_NAME_TOO_LONG; + } + } +#endif +#endif + + // Convert the name into UTF-16 format. +#ifdef FF_UNICODE_UTF8_SUPPORT + // Simply convert the UTF8 to UTF16 and be done with it. + i = 0; + y = 0; + while(Name[i]) { + slRetVal = FF_Utf8ctoUtf16c(&usUtf16Name[y], (FF_T_UINT8 *)&Name[i], FF_MAX_FILENAME - i); + if(slRetVal > 0) { + i += slRetVal; + } else { + break; // No more space in the UTF-16 buffer, simply truncate for safety. + } + y += FF_GetUtf16SequenceLen(usUtf16Name[y]); + if(y > FF_MAX_FILENAME) { + return FF_ERR_DIR_NAME_TOO_LONG; + } + } +#else +#ifndef FF_UNICODE_SUPPORT + i = 0; + y = strlen(Name); + if(y > FF_MAX_FILENAME) { + return FF_ERR_DIR_NAME_TOO_LONG; + } + pUtf16 = usUtf16Name; + while(Name[i]) { + usUtf16Name[i] = (FF_T_UINT16) Name[i]; + i++; + } +#endif +#endif + + // Whole name is now in a valid UTF-16 format. Lets go make thos LFN's. + // i should at this point be the length of the name. + + uiNumLFNs = y / 13; // Number of LFNs is the total number of UTF-16 units, divided by 13 (13 units per LFN). + uiEndPos = y % 13; // The ending position in an LFN, of the last LFN UTF-16 charachter. + + if(uiEndPos) { + uiNumLFNs++; + } else { + uiEndPos = 13; + } + + Error = FF_InitEntryFetch(pIoman, DirCluster, &FetchContext); + if(Error) { + return Error; + } + + // After this point, i is no longer the length of the Filename in UTF-16 units. + for(i = uiNumLFNs; i > 0; i--) { + if(i == uiNumLFNs) { + FF_CreateLFNEntry(EntryBuffer, (usUtf16Name + (13 * (i - 1))), uiEndPos, i, CheckSum); + EntryBuffer[0] |= 0x40; + } else { + FF_CreateLFNEntry(EntryBuffer, (usUtf16Name + (13 * (i - 1))), 13, i, CheckSum); + } + + Error = FF_PushEntryWithContext(pIoman, nEntry + (uiNumLFNs - i), &FetchContext, EntryBuffer); + if(Error) { + FF_CleanupEntryFetch(pIoman, &FetchContext); + return Error; + } + } + + FF_CleanupEntryFetch(pIoman, &FetchContext); + + return FF_ERR_NONE; +} + +FF_ERROR FF_ExtendDirectory(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster) { FF_T_UINT32 CurrentCluster; FF_T_UINT32 NextCluster; + FF_ERROR Error; if(pIoman->pPartition->Type != FF_T_FAT32) { if(DirCluster == pIoman->pPartition->RootDirCluster) { @@ -1500,7 +2192,10 @@ FF_T_SINT8 FF_ExtendDirectory(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster) { } if(!pIoman->pPartition->FreeClusterCount) { - pIoman->pPartition->FreeClusterCount = FF_CountFreeClusters(pIoman); + pIoman->pPartition->FreeClusterCount = FF_CountFreeClusters(pIoman, &Error); + if(Error) { + return Error; + } if(pIoman->pPartition->FreeClusterCount == 0) { return FF_ERR_FAT_NO_FREE_CLUSTERS; } @@ -1508,20 +2203,52 @@ FF_T_SINT8 FF_ExtendDirectory(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster) { FF_lockFAT(pIoman); { - CurrentCluster = FF_FindEndOfChain(pIoman, DirCluster); - NextCluster = FF_FindFreeCluster(pIoman); - FF_putFatEntry(pIoman, CurrentCluster, NextCluster); - FF_putFatEntry(pIoman, NextCluster, 0xFFFFFFFF); + CurrentCluster = FF_FindEndOfChain(pIoman, DirCluster, &Error); + if(Error) { + FF_unlockFAT(pIoman); + return Error; + } + + NextCluster = FF_FindFreeCluster(pIoman, &Error); + if(Error) { + FF_unlockFAT(pIoman); + return Error; + } + + Error = FF_putFatEntry(pIoman, CurrentCluster, NextCluster); + if(Error) { + FF_unlockFAT(pIoman); + return Error; + } + + Error = FF_putFatEntry(pIoman, NextCluster, 0xFFFFFFFF); + if(Error) { + FF_unlockFAT(pIoman); + return Error; + } } FF_unlockFAT(pIoman); - FF_ClearCluster(pIoman, NextCluster); - FF_DecreaseFreeClusters(pIoman, 1); + Error = FF_ClearCluster(pIoman, NextCluster); + if(Error) { + FF_unlockFAT(pIoman); + return Error; + } + + Error = FF_DecreaseFreeClusters(pIoman, 1); + if(Error) { + FF_unlockFAT(pIoman); + return Error; + } return FF_ERR_NONE; } -static void FF_MakeNameCompliant(FF_T_INT8 *Name) { +#ifdef FF_UNICODE_SUPPORT +static void FF_MakeNameCompliant(FF_T_WCHAR *Name) { +#else +static void FF_MakeNameCompliant(FF_T_UINT8 *Name) { +#endif if((FF_T_UINT8) Name[0] == 0xE5) { // Support Japanese KANJI symbol. Name[0] = 0x05; @@ -1531,7 +2258,7 @@ static void FF_MakeNameCompliant(FF_T_INT8 *Name) { if(*Name < 0x20 || *Name == 0x7F || *Name == 0x22 || *Name == 0x7C) { // Leave all extended chars as they are. *Name = '_'; } - if(*Name >= 0x2A && *Name <= 0x2F && *Name != 0x2B && *Name != 0x2E) { + if(*Name >= 0x2A && *Name <= 0x2F && *Name != 0x2B && *Name != 0x2E && *Name != 0x2D) { *Name = '_'; } if(*Name >= 0x3A && *Name <= 0x3F) { @@ -1544,23 +2271,43 @@ static void FF_MakeNameCompliant(FF_T_INT8 *Name) { } } -FF_T_SINT8 FF_CreateDirent(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent) { +FF_ERROR FF_CreateDirent(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent) { FF_T_UINT8 EntryBuffer[32]; +#ifdef FF_UNICODE_SUPPORT + FF_T_UINT16 NameLen = (FF_T_UINT16) wcslen(pDirent->FileName); +#else FF_T_UINT16 NameLen = (FF_T_UINT16) strlen(pDirent->FileName); +#endif FF_T_UINT8 numLFNs = (FF_T_UINT8) (NameLen / 13); FF_T_SINT32 FreeEntry; - FF_T_SINT8 RetVal = 0; + FF_ERROR RetVal = FF_ERR_NONE; FF_T_UINT8 Entries; + + FF_FETCH_CONTEXT FetchContext; + #ifdef FF_LFN_SUPPORT FF_T_UINT8 CheckSum; #endif +#ifdef FF_UNICODE_SUPPORT + FF_T_WCHAR UTF16EntryBuffer[32]; +#if WCHAR_MAX > 0xFFFF + // Check that the filename won't exceed the max LFN length if converted to UTF-16. + /*if(FF_Utf32GetUtf16Len((FF_T_UINT32 *) pDirent->FileName) > FF_MAX_FILENAME) { + return FF_ERR_UNICODE_CONVERSION_EXCEEDED; + }*/ +#endif + +#endif + +#ifdef FF_UNICODE_SUPPORT FF_MakeNameCompliant(pDirent->FileName); // Ensure we don't break the Dir tables. +#else + FF_MakeNameCompliant((FF_T_UINT8 *)pDirent->FileName); // Ensure we don't break the Dir tables. +#endif memset(EntryBuffer, 0, 32); - - if(NameLen % 13) { numLFNs ++; } @@ -1576,10 +2323,18 @@ FF_T_SINT8 FF_CreateDirent(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_DIRENT * FF_lockDIR(pIoman); { if((FreeEntry = FF_FindFreeDirent(pIoman, DirCluster, Entries)) >= 0) { +#ifdef FF_UNICODE_SUPPORT + //FF_cstrntowcs(UTF16EntryBuffer, (FF_T_INT8 *) EntryBuffer, 32); + RetVal = FF_CreateShortName(pIoman, DirCluster, UTF16EntryBuffer, pDirent->FileName); +#else RetVal = FF_CreateShortName(pIoman, DirCluster, (FF_T_INT8 *) EntryBuffer, pDirent->FileName); +#endif - if(!RetVal) { + //if(!RetVal) { #ifdef FF_LFN_SUPPORT +#ifdef FF_UNICODE_SUPPORT + FF_wcsntocstr((FF_T_INT8 *) EntryBuffer, UTF16EntryBuffer, 11); +#endif CheckSum = FF_CreateChkSum(EntryBuffer); FF_CreateLFNs(pIoman, DirCluster, pDirent->FileName, CheckSum, (FF_T_UINT16) FreeEntry); #else @@ -1598,10 +2353,24 @@ FF_T_SINT8 FF_CreateDirent(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_DIRENT * FF_putShort(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_LOW), (FF_T_UINT16)(pDirent->ObjectCluster)); FF_putLong(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_FILESIZE), pDirent->Filesize); - FF_PushEntry(pIoman, DirCluster, (FF_T_UINT16) (FreeEntry + numLFNs), EntryBuffer); - } + RetVal = FF_InitEntryFetch(pIoman, DirCluster, &FetchContext); + if(RetVal) { + FF_unlockDIR(pIoman); + return RetVal; + } + RetVal = FF_PushEntryWithContext(pIoman, (FF_T_UINT16) (FreeEntry + numLFNs), &FetchContext, EntryBuffer); + FF_CleanupEntryFetch(pIoman, &FetchContext); + if(RetVal) { + FF_unlockDIR(pIoman); + return RetVal; + } + /*} else { + FF_unlockDIR(pIoman); + return RetVal; + }*/ }else { - RetVal = (FF_T_SINT8) FreeEntry; + FF_unlockDIR(pIoman); + return FreeEntry; } } FF_unlockDIR(pIoman); @@ -1614,19 +2383,36 @@ FF_T_SINT8 FF_CreateDirent(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_DIRENT * pDirent->CurrentItem = (FF_T_UINT16) (FreeEntry + numLFNs); } - return 0; + return FF_ERR_NONE; } -FF_T_UINT32 FF_CreateFile(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *FileName, FF_DIRENT *pDirent) { - FF_DIRENT MyFile; + +#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_DIRENT MyFile; + *pError = FF_ERR_NONE; +#ifdef FF_UNICODE_SUPPORT + wcsncpy(MyFile.FileName, FileName, FF_MAX_FILENAME); +#else strncpy(MyFile.FileName, FileName, FF_MAX_FILENAME); +#endif MyFile.Attrib = 0x00; MyFile.Filesize = 0; - MyFile.ObjectCluster = FF_CreateClusterChain(pIoman); + MyFile.ObjectCluster = FF_CreateClusterChain(pIoman, pError); + if(*pError) { + FF_UnlinkClusterChain(pIoman, MyFile.ObjectCluster, 0); + FF_FlushCache(pIoman); + return 0; + } MyFile.CurrentItem = 0; - if(FF_CreateDirent(pIoman, DirCluster, &MyFile)) { + *pError = FF_CreateDirent(pIoman, DirCluster, &MyFile); + + if(*pError) { FF_UnlinkClusterChain(pIoman, MyFile.ObjectCluster, 0); FF_FlushCache(pIoman); return 0; @@ -1653,20 +2439,34 @@ FF_T_UINT32 FF_CreateFile(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *F * @return FF_ERR_DIR_INVALID_PATH * @return FF_ERR_NONE on success. **/ +#ifdef FF_UNICODE_SUPPORT +FF_ERROR FF_MkDir(FF_IOMAN *pIoman, const FF_T_WCHAR *Path) { +#else FF_ERROR FF_MkDir(FF_IOMAN *pIoman, const FF_T_INT8 *Path) { +#endif FF_DIRENT MyDir; FF_T_UINT32 DirCluster; +#ifdef FF_UNICODE_SUPPORT + FF_T_WCHAR DirName[FF_MAX_FILENAME]; +#else FF_T_INT8 DirName[FF_MAX_FILENAME]; +#endif FF_T_UINT8 EntryBuffer[32]; FF_T_UINT32 DotDotCluster; FF_T_UINT16 i; - FF_T_SINT8 RetVal = 0; + FF_ERROR Error = FF_ERR_NONE; + + FF_FETCH_CONTEXT FetchContext; if(!pIoman) { return FF_ERR_NULL_POINTER; } +#ifdef FF_UNICODE_SUPPORT + i = (FF_T_UINT16) wcslen(Path); +#else i = (FF_T_UINT16) strlen(Path); +#endif while(i != 0) { if(Path[i] == '\\' || Path[i] == '/') { @@ -1675,35 +2475,60 @@ FF_ERROR FF_MkDir(FF_IOMAN *pIoman, const FF_T_INT8 *Path) { i--; } +#ifdef FF_UNICODE_SUPPORT + wcsncpy(DirName, (Path + i + 1), FF_MAX_FILENAME); +#else strncpy(DirName, (Path + i + 1), FF_MAX_FILENAME); +#endif if(i == 0) { i = 1; } - DirCluster = FF_FindDir(pIoman, Path, i); + DirCluster = FF_FindDir(pIoman, Path, i, &Error); + + if(Error) { + return Error; + } if(DirCluster) { - - /*if(!FF_FindEntry(pIoman, DirCluster, DirName, &MyDir, FF_TRUE)) { - return FF_ERR_DIR_OBJECT_EXISTS; - }*/ - if(FF_FindEntryInDir(pIoman, DirCluster, DirName, 0x00, &MyDir)) { + if(FF_FindEntryInDir(pIoman, DirCluster, DirName, 0x00, &MyDir, &Error)) { return FF_ERR_DIR_OBJECT_EXISTS; } + if(Error && Error != FF_ERR_DIR_END_OF_DIR) { + return Error; + } + +#ifdef FF_UNICODE_SUPPORT + wcsncpy(MyDir.FileName, DirName, FF_MAX_FILENAME); +#else strncpy(MyDir.FileName, DirName, FF_MAX_FILENAME); +#endif MyDir.Filesize = 0; MyDir.Attrib = FF_FAT_ATTR_DIR; - MyDir.ObjectCluster = FF_CreateClusterChain(pIoman); - FF_ClearCluster(pIoman, MyDir.ObjectCluster); + MyDir.ObjectCluster = FF_CreateClusterChain(pIoman, &Error); + if(Error) { + return Error; + } + if(MyDir.ObjectCluster) { + Error = FF_ClearCluster(pIoman, MyDir.ObjectCluster); + if(Error) { + FF_UnlinkClusterChain(pIoman, MyDir.ObjectCluster, 0); + FF_FlushCache(pIoman); + return Error; + } + } else { + // Couldn't allocate any space for the dir! + return FF_ERR_DIR_EXTEND_FAILED; + } - RetVal = FF_CreateDirent(pIoman, DirCluster, &MyDir); + Error = FF_CreateDirent(pIoman, DirCluster, &MyDir); - if(RetVal) { + if(Error) { FF_UnlinkClusterChain(pIoman, MyDir.ObjectCluster, 0); FF_FlushCache(pIoman); - return RetVal; + return Error; } memset(EntryBuffer, 0, 32); @@ -1716,7 +2541,20 @@ FF_ERROR FF_MkDir(FF_IOMAN *pIoman, const FF_T_INT8 *Path) { FF_putShort(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_LOW), (FF_T_UINT16) MyDir.ObjectCluster); FF_putLong(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_FILESIZE), 0); - FF_PushEntry(pIoman, MyDir.ObjectCluster, 0, EntryBuffer); + Error = FF_InitEntryFetch(pIoman, MyDir.ObjectCluster, &FetchContext); + if(Error) { + FF_UnlinkClusterChain(pIoman, MyDir.ObjectCluster, 0); + FF_FlushCache(pIoman); + return Error; + } + + Error = FF_PushEntryWithContext(pIoman, 0, &FetchContext, EntryBuffer); + if(Error) { + FF_UnlinkClusterChain(pIoman, MyDir.ObjectCluster, 0); + FF_FlushCache(pIoman); + FF_CleanupEntryFetch(pIoman, &FetchContext); + return Error; + } memset(EntryBuffer, 0, 32); EntryBuffer[0] = '.'; @@ -1736,8 +2574,16 @@ FF_ERROR FF_MkDir(FF_IOMAN *pIoman, const FF_T_INT8 *Path) { FF_putShort(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_LOW), (FF_T_UINT16) DotDotCluster); FF_putLong(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_FILESIZE), 0); - FF_PushEntry(pIoman, MyDir.ObjectCluster, 1, EntryBuffer); - + //FF_PushEntry(pIoman, MyDir.ObjectCluster, 1, EntryBuffer); + Error = FF_PushEntryWithContext(pIoman, 1, &FetchContext, EntryBuffer); + if(Error) { + FF_UnlinkClusterChain(pIoman, MyDir.ObjectCluster, 0); + FF_FlushCache(pIoman); + FF_CleanupEntryFetch(pIoman, &FetchContext); + return Error; + } + FF_CleanupEntryFetch(pIoman, &FetchContext); + FF_FlushCache(pIoman); // Ensure dir was flushed to the disk! return FF_ERR_NONE; @@ -1748,24 +2594,32 @@ FF_ERROR FF_MkDir(FF_IOMAN *pIoman, const FF_T_INT8 *Path) { -void FF_RmLFNs(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT16 DirEntry) { +FF_ERROR FF_RmLFNs(FF_IOMAN *pIoman, FF_T_UINT16 usDirEntry, FF_FETCH_CONTEXT *pContext) { + FF_ERROR Error; FF_T_UINT8 EntryBuffer[32]; - DirEntry--; + usDirEntry--; do { - FF_FetchEntry(pIoman, DirCluster, DirEntry, EntryBuffer); + Error = FF_FetchEntryWithContext(pIoman, usDirEntry, pContext, EntryBuffer); + if(Error) { + return Error; + } if(FF_getChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB)) == FF_FAT_ATTR_LFN) { FF_putChar(EntryBuffer, (FF_T_UINT16) 0, (FF_T_UINT8) 0xE5); - FF_PushEntry(pIoman, DirCluster, DirEntry, EntryBuffer); + Error = FF_PushEntryWithContext(pIoman, usDirEntry, pContext, EntryBuffer); + if(Error) { + return Error; + } } - if(DirEntry == 0) { + if(usDirEntry == 0) { break; } - DirEntry--; + usDirEntry--; }while(FF_getChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB)) == FF_FAT_ATTR_LFN); + return FF_ERR_NONE; } diff --git a/reactos/lib/3rdparty/fullfat/ff_dir.h b/reactos/lib/3rdparty/fullfat/ff_dir.h index 41eb7278f8d..6c99b7279c5 100644 --- a/reactos/lib/3rdparty/fullfat/ff_dir.h +++ b/reactos/lib/3rdparty/fullfat/ff_dir.h @@ -52,54 +52,118 @@ #include typedef struct { - FF_T_INT8 FileName[FF_MAX_FILENAME]; - FF_T_UINT8 Attrib; + FF_T_UINT32 ulChainLength; + 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 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 FF_SYSTEMTIME CreateTime; ///< Date and Time Created. FF_SYSTEMTIME ModifiedTime; ///< Date and Time Modified. FF_SYSTEMTIME AccessedTime; ///< Date of Last Access. #endif - //---- Book Keeping for FF_Find Functions - FF_T_UINT16 CurrentItem; - FF_T_UINT32 DirCluster; - FF_T_UINT32 CurrentCluster; - FF_T_UINT32 AddrCurrentCluster; - //FF_T_UINT8 NumLFNs; +#ifdef FF_FINDAPI_ALLOW_WILDCARDS +#ifdef FF_UNICODE_SUPPORT + FF_T_WCHAR szWildCard[FF_MAX_FILENAME]; +#else + FF_T_INT8 szWildCard[FF_MAX_FILENAME]; +#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_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); -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); -void FF_SetDirHashed(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster); +// PUBLIC API +#ifdef FF_UNICODE_SUPPORT +FF_ERROR FF_FindFirst (FF_IOMAN *pIoman, FF_DIRENT *pDirent, const FF_T_WCHAR *path); +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 diff --git a/reactos/lib/3rdparty/fullfat/ff_error.c b/reactos/lib/3rdparty/fullfat/ff_error.c index 483bf964ce3..787c8769aaa 100644 --- a/reactos/lib/3rdparty/fullfat/ff_error.c +++ b/reactos/lib/3rdparty/fullfat/ff_error.c @@ -56,7 +56,7 @@ const struct _FFERRTAB {"Not enough memory (malloc() returned NULL).", FF_ERR_NOT_ENOUGH_MEMORY}, {"Device Driver returned a FATAL error!.", FF_ERR_DEVICE_DRIVER_FAILED}, {"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}, {"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}, @@ -65,6 +65,7 @@ const struct _FFERRTAB {"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 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}, {"The specified file could not be found.", FF_ERR_FILE_NOT_FOUND}, {"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}, {"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}, + {"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}, }; /** diff --git a/reactos/lib/3rdparty/fullfat/ff_fat.c b/reactos/lib/3rdparty/fullfat/ff_fat.c index 66769e56af7..fb5ac824033 100644 --- a/reactos/lib/3rdparty/fullfat/ff_fat.c +++ b/reactos/lib/3rdparty/fullfat/ff_fat.c @@ -110,7 +110,7 @@ FF_T_UINT32 FF_LBA2Cluster(FF_IOMAN *pIoman, FF_T_UINT32 Address) { /** * @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_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); { 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)); } @@ -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); { if(!pBuffer) { - return FF_ERR_DEVICE_DRIVER_FAILED; + *pError = FF_ERR_DEVICE_DRIVER_FAILED; + return 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); { if(!pBuffer) { - return FF_ERR_DEVICE_DRIVER_FAILED; + *pError = FF_ERR_DEVICE_DRIVER_FAILED; + return 0; } 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; } -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_T_UINT16 i; FF_T_UINT32 BaseLBA; - FF_T_SINT8 RetVal = 0; BaseLBA = FF_Cluster2LBA(pIoman, nCluster); 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++) { pBuffer = FF_GetBuffer(pIoman, BaseLBA++, FF_MODE_WRITE); { - if(pBuffer) { - memset(pBuffer->pBuffer, 0x00, 512); - } else { - RetVal = FF_ERR_DEVICE_DRIVER_FAILED; + if(!pBuffer) { + return FF_ERR_DEVICE_DRIVER_FAILED; } + memset(pBuffer->pBuffer, 0x00, 512); } 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 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 fatEntry = Start, currentCluster = Start; + *pError = FF_ERR_NONE; + for(i = 0; i < Count; i++) { - fatEntry = FF_getFatEntry(pIoman, currentCluster); - if(fatEntry == (FF_T_UINT32) FF_ERR_DEVICE_DRIVER_FAILED) { + fatEntry = FF_getFatEntry(pIoman, currentCluster, pError); + if(*pError) { return 0; } @@ -264,13 +267,14 @@ FF_T_UINT32 FF_TraverseFAT(FF_IOMAN *pIoman, FF_T_UINT32 Start, FF_T_UINT32 Coun 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; + *pError = FF_ERR_NONE; while(!FF_isEndOfChain(pIoman, fatEntry)) { - fatEntry = FF_getFatEntry(pIoman, currentCluster); - if(fatEntry == (FF_T_UINT32) FF_ERR_DEVICE_DRIVER_FAILED) { + fatEntry = FF_getFatEntry(pIoman, currentCluster, pError); + if(*pError) { 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 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_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); - 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. **/ #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 fatEntry; + *pError = FF_ERR_NONE; + 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) { pIoman->pPartition->LastFreeCluster = nCluster; return nCluster; @@ -469,7 +478,7 @@ FF_T_UINT32 FF_FindFreeClusterOLD(FF_IOMAN *pIoman) { } #endif -FF_T_UINT32 FF_FindFreeCluster(FF_IOMAN *pIoman) { +FF_T_UINT32 FF_FindFreeCluster(FF_IOMAN *pIoman, FF_ERROR *pError) { FF_BUFFER *pBuffer; FF_T_UINT32 i, x, nCluster = pIoman->pPartition->LastFreeCluster; FF_T_UINT32 FatOffset; @@ -478,9 +487,11 @@ FF_T_UINT32 FF_FindFreeCluster(FF_IOMAN *pIoman) { FF_T_UINT32 EntriesPerSector; FF_T_UINT32 FatEntry = 1; + *pError = FF_ERR_NONE; + #ifdef FF_FAT12_SUPPORT 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 @@ -491,15 +502,20 @@ FF_T_UINT32 FF_FindFreeCluster(FF_IOMAN *pIoman) { EntriesPerSector = pIoman->BlkSize / 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); for(i = FatSector; i < pIoman->pPartition->SectorsPerFAT; i++) { pBuffer = FF_GetBuffer(pIoman, pIoman->pPartition->FatBeginLBA + i, FF_MODE_READ); { - // HT addition: don't use non-existing clusters - if (nCluster >= pIoman->pPartition->NumClusters) { - FF_ReleaseBuffer(pIoman, pBuffer); + if(!pBuffer) { + *pError = FF_ERR_DEVICE_DRIVER_FAILED; return 0; } for(x = nCluster % EntriesPerSector; x < EntriesPerSector; x++) { @@ -533,24 +549,54 @@ FF_T_UINT32 FF_FindFreeCluster(FF_IOMAN *pIoman) { * @private * @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_ERROR Error; + *pError = FF_ERR_NONE; + FF_lockFAT(pIoman); { - iStartCluster = FF_FindFreeCluster(pIoman); - FF_putFatEntry(pIoman, iStartCluster, 0xFFFFFFFF); // Mark the cluster as EOC + iStartCluster = FF_FindFreeCluster(pIoman, &Error); + 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); + + if(iStartCluster) { + Error = FF_DecreaseFreeClusters(pIoman, 1); + if(Error) { + *pError = Error; + return 0; + } + } + 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; + + *pError = FF_ERR_NONE; FF_lockFAT(pIoman); { 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++; } 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. * **/ -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 currentCluster, chainLength = 0; FF_T_UINT32 iLen = 0; FF_T_UINT32 lastFree = StartCluster; /* HT addition : reset LastFreeCluster */ + FF_ERROR Error; fatEntry = StartCluster; @@ -626,8 +673,15 @@ FF_T_SINT8 FF_UnlinkClusterChain(FF_IOMAN *pIoman, FF_T_UINT32 StartCluster, FF_ currentCluster = StartCluster; fatEntry = currentCluster; do { - fatEntry = FF_getFatEntry(pIoman, fatEntry); - FF_putFatEntry(pIoman, currentCluster, 0x00000000); + fatEntry = FF_getFatEntry(pIoman, fatEntry, &Error); + if(Error) { + return Error; + } + Error = FF_putFatEntry(pIoman, currentCluster, 0x00000000); + if(Error) { + return Error; + } + if (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) { pIoman->pPartition->LastFreeCluster = lastFree; } - FF_IncreaseFreeClusters(pIoman, iLen); + Error = FF_IncreaseFreeClusters(pIoman, iLen); + if(Error) { + return Error; + } } else { // Truncation - This is quite hard, because we can only do it backwards. do { - fatEntry = FF_getFatEntry(pIoman, fatEntry); + fatEntry = FF_getFatEntry(pIoman, fatEntry, &Error); + if(Error) { + return Error; + } chainLength++; }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 -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 TotalClusters = pIoman->pPartition->DataSectors / pIoman->pPartition->SectorsPerCluster; FF_T_UINT32 FatEntry; FF_T_UINT32 FreeClusters = 0; + *pError = FF_ERR_NONE; + for(i = 0; i < TotalClusters; i++) { - FatEntry = FF_getFatEntry(pIoman, i); + FatEntry = FF_getFatEntry(pIoman, i, pError); + if(*pError) { + return 0; + } if(!FatEntry) { FreeClusters++; } @@ -668,7 +733,7 @@ FF_T_UINT32 FF_CountFreeClustersOLD(FF_IOMAN *pIoman) { #endif -FF_T_UINT32 FF_CountFreeClusters(FF_IOMAN *pIoman) { +FF_T_UINT32 FF_CountFreeClusters(FF_IOMAN *pIoman, FF_ERROR *pError) { FF_BUFFER *pBuffer; FF_T_UINT32 i, x, nCluster = 0; FF_T_UINT32 FatOffset; @@ -678,9 +743,14 @@ FF_T_UINT32 FF_CountFreeClusters(FF_IOMAN *pIoman) { FF_T_UINT32 FatEntry = 1; FF_T_UINT32 FreeClusters = 0; + *pError = FF_ERR_NONE; + #ifdef FF_FAT12_SUPPORT 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 @@ -697,6 +767,10 @@ FF_T_UINT32 FF_CountFreeClusters(FF_IOMAN *pIoman) { for(i = 0; i < pIoman->pPartition->SectorsPerFAT; i++) { 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++) { if(pIoman->pPartition->Type == FF_T_FAT32) { FatOffset = x * 4; @@ -722,15 +796,23 @@ FF_T_UINT32 FF_CountFreeClusters(FF_IOMAN *pIoman) { } #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_UINT64 FreeSize; + FF_ERROR Error; if(pIoman) { FF_lockFAT(pIoman); { 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; } diff --git a/reactos/lib/3rdparty/fullfat/ff_file.c b/reactos/lib/3rdparty/fullfat/ff_file.c index cd29e31562b..716467a7833 100644 --- a/reactos/lib/3rdparty/fullfat/ff_file.c +++ b/reactos/lib/3rdparty/fullfat/ff_file.c @@ -42,6 +42,11 @@ #include "ff_file.h" #include "ff_string.h" +#include "ff_config.h" + +#ifdef FF_UNICODE_SUPPORT +#include +#endif /** * @public @@ -143,13 +148,22 @@ FF_T_UINT8 FF_GetModeBits(FF_T_INT8 *Mode) { * @return NULL pointer on Error, in which case pError should be checked for more information. * @return pError can be: **/ +#ifdef FF_UNICODE_SUPPORT +FF_FILE *FF_Open(FF_IOMAN *pIoman, const FF_T_WCHAR *path, FF_T_UINT8 Mode, FF_ERROR *pError) { +#else FF_FILE *FF_Open(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT8 Mode, FF_ERROR *pError) { +#endif FF_FILE *pFile; FF_FILE *pFileChain; FF_DIRENT Object; FF_T_UINT32 DirCluster, FileCluster; FF_T_UINT32 nBytesPerCluster; +#ifdef FF_UNICODE_SUPPORT + FF_T_WCHAR filename[FF_MAX_FILENAME]; +#else FF_T_INT8 filename[FF_MAX_FILENAME]; +#endif + FF_ERROR Error; FF_T_UINT16 i; @@ -174,7 +188,11 @@ FF_FILE *FF_Open(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT8 Mode, FF_ER // Get the Mode Bits. pFile->Mode = Mode; +#ifdef FF_UNICODE_SUPPORT + i = (FF_T_UINT16) wcslen(path); +#else i = (FF_T_UINT16) strlen(path); +#endif while(i != 0) { if(path[i] == '\\' || path[i] == '/') { @@ -182,29 +200,45 @@ FF_FILE *FF_Open(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT8 Mode, FF_ER } i--; } - +#ifdef FF_UNICODE_SUPPORT + wcsncpy(filename, (path + i + 1), FF_MAX_FILENAME); +#else strncpy(filename, (path + i + 1), FF_MAX_FILENAME); +#endif if(i == 0) { i = 1; } - DirCluster = FF_FindDir(pIoman, path, i); + DirCluster = FF_FindDir(pIoman, path, i, &Error); + if(Error) { + if(pError) { + *pError = Error; + } + FF_FREE(pFile); + return (FF_FILE *) NULL; + } if(DirCluster) { - //RetVal = //FF_FindEntry(pIoman, DirCluster, filename, &Object, FF_TRUE); - //if(RetVal >= 0) { - //FileCluster = Object.ObjectCluster;//FF_FindEntryInDir(pIoman, DirCluster, filename, 0x00, &Object); - //} else { - // FileCluster = 0; - //} - FileCluster = FF_FindEntryInDir(pIoman, DirCluster, filename, 0x00, &Object); + FileCluster = FF_FindEntryInDir(pIoman, DirCluster, filename, 0x00, &Object, &Error); + if(Error) { + if(pError) { + *pError = Error; + } + FF_FREE(pFile); + return (FF_FILE *) NULL; + } if(!FileCluster) { // If 0 was returned, it might be because the file has no allocated cluster +#ifdef FF_UNICODE_SUPPORT + if(wcslen(filename) == wcslen(Object.FileName)) { + if(Object.Filesize == 0 && FF_strmatch(filename, Object.FileName, (FF_T_UINT16) wcslen(filename)) == FF_TRUE) { +#else if(strlen(filename) == strlen(Object.FileName)) { if(Object.Filesize == 0 && FF_strmatch(filename, Object.FileName, (FF_T_UINT16) strlen(filename)) == FF_TRUE) { +#endif // The file really was found! FileCluster = 1; } @@ -213,7 +247,14 @@ FF_FILE *FF_Open(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT8 Mode, FF_ER if(!FileCluster) { if((pFile->Mode & FF_MODE_CREATE)) { - FileCluster = FF_CreateFile(pIoman, DirCluster, filename, &Object); + FileCluster = FF_CreateFile(pIoman, DirCluster, filename, &Object, &Error); + if(Error) { + if(pError) { + *pError = Error; + } + FF_FREE(pFile); + return (FF_FILE *) NULL; + } Object.CurrentItem += 1; } } @@ -318,7 +359,11 @@ FF_FILE *FF_Open(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT8 Mode, FF_ER * @param pIoman FF_IOMAN object returned from the FF_CreateIOMAN() function. * **/ +#ifdef FF_UNICODE_SUPPORT +FF_T_BOOL FF_isDirEmpty(FF_IOMAN *pIoman, const FF_T_WCHAR *Path) { +#else FF_T_BOOL FF_isDirEmpty(FF_IOMAN *pIoman, const FF_T_INT8 *Path) { +#endif FF_DIRENT MyDir; FF_ERROR RetVal = FF_ERR_NONE; @@ -340,11 +385,16 @@ FF_T_BOOL FF_isDirEmpty(FF_IOMAN *pIoman, const FF_T_INT8 *Path) { return FF_TRUE; } +#ifdef FF_UNICODE_SUPPORT +FF_ERROR FF_RmDir(FF_IOMAN *pIoman, const FF_T_WCHAR *path) { +#else FF_ERROR FF_RmDir(FF_IOMAN *pIoman, const FF_T_INT8 *path) { - FF_FILE *pFile; - FF_ERROR Error = FF_ERR_NONE; - FF_T_UINT8 EntryBuffer[32]; - FF_T_SINT8 RetVal = FF_ERR_NONE; +#endif + FF_FILE *pFile; + FF_ERROR Error = FF_ERR_NONE; + FF_T_UINT8 EntryBuffer[32]; + FF_FETCH_CONTEXT FetchContext; + FF_T_SINT8 RetVal = FF_ERR_NONE; #ifdef FF_PATH_CACHE FF_T_UINT32 i; #endif @@ -366,20 +416,57 @@ FF_ERROR FF_RmDir(FF_IOMAN *pIoman, const FF_T_INT8 *path) { if(FF_isDirEmpty(pIoman, path)) { FF_lockFAT(pIoman); { - FF_UnlinkClusterChain(pIoman, pFile->ObjectCluster, 0); // 0 to delete the entire chain! + Error = FF_UnlinkClusterChain(pIoman, pFile->ObjectCluster, 0); // 0 to delete the entire chain! } FF_unlockFAT(pIoman); + + if(Error) { + FF_unlockDIR(pIoman); + FF_Close(pFile); + return Error; + } + + // Initialise the dirent Fetch Context object for faster removal of dirents. + + Error = FF_InitEntryFetch(pIoman, pFile->DirCluster, &FetchContext); + if(Error) { + FF_unlockDIR(pIoman); + FF_Close(pFile); + return Error; + } // Edit the Directory Entry! (So it appears as deleted); - FF_RmLFNs(pIoman, pFile->DirCluster, pFile->DirEntry); - FF_FetchEntry(pIoman, pFile->DirCluster, pFile->DirEntry, EntryBuffer); + Error = FF_RmLFNs(pIoman, pFile->DirEntry, &FetchContext); + if(Error) { + FF_CleanupEntryFetch(pIoman, &FetchContext); + FF_unlockDIR(pIoman); + FF_Close(pFile); + return Error; + } + Error = FF_FetchEntryWithContext(pIoman, pFile->DirEntry, &FetchContext, EntryBuffer); + if(Error) { + FF_CleanupEntryFetch(pIoman, &FetchContext); + FF_unlockDIR(pIoman); + FF_Close(pFile); + return Error; + } EntryBuffer[0] = 0xE5; - FF_PushEntry(pIoman, pFile->DirCluster, pFile->DirEntry, EntryBuffer); + Error = FF_PushEntryWithContext(pIoman, pFile->DirEntry, &FetchContext, EntryBuffer); + if(Error) { + FF_CleanupEntryFetch(pIoman, &FetchContext); + FF_unlockDIR(pIoman); + FF_Close(pFile); + return Error; + } #ifdef FF_PATH_CACHE FF_PendSemaphore(pIoman->pSemaphore); // Thread safety on shared object! { for(i = 0; i < FF_PATH_CACHE_DEPTH; i++) { +#ifdef FF_UNICODE_SUPPORT + if(FF_strmatch(pIoman->pPartition->PathCache[i].Path, path, (FF_T_UINT16)wcslen(path))) { +#else if(FF_strmatch(pIoman->pPartition->PathCache[i].Path, path, (FF_T_UINT16)strlen(path))) { +#endif pIoman->pPartition->PathCache[i].Path[0] = '\0'; pIoman->pPartition->PathCache[i].DirCluster = 0; FF_ReleaseSemaphore(pIoman->pSemaphore); @@ -389,24 +476,46 @@ FF_ERROR FF_RmDir(FF_IOMAN *pIoman, const FF_T_INT8 *path) { FF_ReleaseSemaphore(pIoman->pSemaphore); #endif - FF_IncreaseFreeClusters(pIoman, pFile->iChainLength); + Error = FF_IncreaseFreeClusters(pIoman, pFile->iChainLength); + if(Error) { + FF_CleanupEntryFetch(pIoman, &FetchContext); + FF_unlockDIR(pIoman); + FF_Close(pFile); + return Error; + } - FF_FlushCache(pIoman); + FF_CleanupEntryFetch(pIoman, &FetchContext); + + Error = FF_FlushCache(pIoman); + if(Error) { + FF_unlockDIR(pIoman); + FF_Close(pFile); + return Error; + } } else { RetVal = FF_ERR_DIR_NOT_EMPTY; } } FF_unlockDIR(pIoman); - - FF_Close(pFile); // Free the file pointer resources + Error = FF_Close(pFile); // Free the file pointer resources + + if(Error) { + return Error; + } + // File is now lost! return RetVal; } +#ifdef FF_UNICODE_SUPPORT +FF_ERROR FF_RmFile(FF_IOMAN *pIoman, const FF_T_WCHAR *path) { +#else FF_ERROR FF_RmFile(FF_IOMAN *pIoman, const FF_T_INT8 *path) { +#endif FF_FILE *pFile; - FF_ERROR Error = 0; + FF_ERROR Error = FF_ERR_NONE; FF_T_UINT8 EntryBuffer[32]; + FF_FETCH_CONTEXT FetchContext; pFile = FF_Open(pIoman, path, FF_MODE_READ, &Error); @@ -416,26 +525,64 @@ FF_ERROR FF_RmFile(FF_IOMAN *pIoman, const FF_T_INT8 *path) { pFile->FileDeleted = FF_TRUE; - FF_lockFAT(pIoman); // Lock the FAT so its thread-safe. - { - FF_UnlinkClusterChain(pIoman, pFile->ObjectCluster, 0); // 0 to delete the entire chain! + if(pFile->ObjectCluster) { // Ensure there is actually a cluster chain to delete! + FF_lockFAT(pIoman); // Lock the FAT so its thread-safe. + { + Error = FF_UnlinkClusterChain(pIoman, pFile->ObjectCluster, 0); // 0 to delete the entire chain! + } + FF_unlockFAT(pIoman); + + if(Error) { + FF_Close(pFile); + return Error; + } } - FF_unlockFAT(pIoman); // Edit the Directory Entry! (So it appears as deleted); FF_lockDIR(pIoman); { - FF_RmLFNs(pIoman, pFile->DirCluster, pFile->DirEntry); - FF_FetchEntry(pIoman, pFile->DirCluster, pFile->DirEntry, EntryBuffer); + Error = FF_InitEntryFetch(pIoman, pFile->DirCluster, &FetchContext); + if(Error) { + FF_unlockDIR(pIoman); + FF_Close(pFile); + return Error; + } + Error = FF_RmLFNs(pIoman, pFile->DirEntry, &FetchContext); + if(Error) { + FF_CleanupEntryFetch(pIoman, &FetchContext); + FF_unlockDIR(pIoman); + FF_Close(pFile); + return Error; + } + Error = FF_FetchEntryWithContext(pIoman, pFile->DirEntry, &FetchContext, EntryBuffer); + if(Error) { + FF_CleanupEntryFetch(pIoman, &FetchContext); + FF_unlockDIR(pIoman); + FF_Close(pFile); + return Error; + } EntryBuffer[0] = 0xE5; - FF_PushEntry(pIoman, pFile->DirCluster, pFile->DirEntry, EntryBuffer); + + Error = FF_PushEntryWithContext(pIoman, pFile->DirEntry, &FetchContext, EntryBuffer); + if(Error) { + FF_CleanupEntryFetch(pIoman, &FetchContext); + FF_unlockDIR(pIoman); + FF_Close(pFile); + return Error; + } + + FF_CleanupEntryFetch(pIoman, &FetchContext); } FF_unlockDIR(pIoman); - FF_FlushCache(pIoman); + Error = FF_FlushCache(pIoman); + if(Error) { + FF_Close(pFile); + return Error; + } - FF_Close(pFile); // Free the file pointer resources - return 0; + Error = FF_Close(pFile); // Free the file pointer resources + return Error; } /** @@ -453,13 +600,18 @@ FF_ERROR FF_RmFile(FF_IOMAN *pIoman, const FF_T_INT8 *path) { * @return FF_ERR_FILE_SOURCE_NOT_FOUND if the source file was not found. * **/ +#ifdef FF_UNICODE_SUPPORT +FF_ERROR FF_Move(FF_IOMAN *pIoman, const FF_T_WCHAR *szSourceFile, const FF_T_WCHAR *szDestinationFile) { +#else FF_ERROR FF_Move(FF_IOMAN *pIoman, const FF_T_INT8 *szSourceFile, const FF_T_INT8 *szDestinationFile) { +#endif FF_ERROR Error; FF_FILE *pSrcFile, *pDestFile; FF_DIRENT MyFile; FF_T_UINT8 EntryBuffer[32]; FF_T_UINT16 i; FF_T_UINT32 DirCluster; + FF_FETCH_CONTEXT FetchContext; if(!pIoman) { return FF_ERR_NULL_POINTER; @@ -480,16 +632,34 @@ FF_ERROR FF_Move(FF_IOMAN *pIoman, const FF_T_INT8 *szSourceFile, const FF_T_INT pSrcFile = FF_Open(pIoman, szSourceFile, FF_MODE_DIR, &Error); } - if(pSrcFile) { + if(!pSrcFile) { + return Error; + } + if(pSrcFile) { // Create the new dirent. - FF_FetchEntry(pIoman, pSrcFile->DirCluster, pSrcFile->DirEntry, EntryBuffer); + Error = FF_InitEntryFetch(pIoman, pSrcFile->DirCluster, &FetchContext); + if(Error) { + FF_Close(pSrcFile); + return Error; + } + Error = FF_FetchEntryWithContext(pIoman, pSrcFile->DirEntry, &FetchContext, EntryBuffer); + if(Error) { + FF_Close(pSrcFile); + FF_CleanupEntryFetch(pIoman, &FetchContext); + return Error; + } + //FF_FetchEntry(pIoman, pSrcFile->DirCluster, pSrcFile->DirEntry, EntryBuffer); MyFile.Attrib = FF_getChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB)); MyFile.Filesize = pSrcFile->Filesize; MyFile.ObjectCluster = pSrcFile->ObjectCluster; MyFile.CurrentItem = 0; +#ifdef FF_UNICODE_SUPPORT + i = (FF_T_UINT16) wcslen(szDestinationFile); +#else i = (FF_T_UINT16) strlen(szDestinationFile); +#endif while(i != 0) { if(szDestinationFile[i] == '\\' || szDestinationFile[i] == '/') { @@ -498,30 +668,62 @@ FF_ERROR FF_Move(FF_IOMAN *pIoman, const FF_T_INT8 *szSourceFile, const FF_T_INT i--; } +#ifdef FF_UNICODE_SUPPORT + wcsncpy(MyFile.FileName, (szDestinationFile + i + 1), FF_MAX_FILENAME); +#else strncpy(MyFile.FileName, (szDestinationFile + i + 1), FF_MAX_FILENAME); +#endif if(i == 0) { i = 1; } - DirCluster = FF_FindDir(pIoman, szDestinationFile, i); + DirCluster = FF_FindDir(pIoman, szDestinationFile, i, &Error); + if(Error) { + FF_Close(pSrcFile); + FF_CleanupEntryFetch(pIoman, &FetchContext); + return Error; + } if(DirCluster) { // Destination Dir was found, we can now create the new entry. - if(FF_CreateDirent(pIoman, DirCluster, &MyFile)) { + Error = FF_CreateDirent(pIoman, DirCluster, &MyFile); + if(Error) { FF_Close(pSrcFile); - return FF_ERR_FILE_COULD_NOT_CREATE_DIRENT; // FAILED + FF_CleanupEntryFetch(pIoman, &FetchContext); + return Error; // FAILED } // Edit the Directory Entry! (So it appears as deleted); FF_lockDIR(pIoman); { - FF_RmLFNs(pIoman, pSrcFile->DirCluster, pSrcFile->DirEntry); - FF_FetchEntry(pIoman, pSrcFile->DirCluster, pSrcFile->DirEntry, EntryBuffer); + + Error = FF_RmLFNs(pIoman, pSrcFile->DirEntry, &FetchContext); + if(Error) { + FF_unlockDIR(pIoman); + FF_Close(pSrcFile); + FF_CleanupEntryFetch(pIoman, &FetchContext); + return Error; + } + Error = FF_FetchEntryWithContext(pIoman, pSrcFile->DirEntry, &FetchContext, EntryBuffer); + if(Error) { + FF_unlockDIR(pIoman); + FF_Close(pSrcFile); + FF_CleanupEntryFetch(pIoman, &FetchContext); + return Error; + } EntryBuffer[0] = 0xE5; - FF_PushEntry(pIoman, pSrcFile->DirCluster, pSrcFile->DirEntry, EntryBuffer); + //FF_PushEntry(pIoman, pSrcFile->DirCluster, pSrcFile->DirEntry, EntryBuffer); + Error = FF_PushEntryWithContext(pIoman, pSrcFile->DirEntry, &FetchContext, EntryBuffer); + if(Error) { + FF_unlockDIR(pIoman); + FF_Close(pSrcFile); + FF_CleanupEntryFetch(pIoman, &FetchContext); + return Error; + } + FF_CleanupEntryFetch(pIoman, &FetchContext); } FF_unlockDIR(pIoman); FF_Close(pSrcFile); @@ -560,14 +762,19 @@ FF_T_BOOL FF_isEOF(FF_FILE *pFile) { } } -static FF_T_UINT32 FF_GetSequentialClusters(FF_IOMAN *pIoman, FF_T_UINT32 StartCluster, FF_T_UINT32 Limit) { +static FF_T_UINT32 FF_GetSequentialClusters(FF_IOMAN *pIoman, FF_T_UINT32 StartCluster, FF_T_UINT32 Limit, FF_ERROR *pError) { FF_T_UINT32 CurrentCluster; FF_T_UINT32 NextCluster = StartCluster; FF_T_UINT32 i = 0; + *pError = FF_ERR_NONE; + do { CurrentCluster = NextCluster; - NextCluster = FF_getFatEntry(pIoman, CurrentCluster); + NextCluster = FF_getFatEntry(pIoman, CurrentCluster, pError); + if(*pError) { + return 0; + } if(NextCluster == (CurrentCluster + 1)) { i++; } else { @@ -584,48 +791,40 @@ static FF_T_UINT32 FF_GetSequentialClusters(FF_IOMAN *pIoman, FF_T_UINT32 StartC return i; } -static FF_T_SINT32 FF_ReadClusters(FF_FILE *pFile, FF_T_UINT32 Count, FF_T_UINT8 *buffer) { - FF_T_UINT32 Sectors; +static FF_ERROR FF_ReadClusters(FF_FILE *pFile, FF_T_UINT32 Count, FF_T_UINT8 *buffer) { + FF_T_UINT32 ulSectors; FF_T_UINT32 SequentialClusters = 0; FF_T_UINT32 nItemLBA; - FF_T_SINT32 RetVal; + FF_T_SINT32 slRetVal; + FF_ERROR Error; while(Count != 0) { if((Count - 1) > 0) { - SequentialClusters = FF_GetSequentialClusters(pFile->pIoman, pFile->AddrCurrentCluster, (Count - 1)); + SequentialClusters = FF_GetSequentialClusters(pFile->pIoman, pFile->AddrCurrentCluster, (Count - 1), &Error); + if(Error) { + return Error; + } } - Sectors = (SequentialClusters + 1) * pFile->pIoman->pPartition->SectorsPerCluster; + ulSectors = (SequentialClusters + 1) * pFile->pIoman->pPartition->SectorsPerCluster; nItemLBA = FF_Cluster2LBA(pFile->pIoman, pFile->AddrCurrentCluster); nItemLBA = FF_getRealLBA(pFile->pIoman, nItemLBA); - do { - if(pFile->pIoman->pBlkDevice->fnReadBlocks) { -#ifdef FF_BLKDEV_USES_SEM - FF_PendSemaphore(pFile->pIoman->pSemaphore); -#endif - // Called from FF_Read, sem not claimed - RetVal = pFile->pIoman->pBlkDevice->fnReadBlocks(buffer, nItemLBA, Sectors, pFile->pIoman->pBlkDevice->pParam); -#ifdef FF_BLKDEV_USES_SEM - FF_ReleaseSemaphore(pFile->pIoman->pSemaphore); -#endif - if(RetVal == FF_ERR_DRIVER_BUSY) { - FF_Yield(); - FF_Sleep(FF_DRIVER_BUSY_SLEEP); - } - } else { - RetVal = FF_ERR_DEVICE_DRIVER_FAILED; - } - - }while(RetVal == FF_ERR_DRIVER_BUSY); + slRetVal = FF_BlockRead(pFile->pIoman, nItemLBA, ulSectors, buffer); + if(slRetVal < 0) { + return slRetVal; + } Count -= (SequentialClusters + 1); - pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->AddrCurrentCluster, (SequentialClusters + 1)); + pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->AddrCurrentCluster, (SequentialClusters + 1), &Error); + if(Error) { + return Error; + } pFile->CurrentCluster += (SequentialClusters + 1); - buffer += Sectors * pFile->pIoman->BlkSize; + buffer += ulSectors * pFile->pIoman->BlkSize; SequentialClusters = 0; } - return 0; + return FF_ERR_NONE; } @@ -637,6 +836,7 @@ static FF_ERROR FF_ExtendFile(FF_FILE *pFile, FF_T_UINT32 Size) { FF_T_UINT32 CurrentCluster, NextCluster; FF_T_UINT32 i; FF_DIRENT OriginalEntry; + FF_ERROR Error; if((pFile->Mode & FF_MODE_WRITE) != FF_MODE_WRITE) { return FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE; @@ -644,13 +844,25 @@ static FF_ERROR FF_ExtendFile(FF_FILE *pFile, FF_T_UINT32 Size) { if(pFile->Filesize == 0 && pFile->ObjectCluster == 0) { // No Allocated clusters. // Create a Cluster chain! - pFile->AddrCurrentCluster = FF_CreateClusterChain(pFile->pIoman); - if(!FF_GetEntry(pIoman, pFile->DirEntry, pFile->DirCluster, &OriginalEntry)) { - OriginalEntry.ObjectCluster = pFile->AddrCurrentCluster; - FF_PutEntry(pIoman, pFile->DirEntry, pFile->DirCluster, &OriginalEntry); - } else { - return FF_ERR_FILE_EXTEND_FAILED; + pFile->AddrCurrentCluster = FF_CreateClusterChain(pFile->pIoman, &Error); + + if(Error) { + return Error; } + + Error = FF_GetEntry(pIoman, pFile->DirEntry, pFile->DirCluster, &OriginalEntry); + + if(!Error) { + OriginalEntry.ObjectCluster = pFile->AddrCurrentCluster; + Error = FF_PutEntry(pIoman, pFile->DirEntry, pFile->DirCluster, &OriginalEntry); + } else { + return Error; + } + + if(Error) { + return Error; + } + pFile->ObjectCluster = pFile->AddrCurrentCluster; pFile->iChainLength = 1; pFile->CurrentCluster = 0; @@ -662,7 +874,10 @@ static FF_ERROR FF_ExtendFile(FF_FILE *pFile, FF_T_UINT32 Size) { } if(pFile->iChainLength == 0) { // First extension requiring the chain length, - pFile->iChainLength = FF_GetChainLength(pIoman, pFile->ObjectCluster, &pFile->iEndOfChain); + pFile->iChainLength = FF_GetChainLength(pIoman, pFile->ObjectCluster, &pFile->iEndOfChain, &Error); + if(Error) { + return Error; + } } nClusterToExtend = (nTotalClustersNeeded - pFile->iChainLength); @@ -673,65 +888,88 @@ static FF_ERROR FF_ExtendFile(FF_FILE *pFile, FF_T_UINT32 Size) { FF_lockFAT(pIoman); { for(i = 0; i <= nClusterToExtend; i++) { - CurrentCluster = FF_FindEndOfChain(pIoman, NextCluster); - NextCluster = FF_FindFreeCluster(pIoman); + CurrentCluster = FF_FindEndOfChain(pIoman, NextCluster, &Error); + if(Error) { + FF_unlockFAT(pIoman); + FF_DecreaseFreeClusters(pIoman, i); + return Error; + } + NextCluster = FF_FindFreeCluster(pIoman, &Error); + if(Error) { + FF_unlockFAT(pIoman); + FF_DecreaseFreeClusters(pIoman, i); + return Error; + } if(!NextCluster) { FF_unlockFAT(pIoman); + FF_DecreaseFreeClusters(pIoman, i); return FF_ERR_FAT_NO_FREE_CLUSTERS; } - FF_putFatEntry(pIoman, CurrentCluster, NextCluster); - FF_putFatEntry(pIoman, NextCluster, 0xFFFFFFFF); + + Error = FF_putFatEntry(pIoman, CurrentCluster, NextCluster); + if(Error) { + FF_unlockFAT(pIoman); + FF_DecreaseFreeClusters(pIoman, i); + return Error; + } + Error = FF_putFatEntry(pIoman, NextCluster, 0xFFFFFFFF); + if(Error) { + FF_unlockFAT(pIoman); + FF_DecreaseFreeClusters(pIoman, i); + return Error; + } } - pFile->iEndOfChain = FF_FindEndOfChain(pIoman, NextCluster); + pFile->iEndOfChain = FF_FindEndOfChain(pIoman, NextCluster, &Error); + if(Error) { + FF_unlockFAT(pIoman); + FF_DecreaseFreeClusters(pIoman, i); + return Error; + } } FF_unlockFAT(pIoman); pFile->iChainLength += i; - FF_DecreaseFreeClusters(pIoman, i); // Keep Tab of Numbers for fast FreeSize() + Error = FF_DecreaseFreeClusters(pIoman, i); // Keep Tab of Numbers for fast FreeSize() + if(Error) { + return Error; + } } return FF_ERR_NONE; } -static FF_T_SINT32 FF_WriteClusters(FF_FILE *pFile, FF_T_UINT32 Count, FF_T_UINT8 *buffer) { - FF_T_UINT32 Sectors; +static FF_ERROR FF_WriteClusters(FF_FILE *pFile, FF_T_UINT32 Count, FF_T_UINT8 *buffer) { + FF_T_UINT32 ulSectors; FF_T_UINT32 SequentialClusters = 0; FF_T_UINT32 nItemLBA; - FF_T_SINT32 RetVal; + FF_T_SINT32 slRetVal; + FF_ERROR Error; while(Count != 0) { if((Count - 1) > 0) { - SequentialClusters = FF_GetSequentialClusters(pFile->pIoman, pFile->AddrCurrentCluster, (Count - 1)); + SequentialClusters = FF_GetSequentialClusters(pFile->pIoman, pFile->AddrCurrentCluster, (Count - 1), &Error); + if(Error) { + return Error; + } } - Sectors = (SequentialClusters + 1) * pFile->pIoman->pPartition->SectorsPerCluster; + ulSectors = (SequentialClusters + 1) * pFile->pIoman->pPartition->SectorsPerCluster; nItemLBA = FF_Cluster2LBA(pFile->pIoman, pFile->AddrCurrentCluster); nItemLBA = FF_getRealLBA(pFile->pIoman, nItemLBA); - do { - if(pFile->pIoman->pBlkDevice->fnWriteBlocks) { -#ifdef FF_BLKDEV_USES_SEM - FF_PendSemaphore(pFile->pIoman->pSemaphore); -#endif - // Called from FF_Write, sem not claimed - RetVal = pFile->pIoman->pBlkDevice->fnWriteBlocks(buffer, nItemLBA, Sectors, pFile->pIoman->pBlkDevice->pParam); -#ifdef FF_BLKDEV_USES_SEM - FF_ReleaseSemaphore(pFile->pIoman->pSemaphore); -#endif - if(RetVal == FF_ERR_DRIVER_BUSY) { - FF_Yield(); - FF_Sleep(FF_DRIVER_BUSY_SLEEP); - } - } else { - RetVal = FF_ERR_DEVICE_DRIVER_FAILED; - } - - }while(RetVal == FF_ERR_DRIVER_BUSY); + slRetVal = FF_BlockWrite(pFile->pIoman, nItemLBA, ulSectors, buffer); + + if(slRetVal < 0) { + return slRetVal; + } Count -= (SequentialClusters + 1); - pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->AddrCurrentCluster, (SequentialClusters + 1)); + pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->AddrCurrentCluster, (SequentialClusters + 1), &Error); + if(Error) { + return Error; + } pFile->CurrentCluster += (SequentialClusters + 1); - buffer += Sectors * pFile->pIoman->BlkSize; + buffer += ulSectors * pFile->pIoman->BlkSize; SequentialClusters = 0; } @@ -763,6 +1001,7 @@ FF_T_SINT32 FF_Read(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, FF_T_UINT32 nRelClusterPos; FF_T_UINT32 nBytesPerCluster; FF_T_UINT32 nClusterDiff; + FF_ERROR Error; if(!pFile) { return FF_ERR_NULL_POINTER; @@ -785,7 +1024,10 @@ FF_T_SINT32 FF_Read(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; if(nClusterDiff) { if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { - pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff); + pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff, &Error); + if(Error) { + return Error; + } pFile->CurrentCluster += nClusterDiff; } } @@ -798,6 +1040,9 @@ FF_T_SINT32 FF_Read(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, if((nRelBlockPos + nBytes) < pIoman->BlkSize) { // Bytes to read are within a block and less than a block size. pBuffer = FF_GetBuffer(pIoman, nItemLBA, FF_MODE_READ); { + if(!pBuffer) { + return FF_ERR_DEVICE_DRIVER_FAILED; + } memcpy(buffer, (pBuffer->pBuffer + nRelBlockPos), nBytes); } FF_ReleaseBuffer(pIoman, pBuffer); @@ -813,6 +1058,9 @@ FF_T_SINT32 FF_Read(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, nBytesToRead = pIoman->BlkSize - nRelBlockPos; pBuffer = FF_GetBuffer(pIoman, nItemLBA, FF_MODE_READ); { + if(!pBuffer) { + return FF_ERR_DEVICE_DRIVER_FAILED; + } // Here we copy to the sector boudary. memcpy(buffer, (pBuffer->pBuffer + nRelBlockPos), nBytesToRead); } @@ -834,7 +1082,10 @@ FF_T_SINT32 FF_Read(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; if(nClusterDiff) { if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { - pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff); + pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff, &Error); + if(Error) { + return Error; + } pFile->CurrentCluster += nClusterDiff; } } @@ -844,21 +1095,7 @@ FF_T_SINT32 FF_Read(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, sSectors = (FF_T_UINT16) (pIoman->pPartition->SectorsPerCluster - (nRelClusterPos / pIoman->BlkSize)); - do { - if(pIoman->pBlkDevice->fnReadBlocks) { -#ifdef FF_BLKDEV_USES_SEM - FF_PendSemaphore(pFile->pIoman->pSemaphore); -#endif - RetVal = pFile->pIoman->pBlkDevice->fnReadBlocks(buffer, nItemLBA, sSectors, pIoman->pBlkDevice->pParam); -#ifdef FF_BLKDEV_USES_SEM - FF_ReleaseSemaphore(pFile->pIoman->pSemaphore); -#endif - } - if(RetVal == FF_ERR_DRIVER_BUSY) { - FF_Yield(); - FF_Sleep(FF_DRIVER_BUSY_SLEEP); - } - }while(RetVal == FF_ERR_DRIVER_BUSY); + RetVal = FF_BlockRead(pIoman, nItemLBA, (FF_T_UINT32) sSectors, buffer); nBytesToRead = sSectors * pIoman->BlkSize; nBytes -= nBytesToRead; @@ -874,13 +1111,19 @@ FF_T_SINT32 FF_Read(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; if(nClusterDiff) { if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { - pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff); + pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff, &Error); + if(Error) { + return Error; + } pFile->CurrentCluster += nClusterDiff; } } //----- End of Contributor fix. - FF_ReadClusters(pFile, (nBytes / nBytesPerCluster), buffer); + RetVal = FF_ReadClusters(pFile, (nBytes / nBytesPerCluster), buffer); + if(RetVal < 0) { + return RetVal; + } nBytesToRead = (nBytesPerCluster * (nBytes / nBytesPerCluster)); pFile->FilePointer += nBytesToRead; @@ -897,29 +1140,22 @@ FF_T_SINT32 FF_Read(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; if(nClusterDiff) { if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { - pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff); + pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff, &Error); + if(Error) { + return Error; + } pFile->CurrentCluster += nClusterDiff; } } nItemLBA = FF_Cluster2LBA(pIoman, pFile->AddrCurrentCluster); nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1); - - do { - if(pIoman->pBlkDevice->fnReadBlocks) { -#ifdef FF_BLKDEV_USES_SEM - FF_PendSemaphore(pFile->pIoman->pSemaphore); -#endif - RetVal = pFile->pIoman->pBlkDevice->fnReadBlocks(buffer, nItemLBA, sSectors, pIoman->pBlkDevice->pParam); -#ifdef FF_BLKDEV_USES_SEM - FF_ReleaseSemaphore(pFile->pIoman->pSemaphore); -#endif - } - if(RetVal == FF_ERR_DRIVER_BUSY) { - FF_Yield(); - FF_Sleep(FF_DRIVER_BUSY_SLEEP); - } - }while(RetVal == FF_ERR_DRIVER_BUSY); + + RetVal = FF_BlockRead(pIoman, nItemLBA, (FF_T_UINT32) sSectors, buffer); + + if(RetVal < 0) { + return RetVal; + } nBytesToRead = sSectors * pIoman->BlkSize; pFile->FilePointer += nBytesToRead; @@ -934,7 +1170,10 @@ FF_T_SINT32 FF_Read(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; if(nClusterDiff) { if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { - pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff); + pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff, &Error); + if(Error) { + return Error; + } pFile->CurrentCluster += nClusterDiff; } } @@ -943,6 +1182,9 @@ FF_T_SINT32 FF_Read(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1); pBuffer = FF_GetBuffer(pIoman, nItemLBA, FF_MODE_READ); { + if(!pBuffer) { + return FF_ERR_DEVICE_DRIVER_FAILED; + } memcpy(buffer, pBuffer->pBuffer, nBytes); } FF_ReleaseBuffer(pIoman, pBuffer); @@ -980,6 +1222,7 @@ FF_T_SINT32 FF_GetC(FF_FILE *pFile) { FF_T_UINT32 relMinorBlockPos; FF_T_UINT32 clusterNum; FF_T_UINT32 nClusterDiff; + FF_ERROR Error; if(!pFile) { @@ -1000,7 +1243,10 @@ FF_T_SINT32 FF_GetC(FF_FILE *pFile) { nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; if(nClusterDiff) { if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { - pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->AddrCurrentCluster, nClusterDiff); + pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->AddrCurrentCluster, nClusterDiff, &Error); + if(Error) { + return Error; + } pFile->CurrentCluster += nClusterDiff; } } @@ -1012,7 +1258,7 @@ FF_T_SINT32 FF_GetC(FF_FILE *pFile) { pBuffer = FF_GetBuffer(pFile->pIoman, fileLBA, FF_MODE_READ); { if(!pBuffer) { - return -3; + return FF_ERR_DEVICE_DRIVER_FAILED; } retChar = pBuffer->pBuffer[relMinorBlockPos]; } @@ -1023,6 +1269,45 @@ FF_T_SINT32 FF_GetC(FF_FILE *pFile) { return (FF_T_INT32) retChar; } + +/** + * @public + * @brief Gets a Line from a Text File, but no more than ulLimit charachters. The line will be NULL terminated. + * + * The behaviour of this function is undefined when called on a binary file. + * It should just read in ulLimit bytes of binary, and ZERO terminate the line. + * + * This function works for both UNIX line feeds, and Windows CRLF type files. + * + * @param pFile The FF_FILE object pointer. + * @param szLine The charachter buffer where the line should be stored. + * @param ulLimit This should be the max number of charachters that szLine can hold. + * + * @return The number of charachters read from the line, on success. + * @return 0 when no more lines are available, or when ulLimit is 0. + * @return FF_ERR_NULL_POINTER if pFile or szLine are NULL; + * + **/ +FF_T_SINT32 FF_GetLine(FF_FILE *pFile, FF_T_INT8 *szLine, FF_T_UINT32 ulLimit) { + FF_T_SINT32 c; + FF_T_UINT32 i; + + if(!pFile || !szLine) { + return FF_ERR_NULL_POINTER; + } + + for(i = 0; i < (ulLimit - 1) && (c=FF_GetC(pFile)) >= 0 && c != '\n'; ++i) { + if(c == '\r') { + i--; + } else { + szLine[i] = (FF_T_INT8) c; + } + } + + szLine[i] = '\0'; + return i; +} + FF_T_UINT32 FF_Tell(FF_FILE *pFile) { return pFile->FilePointer; } @@ -1047,7 +1332,7 @@ FF_T_SINT32 FF_Write(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, FF_BUFFER *pBuffer; FF_T_UINT32 nRelBlockPos; FF_T_UINT32 nItemLBA; - FF_T_SINT32 RetVal = 0; + FF_T_SINT32 slRetVal = 0; FF_T_UINT16 sSectors; FF_T_UINT32 nRelClusterPos; FF_T_UINT32 nBytesPerCluster, nClusterDiff, nClusters; @@ -1085,7 +1370,10 @@ FF_T_SINT32 FF_Write(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; if(nClusterDiff) { if(pFile->CurrentCluster != FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { - pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff); + pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff, &Error); + if(Error) { + return Error; + } pFile->CurrentCluster += nClusterDiff; } } @@ -1096,6 +1384,9 @@ FF_T_SINT32 FF_Write(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, if((nRelBlockPos + nBytes) < pIoman->BlkSize) { // Bytes to read are within a block and less than a block size. pBuffer = FF_GetBuffer(pIoman, nItemLBA, FF_MODE_WRITE); { + if(!pBuffer) { + return FF_ERR_DEVICE_DRIVER_FAILED; + } memcpy((pBuffer->pBuffer + nRelBlockPos), buffer, nBytes); } FF_ReleaseBuffer(pIoman, pBuffer); @@ -1111,6 +1402,9 @@ FF_T_SINT32 FF_Write(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, nBytesToWrite = pIoman->BlkSize - nRelBlockPos; pBuffer = FF_GetBuffer(pIoman, nItemLBA, FF_MODE_WRITE); { + if(!pBuffer) { + return FF_ERR_DEVICE_DRIVER_FAILED; + } // Here we copy to the sector boudary. memcpy((pBuffer->pBuffer + nRelBlockPos), buffer, nBytesToWrite); } @@ -1130,7 +1424,10 @@ FF_T_SINT32 FF_Write(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; if(nClusterDiff) { if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { - pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff); + pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff, &Error); + if(Error) { + return Error; + } pFile->CurrentCluster += nClusterDiff; } } @@ -1139,22 +1436,11 @@ FF_T_SINT32 FF_Write(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1); sSectors = (FF_T_UINT16) (pIoman->pPartition->SectorsPerCluster - (nRelClusterPos / pIoman->BlkSize)); - - do { - if(pIoman->pBlkDevice->fnWriteBlocks) { -#ifdef FF_BLKDEV_USES_SEM - FF_PendSemaphore(pFile->pIoman->pSemaphore); -#endif - RetVal = pFile->pIoman->pBlkDevice->fnWriteBlocks(buffer, nItemLBA, sSectors, pIoman->pBlkDevice->pParam); -#ifdef FF_BLKDEV_USES_SEM - FF_ReleaseSemaphore(pFile->pIoman->pSemaphore); -#endif - } - if(RetVal == FF_ERR_DRIVER_BUSY) { - FF_Yield(); - FF_Sleep(FF_DRIVER_BUSY_SLEEP); - } - }while(RetVal == FF_ERR_DRIVER_BUSY); + + slRetVal = FF_BlockWrite(pFile->pIoman, nItemLBA, sSectors, buffer); + if(slRetVal < 0) { + return slRetVal; + } nBytesToWrite = sSectors * pIoman->BlkSize; nBytes -= nBytesToWrite; @@ -1170,7 +1456,10 @@ FF_T_SINT32 FF_Write(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; if(nClusterDiff) { if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { - pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff); + pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff, &Error); + if(Error) { + return Error; + } pFile->CurrentCluster += nClusterDiff; } } @@ -1178,7 +1467,10 @@ FF_T_SINT32 FF_Write(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, nClusters = (nBytes / nBytesPerCluster); - FF_WriteClusters(pFile, nClusters, buffer); + slRetVal = FF_WriteClusters(pFile, nClusters, buffer); + if(slRetVal < 0) { + return slRetVal; + } nBytesToWrite = (nBytesPerCluster * nClusters); @@ -1196,7 +1488,10 @@ FF_T_SINT32 FF_Write(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; if(nClusterDiff) { if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { - pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff); + pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff, &Error); + if(Error) { + return Error; + } pFile->CurrentCluster += nClusterDiff; } } @@ -1204,28 +1499,16 @@ FF_T_SINT32 FF_Write(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, nItemLBA = FF_Cluster2LBA(pIoman, pFile->AddrCurrentCluster); nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1); - do { - if(pIoman->pBlkDevice->fnWriteBlocks) { -#ifdef FF_BLKDEV_USES_SEM - FF_PendSemaphore(pFile->pIoman->pSemaphore); -#endif - RetVal = pFile->pIoman->pBlkDevice->fnWriteBlocks(buffer, nItemLBA, sSectors, pIoman->pBlkDevice->pParam); -#ifdef FF_BLKDEV_USES_SEM - FF_ReleaseSemaphore(pFile->pIoman->pSemaphore); -#endif - } - if(RetVal == FF_ERR_DRIVER_BUSY) { - FF_Yield(); - FF_Sleep(FF_DRIVER_BUSY_SLEEP); - } - }while(RetVal == FF_ERR_DRIVER_BUSY); + slRetVal = FF_BlockWrite(pFile->pIoman, nItemLBA, sSectors, buffer); + if(slRetVal < 0) { + return slRetVal; + } nBytesToWrite = sSectors * pIoman->BlkSize; pFile->FilePointer += nBytesToWrite; nBytes -= nBytesToWrite; buffer += nBytesToWrite; nBytesWritten += nBytesToWrite; - } //---------- Write (memcpy) Remaining Bytes @@ -1234,7 +1517,10 @@ FF_T_SINT32 FF_Write(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; if(nClusterDiff) { if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { - pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff); + pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff, &Error); + if(Error) { + return Error; + } pFile->CurrentCluster += nClusterDiff; } } @@ -1243,6 +1529,9 @@ FF_T_SINT32 FF_Write(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1); pBuffer = FF_GetBuffer(pIoman, nItemLBA, FF_MODE_WRITE); { + if(!pBuffer) { + return FF_ERR_DEVICE_DRIVER_FAILED; + } memcpy(pBuffer->pBuffer, buffer, nBytes); } FF_ReleaseBuffer(pIoman, pBuffer); @@ -1279,6 +1568,7 @@ FF_T_SINT32 FF_PutC(FF_FILE *pFile, FF_T_UINT8 pa_cValue) { FF_T_UINT32 iItemLBA; FF_T_UINT32 iRelPos; FF_T_UINT32 nClusterDiff; + FF_ERROR Error; if(!pFile) { // Ensure we don't have a Null file pointer on a Public interface. return FF_ERR_NULL_POINTER; @@ -1298,18 +1588,24 @@ FF_T_SINT32 FF_PutC(FF_FILE *pFile, FF_T_UINT8 pa_cValue) { iRelPos = FF_getMinorBlockEntry(pFile->pIoman, pFile->FilePointer, 1); // Handle File Space Allocation. - FF_ExtendFile(pFile, pFile->FilePointer + 1); + Error = FF_ExtendFile(pFile, pFile->FilePointer + 1); + if(Error) { + return Error; + } nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; if(nClusterDiff) { if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { - pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->AddrCurrentCluster, nClusterDiff); + pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->AddrCurrentCluster, nClusterDiff, &Error); + if(Error) { + return Error; + } pFile->CurrentCluster += nClusterDiff; } } iItemLBA = FF_Cluster2LBA(pFile->pIoman, pFile->AddrCurrentCluster) + FF_getMajorBlockNumber(pFile->pIoman, pFile->FilePointer, (FF_T_UINT16) 1); - iItemLBA = FF_getRealLBA (pFile->pIoman, iItemLBA) + FF_getMinorBlockNumber(pFile->pIoman, pFile->FilePointer, (FF_T_UINT16) 1); + iItemLBA = FF_getRealLBA (pFile->pIoman, iItemLBA) + FF_getMinorBlockNumber(pFile->pIoman, pFile->FilePointer, (FF_T_UINT16) 1); pBuffer = FF_GetBuffer(pFile->pIoman, iItemLBA, FF_MODE_WRITE); { @@ -1339,22 +1635,32 @@ FF_T_SINT32 FF_PutC(FF_FILE *pFile, FF_T_UINT8 pa_cValue) { * * @return 0 on Sucess, * @return -2 if offset results in an invalid position in the file. - * @return -1 if a FF_FILE pointer was not recieved. + * @return FF_ERR_NULL_POINTER if a FF_FILE pointer was not recieved. * @return -3 if an invalid origin was provided. * **/ FF_ERROR FF_Seek(FF_FILE *pFile, FF_T_SINT32 Offset, FF_T_INT8 Origin) { + FF_ERROR Error; + if(!pFile) { return FF_ERR_NULL_POINTER; } + Error = FF_FlushCache(pFile->pIoman); + if(Error) { + return Error; + } + switch(Origin) { case FF_SEEK_SET: if((FF_T_UINT32) Offset <= pFile->Filesize && Offset >= 0) { pFile->FilePointer = Offset; pFile->CurrentCluster = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1); - pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->ObjectCluster, pFile->CurrentCluster); + pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->ObjectCluster, pFile->CurrentCluster, &Error); + if(Error) { + return Error; + } } else { return -2; } @@ -1364,7 +1670,10 @@ FF_ERROR FF_Seek(FF_FILE *pFile, FF_T_SINT32 Offset, FF_T_INT8 Origin) { if((Offset + pFile->FilePointer) <= pFile->Filesize && (Offset + (FF_T_SINT32) pFile->FilePointer) >= 0) { pFile->FilePointer = Offset + pFile->FilePointer; pFile->CurrentCluster = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1); - pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->ObjectCluster, pFile->CurrentCluster); + pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->ObjectCluster, pFile->CurrentCluster, &Error); + if(Error) { + return Error; + } } else { return -2; } @@ -1374,7 +1683,10 @@ FF_ERROR FF_Seek(FF_FILE *pFile, FF_T_SINT32 Offset, FF_T_INT8 Origin) { if((Offset + (FF_T_SINT32) pFile->Filesize) >= 0 && (Offset + pFile->Filesize) <= pFile->Filesize) { pFile->FilePointer = Offset + pFile->Filesize; pFile->CurrentCluster = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1); - pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->ObjectCluster, pFile->CurrentCluster); + pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->ObjectCluster, pFile->CurrentCluster, &Error); + if(Error) { + return Error; + } } else { return -2; } @@ -1419,14 +1731,15 @@ FF_ERROR FF_Close(FF_FILE *pFile) { if(!pFile->FileDeleted) { if(pFile->Filesize != OriginalEntry.Filesize) { OriginalEntry.Filesize = pFile->Filesize; - FF_PutEntry(pFile->pIoman, pFile->DirEntry, pFile->DirCluster, &OriginalEntry); + Error = FF_PutEntry(pFile->pIoman, pFile->DirEntry, pFile->DirCluster, &OriginalEntry); + if(Error) { + return Error; + } } } - //if(pFile->Mode == FF_MODE_WRITE) { - FF_FlushCache(pFile->pIoman); // Ensure all modfied blocks are flushed to disk! - //} - + Error = FF_FlushCache(pFile->pIoman); // Ensure all modfied blocks are flushed to disk! + // Handle Linked list! FF_PendSemaphore(pFile->pIoman->pSemaphore); { // Semaphore is required, or linked list could become corrupted. @@ -1444,6 +1757,11 @@ FF_ERROR FF_Close(FF_FILE *pFile) { // If file written, flush to disk FF_FREE(pFile); + + if(Error) { + return Error; + } + // Simply free the pointer! return FF_ERR_NONE; } diff --git a/reactos/lib/3rdparty/fullfat/ff_format.c b/reactos/lib/3rdparty/fullfat/ff_format.c new file mode 100644 index 00000000000..8799f9a204e --- /dev/null +++ b/reactos/lib/3rdparty/fullfat/ff_format.c @@ -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 . * + * * + * 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; + + +} \ No newline at end of file diff --git a/reactos/lib/3rdparty/fullfat/ff_hash.c b/reactos/lib/3rdparty/fullfat/ff_hash.c index 4a07c81d37e..6357987b313 100644 --- a/reactos/lib/3rdparty/fullfat/ff_hash.c +++ b/reactos/lib/3rdparty/fullfat/ff_hash.c @@ -43,9 +43,9 @@ #include #include -#ifdef FF_HASH_TABLE_SUPPORT +#ifdef FF_HASH_CACHE struct _FF_HASH_TABLE { - FF_T_UINT8 bitTable[FF_HASH_TABLE_SIZE]; + FF_T_UINT8 bitTable[FF_HASH_TABLE_SIZE]; }; /** diff --git a/reactos/lib/3rdparty/fullfat/ff_ioman.c b/reactos/lib/3rdparty/fullfat/ff_ioman.c index 60871f831a0..8e8fc32d418 100644 --- a/reactos/lib/3rdparty/fullfat/ff_ioman.c +++ b/reactos/lib/3rdparty/fullfat/ff_ioman.c @@ -46,9 +46,10 @@ #include "ff_ioman.h" // Includes ff_types.h, ff_safety.h, #include "ff_fatdef.h" +#include "ff_crc.h" -extern FF_T_UINT32 FF_FindFreeCluster (FF_IOMAN *pIoman); -extern FF_T_UINT32 FF_CountFreeClusters (FF_IOMAN *pIoman); +//extern FF_T_UINT32 FF_FindFreeCluster (FF_IOMAN *pIoman); +extern FF_T_UINT32 FF_CountFreeClusters (FF_IOMAN *pIoman, FF_ERROR *pError); 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 * * @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 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. @@ -77,16 +78,16 @@ FF_IOMAN *FF_CreateIOMAN(FF_T_UINT8 *pCacheMem, FF_T_UINT32 Size, FF_T_UINT16 Bl *pError = FF_ERR_NONE; } - if((BlkSize % 512) != 0 || Size == 0) { + if((BlkSize % 512) != 0 || BlkSize == 0) { 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 } - 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) { - *pError = FF_ERR_IOMAN_BAD_MEMSIZE; + *pError = FF_ERR_IOMAN_BAD_MEMSIZE | FF_CREATEIOMAN; } 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(pError) { - *pError = FF_ERR_NOT_ENOUGH_MEMORY; + *pError = FF_ERR_NOT_ENOUGH_MEMORY | FF_CREATEIOMAN; } 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)); if(!pIoman->pPartition) { if(pError) { - *pError = FF_ERR_NOT_ENOUGH_MEMORY; + *pError = FF_ERR_NOT_ENOUGH_MEMORY | FF_CREATEIOMAN; } FF_DestroyIOMAN(pIoman); 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++) { pIoman->pPartition->PathCache[i].DirCluster = 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].bHashed = FF_FALSE; +#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 pIoman->pBlkDevice = (FF_BLK_DEVICE *) FF_MALLOC(sizeof(FF_BLK_DEVICE)); if(!pIoman->pBlkDevice) { // If succeeded, flag that allocation. if(pError) { - *pError = FF_ERR_NOT_ENOUGH_MEMORY; + *pError = FF_ERR_NOT_ENOUGH_MEMORY | FF_CREATEIOMAN; } FF_DestroyIOMAN(pIoman); 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; // Make sure all pointers are NULL - pIoman->pBlkDevice->fnReadBlocks = NULL; - pIoman->pBlkDevice->fnWriteBlocks = NULL; + pIoman->pBlkDevice->fnpReadBlocks = NULL; + pIoman->pBlkDevice->fnpWriteBlocks = NULL; pIoman->pBlkDevice->pParam = NULL; // 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; if(!pIoman->pCacheMem) { if(pError) { - *pError = FF_ERR_NOT_ENOUGH_MEMORY; + *pError = FF_ERR_NOT_ENOUGH_MEMORY | FF_CREATEIOMAN; } FF_DestroyIOMAN(pIoman); 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(pError) { - *pError = FF_ERR_NOT_ENOUGH_MEMORY; + *pError = FF_ERR_NOT_ENOUGH_MEMORY | FF_CREATEIOMAN; } FF_DestroyIOMAN(pIoman); 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. pIoman->pSemaphore = FF_CreateSemaphore(); +#ifdef FF_BLKDEV_USES_SEM + pIoman->pBlkDevSemaphore = FF_CreateSemaphore(); +#endif + 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) { +#ifdef FF_HASH_CACHE + FF_T_UINT32 i; +#endif + // Ensure no NULL pointer was provided. if(!pIoman) { - return FF_ERR_NULL_POINTER; + return FF_ERR_NULL_POINTER | FF_DESTROYIOMAN; } // Ensure pPartition pointer was allocated. @@ -231,6 +248,18 @@ FF_ERROR FF_DestroyIOMAN(FF_IOMAN *pIoman) { if(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. 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 @@ -358,7 +299,7 @@ FF_ERROR FF_FlushCache(FF_IOMAN *pIoman) { FF_T_UINT16 i,x; if(!pIoman) { - return FF_ERR_NULL_POINTER; + return FF_ERR_NULL_POINTER | FF_FLUSHCACHE; } FF_PendSemaphore(pIoman->pSemaphore); @@ -366,7 +307,7 @@ FF_ERROR FF_FlushCache(FF_IOMAN *pIoman) { for(i = 0; i < pIoman->CacheSize; i++) { 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. (pIoman->pBuffers + i)->Mode = FF_MODE_READ; @@ -389,13 +330,6 @@ FF_ERROR FF_FlushCache(FF_IOMAN *pIoman) { 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 *pBuffer; 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) { 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); if(pBuffer->Sector == Sector && pBuffer->Valid == FF_TRUE) { pBufMatch = pBuffer; - } else { - 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; - } - } + break; // Why look further if you found a perfect match? } } @@ -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! } 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) { // Process the suitable candidate. 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->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; } - FF_IOMAN_FillBuffer(pIoman, Sector, pBufLRU->pBuffer); + FF_BlockRead(pIoman, Sector, 1, pBufLRU->pBuffer); pBufLRU->Valid = FF_TRUE; FF_ReleaseSemaphore(pIoman->pSemaphore); 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) { 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) { - 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) { - 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" // Doing so would corrupt the context of FullFAT - if(pIoman->pBlkDevice->fnReadBlocks) { - return FF_ERR_IOMAN_DEV_ALREADY_REGD; + if(pIoman->pBlkDevice->fnpReadBlocks) { + return FF_ERR_IOMAN_DEV_ALREADY_REGD | FF_REGISTERBLKDEVICE; } - if(pIoman->pBlkDevice->fnWriteBlocks) { - return FF_ERR_IOMAN_DEV_ALREADY_REGD; + if(pIoman->pBlkDevice->fnpWriteBlocks) { + return FF_ERR_IOMAN_DEV_ALREADY_REGD | FF_REGISTERBLKDEVICE; } 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. // FullFAT checks before using any of these values. pIoman->pBlkDevice->devBlkSize = BlkSize; - pIoman->pBlkDevice->fnReadBlocks = fnReadBlocks; - pIoman->pBlkDevice->fnWriteBlocks = fnWriteBlocks; + pIoman->pBlkDevice->fnpReadBlocks = fnReadBlocks; + pIoman->pBlkDevice->fnpWriteBlocks = fnWriteBlocks; pIoman->pBlkDevice->pParam = pParam; 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 **/ @@ -638,7 +632,7 @@ static FF_ERROR FF_DetermineFatType(FF_IOMAN *pIoman) { testLong = FF_getLong(pBuffer->pBuffer, 0x0000); } FF_ReleaseBuffer(pIoman, pBuffer); - if((testLong & 0x0FFFFFF8) != 0x0FFFFFF8) { + if((testLong & 0x0FFFFFF8) != 0x0FFFFFF8 && (testLong & 0x0FFFFFF8) != 0x0FFFFFF0) { return FF_ERR_IOMAN_NOT_FAT_FORMATTED; } #endif @@ -676,6 +670,91 @@ static FF_T_SINT8 FF_PartitionCount (FF_T_UINT8 *pBuffer) 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 * @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_PARTITION *pPart; FF_BUFFER *pBuffer = 0; + FF_ERROR Error; + + FF_T_UINT8 ucPartitionType; + int partCount; if(!pIoman) { return FF_ERR_NULL_POINTER; } - if(PartitionNumber > 3) { + /*if(PartitionNumber > 3) { return FF_ERR_IOMAN_INVALID_PARTITION_NUM; - } + }*/ pPart = pIoman->pPartition; @@ -728,10 +811,32 @@ FF_ERROR FF_MountPartition(FF_IOMAN *pIoman, FF_T_UINT8 PartitionNumber) { // Volume is not partitioned (MBR Found) pPart->BeginLBA = 0; } 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); + 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) { 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! + + 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->FirstDataSector = pPart->ClusterBeginLBA + 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; - if(FF_DetermineFatType(pIoman)) { - return FF_ERR_IOMAN_NOT_FAT_FORMATTED; + Error = FF_DetermineFatType(pIoman); + + if(Error) { + return Error; } #ifdef FF_MOUNT_FIND_FREE @@ -820,8 +937,8 @@ FF_ERROR FF_UnregisterBlkDevice(FF_IOMAN *pIoman) { { if(pIoman->pPartition->PartitionMounted == FF_FALSE) { pIoman->pBlkDevice->devBlkSize = 0; - pIoman->pBlkDevice->fnReadBlocks = NULL; - pIoman->pBlkDevice->fnWriteBlocks = NULL; + pIoman->pBlkDevice->fnpReadBlocks = NULL; + pIoman->pBlkDevice->fnpWriteBlocks = NULL; pIoman->pBlkDevice->pParam = NULL; } else { RetVal = FF_ERR_IOMAN_PARTITION_MOUNTED; @@ -876,7 +993,11 @@ FF_ERROR FF_UnmountPartition(FF_IOMAN *pIoman) { { if(!FF_ActiveHandles(pIoman)) { if(pIoman->FirstFile == NULL) { + // Release Semaphore to call this function! + FF_ReleaseSemaphore(pIoman->pSemaphore); FF_FlushCache(pIoman); // Flush any unwritten sectors to disk. + // Reclaim Semaphore + FF_PendSemaphore(pIoman->pSemaphore); pIoman->pPartition->PartitionMounted = FF_FALSE; } else { 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 Error; //FF_PendSemaphore(pIoman->pSemaphore); //{ 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); @@ -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 Error; + //FF_lockFAT(pIoman); //{ 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); diff --git a/reactos/lib/3rdparty/fullfat/ff_string.c b/reactos/lib/3rdparty/fullfat/ff_string.c index 6913ee7082f..b6c06790ea9 100644 --- a/reactos/lib/3rdparty/fullfat/ff_string.c +++ b/reactos/lib/3rdparty/fullfat/ff_string.c @@ -42,27 +42,57 @@ #include #include +#include #include "ff_string.h" +#include "ff_error.h" + +#ifdef FF_UNICODE_SUPPORT +#include +#include +#endif /* * These will eventually be moved into a platform independent string * 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 * @brief Converts an ASCII string to lowercase. **/ -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; - } -} - +#ifndef FF_UNICODE_SUPPORT /** * @private * @brief Converts an ASCII string to uppercase. @@ -76,6 +106,32 @@ void FF_toupper(FF_T_INT8 *string, FF_T_UINT32 strLen) { 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. * **/ + +#ifndef FF_UNICODE_SUPPORT 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_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; } +#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 * @brief A re-entrant Strtok function. No documentation is provided :P * 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_UINT16 strLen = Length; 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; } - - memcpy(token, (string + tokenStart), (FF_T_UINT32)(tokenEnd - tokenStart)); - token[tokenEnd - tokenStart] = '\0'; + if((tokenEnd - tokenStart) < FF_MAX_FILENAME) { + memcpy(token, (string + tokenStart), (FF_T_UINT32)(tokenEnd - tokenStart)); + 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; 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) { - /* Check to see if the string contains the wild card */ + i = 0; + 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 it does not then do a straight string compare */ + // if it does not then do a straight string compare if (strcmp(pszWildCard, pszString)) { return FF_FALSE; @@ -177,20 +321,20 @@ FF_T_BOOL FF_wildcompare(const FF_T_INT8 *pszWildCard, const FF_T_INT8 *pszStrin while ((*pszWildCard) && (*pszString)) { - /* Test for the wild card */ + // Test for the wild card if (*pszWildCard == '*') { - /* Eat more than one */ + // Eat more than one while (*pszWildCard == '*') { pszWildCard++; } - /* If there are more chars in the string */ + // If there are more chars in the string if (*pszWildCard) { - /* Search for the next char */ + // Search for the next char 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) { return FF_FALSE; @@ -201,7 +345,7 @@ FF_T_BOOL FF_wildcompare(const FF_T_INT8 *pszWildCard, const FF_T_INT8 *pszStrin { if (*pszWildCard) { - /* continue */ + // continue break; } else @@ -212,17 +356,17 @@ FF_T_BOOL FF_wildcompare(const FF_T_INT8 *pszWildCard, const FF_T_INT8 *pszStrin } else { - /* Fail if they don't match */ + // Fail if they don't match if (*pszWildCard != *pszString) { return FF_FALSE; } } - /* Bump both pointers */ + // Bump both pointers pszWildCard++; pszString++; } - /* fail if different lengths */ + // fail if different lengths if (*pszWildCard != *pszString) { 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; -} +}*/ +/* + 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 diff --git a/reactos/lib/3rdparty/fullfat/ff_unicode.c b/reactos/lib/3rdparty/fullfat/ff_unicode.c new file mode 100644 index 00000000000..24fffd420d4 --- /dev/null +++ b/reactos/lib/3rdparty/fullfat/ff_unicode.c @@ -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 . * + * * + * 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; +} diff --git a/reactos/lib/3rdparty/fullfat/fullfat.rbuild b/reactos/lib/3rdparty/fullfat/fullfat.rbuild index df4d3580b01..754502d6d57 100644 --- a/reactos/lib/3rdparty/fullfat/fullfat.rbuild +++ b/reactos/lib/3rdparty/fullfat/fullfat.rbuild @@ -1,6 +1,6 @@ - + include/reactos/libs/fullfat @@ -10,10 +10,12 @@ ff_error.c ff_fat.c ff_file.c + ff_format.c ff_hash.c ff_ioman.c ff_memory.c ff_safety.c ff_string.c ff_time.c + ff_unicode.c