Index: ff_blk.c =================================================================== --- ff_blk.c (revision 58178) +++ ff_blk.c (working copy) @@ -1,7 +1,19 @@ /***************************************************************************** - * FullFAT - High Performance, Thread-Safe Embedded FAT File-System * - * Copyright (C) 2009 James Walmsley (james@worm.me.uk) * + * FullFAT - High Performance, Thread-Safe Embedded FAT File-System * * * + * Copyright(C) 2009 James Walmsley * + * Copyright(C) 2011 Hein Tibosch * + * * + * See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT. * + * * + * WARNING : COMMERCIAL PROJECTS MUST COMPLY WITH THE GNU GPL LICENSE. * + * * + * Projects that cannot comply with the GNU GPL terms are legally obliged * + * to seek alternative licensing. Contact James Walmsley for details. * + * * + ***************************************************************************** + * See http://www.fullfat-fs.co.uk/ for more information. * + ***************************************************************************** * 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 * @@ -15,18 +27,14 @@ * 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. * + * The Copyright of Hein Tibosch on this project recognises his efforts in * + * contributing to this project. The right to license the project under * + * any other terms (other than the GNU GPL license) remains with the * + * original copyright holder (James Walmsley) only. * * * - * 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. * + * Modification/Extensions/Bugfixes/Improvements to FullFAT must be sent to * + * James Walmsley for integration into the main development branch. * *****************************************************************************/ /** Index: ff_crc.c =================================================================== --- ff_crc.c (revision 58178) +++ ff_crc.c (working copy) @@ -1,7 +1,19 @@ /***************************************************************************** - * FullFAT - High Performance, Thread-Safe Embedded FAT File-System * - * Copyright (C) 2009 James Walmsley (james@worm.me.uk) * + * FullFAT - High Performance, Thread-Safe Embedded FAT File-System * * * + * Copyright(C) 2009 James Walmsley * + * Copyright(C) 2011 Hein Tibosch * + * * + * See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT. * + * * + * WARNING : COMMERCIAL PROJECTS MUST COMPLY WITH THE GNU GPL LICENSE. * + * * + * Projects that cannot comply with the GNU GPL terms are legally obliged * + * to seek alternative licensing. Contact James Walmsley for details. * + * * + ***************************************************************************** + * See http://www.fullfat-fs.co.uk/ for more information. * + ***************************************************************************** * 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 * @@ -15,18 +27,14 @@ * 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. * + * The Copyright of Hein Tibosch on this project recognises his efforts in * + * contributing to this project. The right to license the project under * + * any other terms (other than the GNU GPL license) remains with the * + * original copyright holder (James Walmsley) only. * * * - * 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. * + * Modification/Extensions/Bugfixes/Improvements to FullFAT must be sent to * + * James Walmsley for integration into the main development branch. * *****************************************************************************/ /** @@ -42,7 +50,7 @@ #include "ff_crc.h" -static const FF_T_UINT32 crc32_table[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, Index: ff_dir.c =================================================================== --- ff_dir.c (revision 58178) +++ ff_dir.c (working copy) @@ -1,7 +1,19 @@ /***************************************************************************** - * FullFAT - High Performance, Thread-Safe Embedded FAT File-System * - * Copyright (C) 2009 James Walmsley (james@worm.me.uk) * + * FullFAT - High Performance, Thread-Safe Embedded FAT File-System * * * + * Copyright(C) 2009 James Walmsley * + * Copyright(C) 2011 Hein Tibosch * + * * + * See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT. * + * * + * WARNING : COMMERCIAL PROJECTS MUST COMPLY WITH THE GNU GPL LICENSE. * + * * + * Projects that cannot comply with the GNU GPL terms are legally obliged * + * to seek alternative licensing. Contact James Walmsley for details. * + * * + ***************************************************************************** + * See http://www.fullfat-fs.co.uk/ for more information. * + ***************************************************************************** * 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 * @@ -15,18 +27,14 @@ * 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. * + * The Copyright of Hein Tibosch on this project recognises his efforts in * + * contributing to this project. The right to license the project under * + * any other terms (other than the GNU GPL license) remains with the * + * original copyright holder (James Walmsley) only. * * * - * 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. * + * Modification/Extensions/Bugfixes/Improvements to FullFAT must be sent to * + * James Walmsley for integration into the main development branch. * *****************************************************************************/ /** @@ -51,7 +59,9 @@ #endif #ifdef WIN32 +#define wcsicmp _wcsicmp #else +#define wcsicmp wcscasecmp #include // tolower() int strcasecmp(const char *s1, const char *s2) { @@ -107,44 +117,46 @@ FF_ERROR FF_FindNextInDir(FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_FETCH_CONTEXT *pFetchContext) { - - FF_T_UINT8 numLFNs; + FF_T_UINT8 EntryBuffer[32]; FF_ERROR Error; - +#ifndef FF_LFN_SUPPORT + FF_T_UINT8 numLFNs; +#endif if(!pIoman) { - return FF_ERR_NULL_POINTER; + return FF_ERR_NULL_POINTER | FF_FINDNEXTINDIR; } for(; pDirent->CurrentItem < 0xFFFF; pDirent->CurrentItem += 1) { - + Error = FF_FetchEntryWithContext(pIoman, pDirent->CurrentItem, pFetchContext, EntryBuffer); - - if(Error) { + + if(FF_isERR(Error)) { return Error; } - + if(EntryBuffer[0] != 0xE5) { if(FF_isEndOfDir(EntryBuffer)){ - return FF_ERR_DIR_END_OF_DIR; + return FF_ERR_DIR_END_OF_DIR | FF_FINDNEXTINDIR; } 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); - //pDirent->NumLFNs = numLFNs; + #ifdef FF_LFN_SUPPORT Error = FF_PopulateLongDirent(pIoman, pDirent, pDirent->CurrentItem, pFetchContext); - if(Error) { + if(FF_isERR(Error)) { return Error; } return FF_ERR_NONE; -#else +#else + // LFN Processing + numLFNs = (FF_T_UINT8)(EntryBuffer[0] & ~0x40); + //pDirent->NumLFNs = numLFNs; 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; @@ -152,8 +164,8 @@ } } } - - return FF_ERR_DIR_END_OF_DIR; + + return FF_ERR_DIR_END_OF_DIR | FF_FINDNEXTINDIR; } #ifdef FF_UNICODE_SUPPORT @@ -170,7 +182,7 @@ #ifdef FF_UNICODE_SUPPORT FF_T_WCHAR UTF16EntryBuffer[32]; #endif - + #ifdef FF_HASH_CACHE FF_T_UINT32 ulHash; #endif @@ -189,7 +201,7 @@ #elif FF_HASH_FUNCTION == CRC8 ulHash = (FF_T_UINT32) FF_GetCRC8((FF_T_UINT8 *) szShortName, strlen(szShortName)); #endif - + if(!FF_CheckDirentHash(pIoman, ulDirCluster, ulHash)) { return FF_FALSE; } @@ -197,15 +209,14 @@ #endif *pError = FF_InitEntryFetch(pIoman, ulDirCluster, &FetchContext); - if(*pError) { + if(FF_isERR(*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; + if(FF_isERR(*pError)) { + break; } Attrib = FF_getChar(EntryBuffer, FF_FAT_DIRENT_ATTRIB); if(FF_getChar(EntryBuffer, 0x00) != 0xE5) { @@ -218,7 +229,7 @@ FF_ProcessShortName((FF_T_INT8 *)EntryBuffer); #endif if(FF_isEndOfDir(EntryBuffer)) { - FF_CleanupEntryFetch(pIoman, &FetchContext); + *pError = FF_CleanupEntryFetch(pIoman, &FetchContext); return FF_FALSE; } #ifdef FF_UNICODE_SUPPORT @@ -226,14 +237,14 @@ #else if(strcmp(szShortName, (FF_T_INT8 *)EntryBuffer) == 0) { #endif - FF_CleanupEntryFetch(pIoman, &FetchContext); + *pError = FF_CleanupEntryFetch(pIoman, &FetchContext); return FF_TRUE; } } } } - FF_CleanupEntryFetch(pIoman, &FetchContext); + *pError = FF_CleanupEntryFetch(pIoman, &FetchContext); return FF_FALSE; } @@ -249,27 +260,35 @@ FF_T_UINT8 *lastSrc; #ifdef FF_UNICODE_UTF8_SUPPORT FF_T_SINT32 utf8Error; - FF_T_UINT8 bSurrogate = FF_FALSE; + //FF_T_UINT8 bSurrogate = FF_FALSE; #endif + + +#ifdef FF_LFN_SUPPORT + #ifdef FF_UNICODE_SUPPORT FF_T_WCHAR *ptr; // Pointer to store a LFN + FF_T_WCHAR *lastPtr = pDirent->FileName + sizeof(pDirent->FileName); #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_UINT16 lfnItem = 0; FF_T_UINT8 CheckSum = 0; + FF_T_INT8 numLFNs = 0; + FF_T_INT8 totalLFNs = 0; FF_T_UINT8 lastAttrib; - FF_T_INT8 totalLFNs = 0; - FF_T_INT8 numLFNs = 0; + FF_T_INT32 i; - FF_T_UINT16 lfnItem = 0; - pError = NULL; +#endif + + if(pError) { + *pError = FF_ERR_NONE; + } + pDirent->CurrentItem = 0; pDirent->Attrib = 0; @@ -282,14 +301,16 @@ 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); + *pError = FF_CleanupEntryFetch(pIoman, &FetchContext); return 0; } if (src[0] == 0xE5) { // Entry not used pDirent->Attrib = 0; continue; } +#ifdef FF_LFN_SUPPORT lastAttrib = pDirent->Attrib; +#endif pDirent->Attrib = FF_getChar(src, FF_FAT_DIRENT_ATTRIB); if((pDirent->Attrib & FF_FAT_ATTR_LFN) == FF_FAT_ATTR_LFN) { // LFN Processing @@ -312,7 +333,7 @@ // 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; @@ -329,7 +350,7 @@ ptr += utf8Error; } else { - if(utf8Error == FF_ERR_UNICODE_INVALID_SEQUENCE) { + if(FF_GETERROR(utf8Error) == FF_ERR_UNICODE_INVALID_SEQUENCE) { // Handle potential surrogate sequence across entries. } @@ -342,7 +363,7 @@ if(utf8Error > 0) { ptr += utf8Error; } else { - if(utf8Error == FF_ERR_UNICODE_INVALID_SEQUENCE) { + if(FF_GETERROR(utf8Error) == FF_ERR_UNICODE_INVALID_SEQUENCE) { // Handle potential surrogate sequence across entries. } } @@ -354,15 +375,14 @@ if(utf8Error > 0) { ptr += utf8Error; } else { - if(utf8Error == FF_ERR_UNICODE_INVALID_SEQUENCE) { + if(FF_GETERROR(utf8Error) == FF_ERR_UNICODE_INVALID_SEQUENCE) { // Handle potential surrogate sequence across entries. } } - } - -#endif -#ifndef FF_UNICODE_SUPPORT -#ifndef FF_UNICODE_UTF8_SUPPORT + } +#endif // FF_UNICODE_UTF8_SUPPORT + +#if !defined(FF_UNICODE_SUPPORT) && !defined(FF_UNICODE_UTF8_SUPPORT) for(i = 0; i < 10 && ptr < lastPtr; i += 2) *(ptr++) = src[FF_FAT_LFN_NAME_1 + i]; @@ -371,24 +391,22 @@ 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 +#endif // FF_LFN_SUPPORT continue; } if ((pDirent->Attrib & FF_FAT_ATTR_VOLID) == FF_FAT_ATTR_VOLID) { - totalLFNs = 0; +#ifdef FF_LFN_SUPPORT + totalLFNs = 0; +#endif continue; } #ifdef FF_LFN_SUPPORT - if(!totalLFNs || CheckSum != FF_CreateChkSum(src)) + if(!totalLFNs || CheckSum != FF_CreateChkSum(src)) #endif { #ifdef FF_UNICODE_SUPPORT @@ -400,7 +418,9 @@ memcpy(pDirent->FileName, src, 11); FF_ProcessShortName(pDirent->FileName); #endif +#ifdef FF_LFN_SUPPORT totalLFNs = 0; +#endif } if((pDirent->Attrib & pa_Attrib) == pa_Attrib){ @@ -412,22 +432,30 @@ // Finally get the complete information #ifdef FF_LFN_SUPPORT if (totalLFNs) { - FF_PopulateLongDirent(pIoman, pDirent, lfnItem, &FetchContext); + *pError = FF_PopulateLongDirent(pIoman, pDirent, lfnItem, &FetchContext); + if(FF_isERR(*pError)) { + FF_CleanupEntryFetch(pIoman, &FetchContext); + return 0; + } } else #endif { FF_PopulateShortDirent(pIoman, pDirent, src); + // HT: CurrentItem wasn't increased here + pDirent->CurrentItem += 1; } // Object found! - FF_CleanupEntryFetch(pIoman, &FetchContext); + *pError = FF_CleanupEntryFetch(pIoman, &FetchContext); return pDirent->ObjectCluster; // Return the cluster number } } +#ifdef FF_LFN_SUPPORT totalLFNs = 0; +#endif } } // for (src = FetchContext.pBuffer->pBuffer; src < lastSrc; src += 32, pDirent->CurrentItem++) - FF_CleanupEntryFetch(pIoman, &FetchContext); + *pError = FF_CleanupEntryFetch(pIoman, &FetchContext); return 0; } @@ -450,7 +478,7 @@ 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; @@ -463,11 +491,11 @@ if(pathLen <= 1) { // Must be the root dir! (/ or \) return pIoman->pPartition->RootDirCluster; } - + if(path[pathLen-1] == '\\' || path[pathLen-1] == '/') { - pathLen--; + pathLen--; } - + #ifdef FF_PATH_CACHE // Is the requested path in the PATH CACHE? FF_PendSemaphore(pIoman->pSemaphore); // Thread safety on shared object! { @@ -479,7 +507,7 @@ 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; } @@ -494,8 +522,7 @@ do{ MyDir.CurrentItem = 0; dirCluster = FF_FindEntryInDir(pIoman, dirCluster, token, FF_FAT_ATTR_DIR, &MyDir, pError); - - if(*pError) { + if(FF_isERR(*pError)) { return 0; } @@ -517,9 +544,9 @@ #endif pIoman->pPartition->PathCache[pIoman->pPartition->PCIndex].Path[pathLen] = '\0'; pIoman->pPartition->PathCache[pIoman->pPartition->PCIndex].DirCluster = dirCluster; -#ifdef FF_HASH_TABLE_SUPPORT +#ifdef FF_HASH_TABLE_SUPPORT FF_ClearHashTable(pIoman->pPartition->PathCache[pIoman->pPartition->PCIndex].pHashTable); -#endif +#endif pIoman->pPartition->PCIndex += 1; if(pIoman->pPartition->PCIndex >= FF_PATH_CACHE_DEPTH) { pIoman->pPartition->PCIndex = 0; @@ -601,14 +628,14 @@ 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) { name[i] = '\0'; @@ -636,29 +663,30 @@ }*/ #ifdef FF_TIME_SUPPORT -static void FF_PlaceTime(FF_T_UINT8 *EntryBuffer, FF_T_UINT32 Offset) { +static void FF_PlaceTime(FF_T_UINT8 *EntryBuffer, FF_T_UINT32 Offset, FF_SYSTEMTIME *pTime) { FF_T_UINT16 myShort; - FF_SYSTEMTIME str_t; - FF_GetSystemTime(&str_t); - + // HT time changes: + // E.g. Unzip needs to use original time rather than + // the result of FF_GetSystemTime + myShort = 0; - myShort |= ((str_t.Hour << 11) & 0xF800); - myShort |= ((str_t.Minute << 5) & 0x07E0); - myShort |= ((str_t.Second / 2) & 0x001F); + myShort |= ((pTime->Hour << 11) & 0xF800); + myShort |= ((pTime->Minute << 5) & 0x07E0); + myShort |= ((pTime->Second / 2) & 0x001F); FF_putShort(EntryBuffer, (FF_T_UINT16) Offset, myShort); } -static void FF_PlaceDate(FF_T_UINT8 *EntryBuffer, FF_T_UINT32 Offset) { +static void FF_PlaceDate(FF_T_UINT8 *EntryBuffer, FF_T_UINT32 Offset, FF_SYSTEMTIME *pTime) { FF_T_UINT16 myShort; - FF_SYSTEMTIME str_t; - FF_GetSystemTime(&str_t); - + // HT time changes: + // Unzip needs to use original date rather than + // the current date, so make it a parameter myShort = 0; - myShort |= (((str_t.Year- 1980) << 9) & 0xFE00) ; - myShort |= ((str_t.Month << 5) & 0x01E0); - myShort |= (str_t.Day & 0x001F); + myShort |= (((pTime->Year- 1980) << 9) & 0xFE00) ; + myShort |= ((pTime->Month << 5) & 0x01E0); + myShort |= (pTime->Day & 0x001F); FF_putShort(EntryBuffer, (FF_T_UINT16) Offset, myShort); } @@ -681,7 +709,7 @@ #endif void FF_PopulateShortDirent(FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_T_UINT8 *EntryBuffer) { - FF_T_UINT16 myShort; + //FF_T_UINT16 myShort; #ifdef FF_UNICODE_SUPPORT FF_T_WCHAR UTF16EntryBuffer[12]; FF_cstrntowcs(UTF16EntryBuffer, (FF_T_INT8 *) EntryBuffer, 11); @@ -692,8 +720,7 @@ #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. - + FF_ProcessShortName(pDirent->ShortName); // For debuggers only #endif FF_ProcessShortName(pDirent->FileName); // Format the shortname, for pleasant viewing. @@ -704,7 +731,7 @@ FF_AddDirentHash(pIoman, pDirent->DirCluster, (FF_T_UINT32)FF_GetCRC8((FF_T_UINT8 *) pDirent->FileName, strlen(pDirent->FileName))); #endif*/ #else - pIoman = NULL; // Silence a compiler warning, about not referencing pIoman. + if (pIoman) {} // Silence a compiler warning, about not referencing pIoman. #endif #ifdef FF_UNICODE_SUPPORT @@ -714,17 +741,17 @@ #endif // Get the item's Cluster address. - 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; + pDirent->ObjectCluster = + ((FF_T_UINT32)FF_getShort(EntryBuffer, FF_FAT_DIRENT_CLUS_HIGH) << 16) | + (FF_T_UINT32)FF_getShort(EntryBuffer, FF_FAT_DIRENT_CLUS_LOW); #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); + // HT Here CreateTime became ModifiedTime: + FF_GetTime(&pDirent->ModifiedTime, EntryBuffer, FF_FAT_DIRENT_LASTMOD_TIME); + FF_GetDate(&pDirent->ModifiedTime, 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; @@ -741,19 +768,19 @@ 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) { + if(FF_isERR(Error)) { return Error; } pContext->ulDirCluster = ulDirCluster; pContext->ulCurrentClusterLCN = ulDirCluster; - pContext->ulCurrentClusterNum = 0; - pContext->ulCurrentEntry = 0; +// pContext->ulCurrentClusterNum = 0; // memset has cleared it +// pContext->ulCurrentEntry = 0; if(pIoman->pPartition->Type != FF_T_FAT32) { // Handle Root Dirs that don't have cluster chains! @@ -769,72 +796,112 @@ return FF_ERR_NONE; } -void FF_CleanupEntryFetch(FF_IOMAN *pIoman, FF_FETCH_CONTEXT *pContext) { +FF_ERROR FF_CleanupEntryFetch(FF_IOMAN *pIoman, FF_FETCH_CONTEXT *pContext) { + FF_ERROR Error = FF_ERR_NONE; if(pContext->pBuffer) { - FF_ReleaseBuffer(pIoman, pContext->pBuffer); + Error = FF_ReleaseBuffer(pIoman, pContext->pBuffer); pContext->pBuffer = NULL; } + return Error; } -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; +/** + * @private + * @brief Find the cluster for a given Entry within a directory + * @brief Make an exception for the root directory (non FAT32 only): + * @brief Just calculate the cluster (don't consult the actual FAT) + * + * @param pIoman FF_IOMAN object that was created by FF_CreateIOMAN(). + * @param ulEntry The sequence number of the entry of interest + * @param pContext Context of current search + * + * @return FF_ERR_NONE on success + * @return Possible error returned by FF_TraverseFAT() or END_OF_DIR + * + * Side effects: + * - pContext->ulCurrentClusterNum : relative cluster number (0 <= Num < ulChainLength) + * - pContext->ulCurrentClusterLCN : fysical cluster on the partition + **/ + +static FF_ERROR FF_Traverse(FF_IOMAN *pIoman, FF_T_UINT32 ulEntry, FF_FETCH_CONTEXT *pContext) +{ + FF_T_UINT32 ulClusterNum = FF_getClusterChainNumber(pIoman, ulEntry, (FF_T_UINT16)32); FF_ERROR Error; - ulClusterNum = FF_getClusterChainNumber(pIoman, ulEntry, (FF_T_UINT16)32); - ulRelItem = FF_getMinorBlockEntry (pIoman, ulEntry, (FF_T_UINT16)32); + // Check if we're past the last cluster (ulChainLength is also valid for root sectors) + if((ulClusterNum + 1) > pContext->ulChainLength) { + return FF_ERR_DIR_END_OF_DIR | FF_TRAVERSE; // End of Dir was reached! + } - if(ulClusterNum != pContext->ulCurrentClusterNum) { + if(pIoman->pPartition->Type != FF_T_FAT32 && + pContext->ulDirCluster == pIoman->pPartition->RootDirCluster) { + // Double-check if the entry number isn't too high + if(ulEntry > ((pIoman->pPartition->RootDirSectors * pIoman->pPartition->BlkSize) / 32)) { + return FF_ERR_DIR_END_OF_DIR | FF_FETCHENTRYWITHCONTEXT; + } + pContext->ulCurrentClusterLCN = pContext->ulDirCluster;// + ulClusterNum; + } else if(ulClusterNum != pContext->ulCurrentClusterNum) { // Traverse the fat gently! if(ulClusterNum > pContext->ulCurrentClusterNum) { + // Start traverse from the current entry pContext->ulCurrentClusterLCN = FF_TraverseFAT(pIoman, pContext->ulCurrentClusterLCN, (ulClusterNum - pContext->ulCurrentClusterNum), &Error); - if(Error) { + if(FF_isERR(Error)) { return Error; } } else { + // Start traverse from the beginning pContext->ulCurrentClusterLCN = FF_TraverseFAT(pIoman, pContext->ulDirCluster, ulClusterNum, &Error); - if(Error) { + if(FF_isERR(Error)) { return Error; } } - pContext->ulCurrentClusterNum = ulClusterNum; } + pContext->ulCurrentClusterNum = ulClusterNum; + return FF_ERR_NONE; +} - 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; - } - } +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; + + Error = FF_Traverse(pIoman, ulEntry, pContext); + if(FF_isERR(Error)) { + return Error; } - if((ulClusterNum + 1) > pContext->ulChainLength) { - return FF_ERR_DIR_END_OF_DIR; // End of Dir was reached! + //ulClusterNum = pContext->ulCurrentClusterNum; + ulRelItem = FF_getMinorBlockEntry (pIoman, ulEntry, (FF_T_UINT16)32); + + ulItemLBA = FF_Cluster2LBA (pIoman, pContext->ulCurrentClusterLCN) + FF_getMajorBlockNumber(pIoman, ulEntry, (FF_T_UINT16)32); + if(pIoman->pPartition->Type != FF_T_FAT32 && + pContext->ulDirCluster == pIoman->pPartition->RootDirCluster) { + ulItemLBA += (ulEntry / ((pIoman->pPartition->BlkSize *pIoman->pPartition->SectorsPerCluster)/32) * pIoman->pPartition->SectorsPerCluster); } - 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); + ulItemLBA = FF_getRealLBA (pIoman, ulItemLBA) + FF_getMinorBlockNumber(pIoman, ulRelItem, (FF_T_UINT16)32); - if(!pContext->pBuffer || (pContext->pBuffer->Sector != ulItemLBA)) { + if(!pContext->pBuffer || + (pContext->pBuffer->Sector != ulItemLBA) || + (pContext->pBuffer->Mode & FF_MODE_WRITE)) { if(pContext->pBuffer) { - FF_ReleaseBuffer(pIoman, pContext->pBuffer); + Error = FF_ReleaseBuffer(pIoman, pContext->pBuffer); + if(FF_isERR(Error)) { + return Error; + } } pContext->pBuffer = FF_GetBuffer(pIoman, ulItemLBA, FF_MODE_READ); if(!pContext->pBuffer) { - return FF_ERR_DEVICE_DRIVER_FAILED; + return FF_ERR_DEVICE_DRIVER_FAILED | FF_FETCHENTRYWITHCONTEXT; } } - + if (pEntryBuffer) { // HT Because it might be called with NULL memcpy(pEntryBuffer, (pContext->pBuffer->pBuffer + (ulRelItem*32)), 32); } - + return FF_ERR_NONE; } @@ -842,61 +909,46 @@ 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_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; + Error = FF_Traverse(pIoman, ulEntry, pContext); + if(FF_isERR(Error)) { + return Error; } - 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; - } - } - } + //ulClusterNum = pContext->ulCurrentClusterNum; + ulRelItem = FF_getMinorBlockEntry (pIoman, ulEntry, (FF_T_UINT16)32); - if((ulClusterNum + 1) > pContext->ulChainLength) { - return FF_ERR_DIR_END_OF_DIR; // End of Dir was reached! + ulItemLBA = FF_Cluster2LBA (pIoman, pContext->ulCurrentClusterLCN) + FF_getMajorBlockNumber(pIoman, ulEntry, (FF_T_UINT16)32); + if(pIoman->pPartition->Type != FF_T_FAT32 && + pContext->ulDirCluster == pIoman->pPartition->RootDirCluster) { + ulItemLBA += (ulEntry / ((pIoman->pPartition->BlkSize *pIoman->pPartition->SectorsPerCluster)/32) * pIoman->pPartition->SectorsPerCluster); } - 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); + ulItemLBA = FF_getRealLBA (pIoman, ulItemLBA) + FF_getMinorBlockNumber(pIoman, ulRelItem, (FF_T_UINT16)32); - if(!pContext->pBuffer || (pContext->pBuffer->Sector != ulItemLBA)) { + if(!pContext->pBuffer || + (pContext->pBuffer->Sector != ulItemLBA) || + !(pContext->pBuffer->Mode & FF_MODE_WRITE)) { if(pContext->pBuffer) { - FF_ReleaseBuffer(pIoman, pContext->pBuffer); + Error = FF_ReleaseBuffer(pIoman, pContext->pBuffer); + if(FF_isERR(Error)) { + return Error; + } } - pContext->pBuffer = FF_GetBuffer(pIoman, ulItemLBA, FF_MODE_READ); + pContext->pBuffer = FF_GetBuffer(pIoman, ulItemLBA, FF_MODE_WRITE); if(!pContext->pBuffer) { - return FF_ERR_DEVICE_DRIVER_FAILED; + return FF_ERR_DEVICE_DRIVER_FAILED | FF_FETCHENTRYWITHCONTEXT; } } + // Now change the entry: memcpy((pContext->pBuffer->pBuffer + (ulRelItem*32)), pEntryBuffer, 32); - pContext->pBuffer->Mode = FF_MODE_WRITE; - pContext->pBuffer->Modified = FF_TRUE; - +// HT: this would be against the rules :-) +// pContext->pBuffer->Mode = FF_MODE_WRITE; +// pContext->pBuffer->Modified = FF_TRUE; + return FF_ERR_NONE; } @@ -905,62 +957,73 @@ * @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_FETCH_CONTEXT FetchContext; - FF_ERROR Error; + FF_ERROR Error; +#ifndef FF_LFN_SUPPORT + FF_T_UINT8 numLFNs; +#endif Error = FF_InitEntryFetch(pIoman, DirCluster, &FetchContext); - if(Error) { + if(FF_isERR(Error)) { return Error; } - + Error = FF_FetchEntryWithContext(pIoman, nEntry, &FetchContext, EntryBuffer); - if(Error) { - FF_CleanupEntryFetch(pIoman, &FetchContext); + if(FF_isERR(Error)) { + FF_CleanupEntryFetch(pIoman, &FetchContext); // Error already, skip error checking. return Error; } if(EntryBuffer[0] != 0xE5) { if(FF_isEndOfDir(EntryBuffer)){ - FF_CleanupEntryFetch(pIoman, &FetchContext); - return FF_ERR_DIR_END_OF_DIR; + Error = FF_CleanupEntryFetch(pIoman, &FetchContext); + if(FF_isERR(Error)) { + return Error; + } + return FF_ERR_DIR_END_OF_DIR | FF_GETENTRY; } - + 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); #ifdef FF_LFN_SUPPORT Error = FF_PopulateLongDirent(pIoman, pDirent, nEntry, &FetchContext); - FF_CleanupEntryFetch(pIoman, &FetchContext); - if(Error) { + if(FF_isERR(Error)) { + FF_CleanupEntryFetch(pIoman, &FetchContext); // Returning error dont check here. return Error; } + + Error = FF_CleanupEntryFetch(pIoman, &FetchContext); + if(FF_isERR(Error)) { + return Error; + } + return FF_ERR_NONE; - #else + #else + // LFN Processing + numLFNs = (FF_T_UINT8)(EntryBuffer[0] & ~0x40); 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; - FF_CleanupEntryFetch(pIoman, &FetchContext); + Error = FF_CleanupEntryFetch(pIoman, &FetchContext); + if(FF_isERR(Error)) { + return Error; + } return 0; } } - FF_CleanupEntryFetch(pIoman, &FetchContext); - return FF_ERR_NONE; + return FF_CleanupEntryFetch(pIoman, &FetchContext); } FF_T_BOOL FF_isEndOfDir(FF_T_UINT8 *EntryBuffer) { - if(EntryBuffer[0] == 0x00) { - return FF_TRUE; - } - return FF_FALSE; + return !(EntryBuffer[0]); } #ifdef FF_HASH_CACHE @@ -1016,6 +1079,7 @@ FF_FETCH_CONTEXT FetchContext; FF_T_UINT8 EntryBuffer[32], ucAttrib; FF_T_UINT32 ulHash; + FF_ERROR Error; if(FF_DirHashed(pIoman, ulDirCluster)) { return FF_ERR_NONE; // Don't wastefully re-hash a dir! @@ -1040,9 +1104,9 @@ FF_ClearHashTable(pHashCache->pHashTable); pHashCache->ulDirCluster = ulDirCluster; pHashCache->ulMisses = 0; - + // Hash the directory! - + FF_InitEntryFetch(pIoman, ulDirCluster, &FetchContext); for(i = 0; i < 0xFFFF; i++) { @@ -1055,10 +1119,13 @@ FF_ProcessShortName((FF_T_INT8 *)EntryBuffer); if(FF_isEndOfDir(EntryBuffer)) { // HT uncommented - FF_CleanupEntryFetch(pIoman, &FetchContext); + Error = FF_CleanupEntryFetch(pIoman, &FetchContext); + if(FF_isERR(Error)) { + return Error; + } return FF_ERR_NONE; } - + // Generate the Hash #if FF_HASH_FUNCTION == CRC16 ulHash = FF_GetCRC16(EntryBuffer, strlen((const FF_T_INT8 *) EntryBuffer)); @@ -1066,12 +1133,15 @@ ulHash = FF_GetCRC8(EntryBuffer, strlen((const FF_T_INT8 *) EntryBuffer)); #endif FF_SetHash(pHashCache->pHashTable, ulHash); - + } } } - FF_CleanupEntryFetch(pIoman, &FetchContext); + Error = FF_CleanupEntryFetch(pIoman, &FetchContext); + if(FF_isERR(Error)) { + return Error; + } return FF_ERR_NONE; } @@ -1096,14 +1166,27 @@ FF_ERROR Error; FF_T_UINT uiNumLFNs; +#ifdef FF_UNICODE_SUPPORT FF_T_UINT uiLfnLength = 0; +#endif +#ifndef FF_UNICODE_SUPPORT + FF_T_UINT i,y; +#endif + +#ifdef FF_UNICODE_SUPPORT +// FF_T_WCHAR *lastPtr = pDirent->FileName + sizeof(pDirent->FileName); +// FF_T_WCHAR *ptr; +#else +#ifndef FF_UNICODE_UTF8_SUPPORT + FF_T_INT8 *lastPtr = pDirent->FileName + sizeof (pDirent->FileName); + FF_T_INT8 *ptr; +#endif +#endif #ifdef FF_UNICODE_UTF8_SUPPORT - FF_T_UINT i,y; // FF_T_SINT32 slRetVal; FF_T_UINT16 nLfnBegin; FF_T_UINT16 usUtf8Len = 0; #endif - FF_T_UINT16 myShort; FF_T_UINT8 ucCheckSum; FF_T_UINT8 EntryBuffer[32]; @@ -1117,7 +1200,7 @@ #endif Error = FF_FetchEntryWithContext(pIoman, nEntry++, pFetchContext, EntryBuffer); - if(Error) { + if(FF_isERR(Error)) { return Error; } @@ -1138,7 +1221,7 @@ uiLfnLength += 13; Error = FF_FetchEntryWithContext(pIoman, nEntry++, pFetchContext, EntryBuffer); - if(Error) { + if(FF_isERR(Error)) { return Error; } uiNumLFNs--; @@ -1153,10 +1236,10 @@ for(i = 0; i < uiNumLFNs; i++) { Error = FF_FetchEntryWithContext(pIoman, (nLfnBegin + (uiNumLFNs - 1) - i), pFetchContext, EntryBuffer); - if(Error) { + if(FF_isERR(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); @@ -1182,45 +1265,40 @@ } pDirent->FileName[usUtf8Len] = '\0'; - + // Put Entry context to correct position. Error = FF_FetchEntryWithContext(pIoman, nEntry-1, pFetchContext, EntryBuffer); - if(Error) { + if(FF_isERR(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)]; +#if !defined(FF_UNICODE_SUPPORT) && !defined(FF_UNICODE_UTF8_SUPPORT) // No Unicode, simple ASCII. + lastPtr[-1] = '\0'; + y = uiNumLFNs; + while(uiNumLFNs--) { + ptr = pDirent->FileName + (uiNumLFNs * 13); + for(i = 0; i < 10 && ptr < lastPtr; i += 2) { + *(ptr++) = EntryBuffer[FF_FAT_LFN_NAME_1 + i]; } - 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 < 12 && ptr < lastPtr; i += 2) { + *(ptr++) = EntryBuffer[FF_FAT_LFN_NAME_2 + i]; } - for(i = 0; i < 2; i++) { - pDirent->FileName[((uiNumLFNs - 1) * 13) + i + 11] = EntryBuffer[FF_FAT_LFN_NAME_3 + (i*2)]; + for(i = 0; i < 4 && ptr < lastPtr; i += 2) { + *(ptr++) = EntryBuffer[FF_FAT_LFN_NAME_3 + i]; } + if (uiNumLFNs == y-1 && ptr < lastPtr) + *ptr = '\0'; - uiLfnLength += 13; - Error = FF_FetchEntryWithContext(pIoman, nEntry++, pFetchContext, EntryBuffer); - if(Error) { + if(FF_isERR(Error)) { return Error; } - uiNumLFNs--; } - - pDirent->FileName[uiLfnLength] = '\0'; - - #endif -#endif // Process the Shortname. -- LFN Transformation is now complete. // Process the ShortName Entry @@ -1247,20 +1325,21 @@ } // 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; + pDirent->ObjectCluster = + ((FF_T_UINT32)FF_getShort(EntryBuffer, FF_FAT_DIRENT_CLUS_HIGH) << 16) | + (FF_T_UINT32)FF_getShort(EntryBuffer, FF_FAT_DIRENT_CLUS_LOW); #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); + // HT Here CreateTime has become ModifiedTime, as it should: + FF_GetTime(&pDirent->ModifiedTime, EntryBuffer, FF_FAT_DIRENT_LASTMOD_TIME); + FF_GetDate(&pDirent->ModifiedTime, EntryBuffer, FF_FAT_DIRENT_LASTMOD_DATE); // Get the last accessed Date. FF_GetDate(&pDirent->AccessedTime, EntryBuffer, FF_FAT_DIRENT_LASTACC_DATE); + // HT Why should these times be zero'd ? pDirent->AccessedTime.Hour = 0; pDirent->AccessedTime.Minute = 0; pDirent->AccessedTime.Second = 0; @@ -1270,7 +1349,7 @@ 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; @@ -1305,9 +1384,9 @@ FF_T_UINT16 lenlfn = 0; FF_T_UINT16 myShort; FF_ERROR Error; - + Error = FF_FetchEntryWithContext(pIoman, nEntry++, pFetchContext, EntryBuffer); - if(Error) { + if(FF_isERR(Error)) { return Error; } @@ -1353,7 +1432,7 @@ 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. + // 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++; @@ -1372,7 +1451,7 @@ #endif Error = FF_FetchEntryWithContext(pIoman, nEntry++, pFetchContext, EntryBuffer); - if(Error) { + if(FF_isERR(Error)) { return Error; } numLFNs--; @@ -1393,7 +1472,7 @@ #else pDirent->FileName[lenlfn] = '\0'; #endif - + // Process the ShortName Entry #ifdef FF_UNICODE_SUPPORT FF_cstrntowcs(UTF16EntryBuffer, (FF_T_INT8 *) EntryBuffer, 32); @@ -1419,7 +1498,7 @@ FF_AddDirentHash(pIoman, DirCluster, (FF_T_UINT32)FF_GetCRC8((FF_T_UINT8 *) ShortName, strlen(ShortName))); #endif*//* #endif - + 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)); @@ -1443,7 +1522,7 @@ 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; @@ -1493,7 +1572,7 @@ #endif FF_ERROR Error; -#ifdef FF_FINDAPI_ALLOW_WILDCARDS +#ifdef FF_FINDAPI_ALLOW_WILDCARDS FF_T_UINT16 i = 0; #ifdef FF_UNICODE_SUPPORT const FF_T_WCHAR *szWildCard; // Check for a Wild-card. @@ -1503,12 +1582,17 @@ #endif if(!pIoman) { - return FF_ERR_NULL_POINTER; + return FF_ERR_NULL_POINTER | FF_FINDFIRST; } + memset(pDirent, 0, sizeof(FF_DIRENT)); + // 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. + pDirent->DirCluster = FF_FindDir(pIoman, path, PathLen, &Error); // Get the directory cluster, if it exists. + if(FF_isERR(Error)) { + return Error; + } #endif #ifdef FF_FINDAPI_ALLOW_WILDCARDS @@ -1525,9 +1609,9 @@ } } } - + pDirent->DirCluster = FF_FindDir(pIoman, path, PathLen - i, &Error); - if(Error) { + if(FF_isERR(Error)) { return Error; } if(pDirent->DirCluster) { @@ -1537,22 +1621,27 @@ #else strncpy(pDirent->szWildCard, ++szWildCard, FF_MAX_FILENAME); #endif + if(pDirent->szWildCard[i-1] == ':') { + pDirent->bInvertWildCard = 1; + pDirent->szWildCard[i-1] = '\0'; + } } #endif if(pDirent->DirCluster == 0) { - return FF_ERR_DIR_INVALID_PATH; + return FF_ERR_DIR_INVALID_PATH | FF_FINDFIRST; } // Initialise the Fetch Context Error = FF_InitEntryFetch(pIoman, pDirent->DirCluster, &pDirent->FetchContext); - if(Error) { + if(FF_isERR(Error)) { return Error; } - + pDirent->CurrentItem = 0; return FF_FindNext(pIoman, pDirent); + } /** @@ -1569,25 +1658,26 @@ * **/ FF_ERROR FF_FindNext(FF_IOMAN *pIoman, FF_DIRENT *pDirent) { - + FF_ERROR Error; FF_T_UINT8 numLFNs; FF_T_UINT8 EntryBuffer[32]; + FF_T_BOOL b; if(!pIoman) { - return FF_ERR_NULL_POINTER; + return FF_ERR_NULL_POINTER | FF_FINDNEXT; } - + for(; pDirent->CurrentItem < 0xFFFF; pDirent->CurrentItem += 1) { Error = FF_FetchEntryWithContext(pIoman, pDirent->CurrentItem, &pDirent->FetchContext, EntryBuffer); - if(Error) { - FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); + if(FF_isERR(Error)) { + FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); // Don't check errors, already passing an error. return Error; } if(EntryBuffer[0] != FF_FAT_DELETED) { if(FF_isEndOfDir(EntryBuffer)){ FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); - return FF_ERR_DIR_END_OF_DIR; + return FF_ERR_DIR_END_OF_DIR | FF_FINDNEXT; } pDirent->Attrib = FF_getChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB)); if((pDirent->Attrib & FF_FAT_ATTR_LFN) == FF_FAT_ATTR_LFN) { @@ -1598,14 +1688,14 @@ // Fetch the shortname, and get it's checksum, or for a deleted item with // orphaned LFN entries. Error = FF_FetchEntryWithContext(pIoman, (pDirent->CurrentItem + numLFNs), &pDirent->FetchContext, EntryBuffer); - if(Error) { + if(FF_isERR(Error)) { FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); return Error; } - + if(EntryBuffer[0] != FF_FAT_DELETED) { Error = FF_PopulateLongDirent(pIoman, pDirent, pDirent->CurrentItem, &pDirent->FetchContext); - if(Error) { + if(FF_isERR(Error)) { FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); return Error; } @@ -1615,30 +1705,45 @@ #ifdef FF_FINDAPI_ALLOW_WILDCARDS #ifdef FF_UNICODE_SUPPORT - if(wcscmp(pDirent->szWildCard, L"")) { + if(wcscmp(pDirent->szWildCard, L"")) #else - if(strcmp(pDirent->szWildCard, "")) { + if(pDirent->szWildCard[0]) #endif - if(FF_wildcompare(pDirent->szWildCard, pDirent->FileName)) { - FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); - return FF_ERR_NONE; + { // HT put single bracket here because of bracket-matching within editor + b = FF_wildcompare(pDirent->szWildCard, pDirent->FileName); + if(pDirent->bInvertWildCard) { + b = !b; } + if(b) { + Error = FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); + if(FF_isERR(Error)) { + return Error; + } + return FF_ERR_NONE; + } + pDirent->CurrentItem -= 1; } else { - FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); + Error = FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); + if(FF_isERR(Error)) { + return Error; + } return FF_ERR_NONE; } #else - FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); + Error = FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); + if(FF_isERR(Error)) { + return Error; + } return FF_ERR_NONE; #endif } -#else +#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); #if defined(FF_SHORTNAME_CASE) @@ -1646,43 +1751,54 @@ 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); + if(pDirent->szWildCard[0]) { + b = FF_wildcompare(pDirent->szWildCard, pDirent->FileName); + if(pDirent->bInvertWildCard) { + b = !b; + } + if(b) { pDirent->CurrentItem += 1; + Error = FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); + if(FF_isERR(Error)) { + return Error; + } return FF_ERR_NONE; } } else { - FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); pDirent->CurrentItem += 1; + Error = FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); + if(FF_isERR(Error)) { + return Error; + } return FF_ERR_NONE; } #else + pDirent->CurrentItem += 1; FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); - pDirent->CurrentItem += 1; + if(FF_isERR(Error)) { + return Error; + } return FF_ERR_NONE; #endif } } } + Error = FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); + if(FF_isERR(Error)) { + return Error; + } - FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); - - return FF_ERR_DIR_END_OF_DIR; + return FF_ERR_DIR_END_OF_DIR | FF_FINDNEXT; } -FF_T_SINT8 FF_RewindFind(FF_IOMAN *pIoman, FF_DIRENT *pDirent) { +FF_ERROR FF_RewindFind(FF_IOMAN *pIoman, FF_DIRENT *pDirent) { if(!pIoman) { - return FF_ERR_NULL_POINTER; + return FF_ERR_NULL_POINTER | FF_REWINDFIND; } pDirent->CurrentItem = 0; - return 0; + return FF_ERR_NONE; } /* @@ -1692,104 +1808,116 @@ static 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_T_UINT16 freeCount = 0; + FF_T_UINT nEntry; FF_ERROR Error; FF_T_UINT32 DirLength; FF_FETCH_CONTEXT FetchContext; Error = FF_InitEntryFetch(pIoman, DirCluster, &FetchContext); - if(Error) { + if(FF_isERR(Error)) { return Error; } - + for(nEntry = 0; nEntry < 0xFFFF; nEntry++) { Error = FF_FetchEntryWithContext(pIoman, nEntry, &FetchContext, EntryBuffer); - if(Error == FF_ERR_DIR_END_OF_DIR) { - + if(FF_GETERROR(Error) == FF_ERR_DIR_END_OF_DIR) { + Error = FF_ExtendDirectory(pIoman, DirCluster); - FF_CleanupEntryFetch(pIoman, &FetchContext); + if(FF_isERR(Error)) { + FF_CleanupEntryFetch(pIoman, &FetchContext); + return Error; + } - if(Error) { + Error = FF_CleanupEntryFetch(pIoman, &FetchContext); + if(FF_isERR(Error)) { return Error; } return nEntry; } else { - if(Error) { - FF_CleanupEntryFetch(pIoman, &FetchContext); + if(FF_isERR(Error)) { + FF_CleanupEntryFetch(pIoman, &FetchContext); // Dont override the current error! return Error; } } if(FF_isEndOfDir(EntryBuffer)) { // If its the end of the Dir, then FreeDirents from here. // Check Dir is long enough! DirLength = FetchContext.ulChainLength;//FF_GetChainLength(pIoman, DirCluster, &iEndOfChain); - if((nEntry + Sequential) > (FF_T_UINT16)(((pIoman->pPartition->SectorsPerCluster * pIoman->pPartition->BlkSize) * DirLength) / 32)) { + if((nEntry + Sequential) > ((DirLength * ((FF_T_UINT)pIoman->pPartition->SectorsPerCluster * pIoman->pPartition->BlkSize)) / 32)) { Error = FF_ExtendDirectory(pIoman, DirCluster); } + if(FF_isERR(Error)) { + FF_CleanupEntryFetch(pIoman, &FetchContext); + return Error; + } - FF_CleanupEntryFetch(pIoman, &FetchContext); - - if(Error) { + Error = FF_CleanupEntryFetch(pIoman, &FetchContext); + if(FF_isERR(Error)) { return Error; } return nEntry; } if(EntryBuffer[0] == 0xE5) { - i++; + freeCount++; } else { - i = 0; + freeCount = 0; } - if(i == Sequential) { - FF_CleanupEntryFetch(pIoman, &FetchContext); + if(freeCount == Sequential) { + Error = FF_CleanupEntryFetch(pIoman, &FetchContext); + if(FF_isERR(Error)) { + return Error; + } return (nEntry - (Sequential - 1));// Return the beginning entry in the sequential sequence. } } - - FF_CleanupEntryFetch(pIoman, &FetchContext); - return FF_ERR_DIR_DIRECTORY_FULL; + Error = FF_CleanupEntryFetch(pIoman, &FetchContext); + if(FF_isERR(Error)) { + return Error; + } + + return FF_ERR_DIR_DIRECTORY_FULL | FF_FINDFREEDIRENT; } - - - - 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, &Error); + FF_T_UINT8 EntryBuffer[32]; + FF_FETCH_CONTEXT FetchContext; - 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); - 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); + // HT: use the standard access routine to get the same logic for root dirs + Error = FF_InitEntryFetch(pIoman, DirCluster, &FetchContext); + if(!FF_isERR(Error)) { + Error = FF_FetchEntryWithContext(pIoman, Entry, &FetchContext, EntryBuffer); + if(!FF_isERR(Error)) { + // Cleanup probably not necessary here? + // FF_PushEntryWithContext checks for R/W flag + Error = FF_CleanupEntryFetch(pIoman, &FetchContext); + if(FF_isERR(Error)) { + goto cleanup; + } + + FF_putChar(EntryBuffer, FF_FAT_DIRENT_ATTRIB, pDirent->Attrib); + FF_putShort(EntryBuffer, FF_FAT_DIRENT_CLUS_HIGH, (FF_T_UINT16)(pDirent->ObjectCluster >> 16)); + FF_putShort(EntryBuffer, FF_FAT_DIRENT_CLUS_LOW, (FF_T_UINT16)(pDirent->ObjectCluster)); + FF_putLong(EntryBuffer, FF_FAT_DIRENT_FILESIZE, pDirent->Filesize); #ifdef FF_TIME_SUPPORT - FF_PlaceDate((pBuffer->pBuffer + relItem), FF_FAT_DIRENT_LASTACC_DATE); // Last accessed date. + FF_GetSystemTime(&pDirent->AccessedTime); ///< Date of Last Access. + FF_PlaceTime(EntryBuffer, FF_FAT_DIRENT_LASTACC_DATE, &pDirent->AccessedTime); + FF_PlaceDate(EntryBuffer, FF_FAT_DIRENT_LASTACC_DATE, &pDirent->AccessedTime); // Last accessed date. + FF_PlaceTime(EntryBuffer, FF_FAT_DIRENT_CREATE_TIME, &pDirent->CreateTime); + FF_PlaceDate(EntryBuffer, FF_FAT_DIRENT_CREATE_DATE, &pDirent->CreateTime); + FF_PlaceTime(EntryBuffer, FF_FAT_DIRENT_LASTMOD_TIME, &pDirent->ModifiedTime); + FF_PlaceDate(EntryBuffer, FF_FAT_DIRENT_LASTMOD_DATE, &pDirent->ModifiedTime); #endif + Error = FF_PushEntryWithContext(pIoman, Entry, &FetchContext, EntryBuffer); + } } - FF_ReleaseBuffer(pIoman, pBuffer); - - return 0; + +cleanup: + FF_CleanupEntryFetch(pIoman, &FetchContext); + return Error; } FF_T_BOOL FF_ValidShortChar (FF_T_INT8 Chr) @@ -1808,9 +1936,9 @@ } #ifdef FF_UNICODE_SUPPORT -FF_T_SINT8 FF_CreateShortName(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_WCHAR *ShortName, FF_T_WCHAR *LongName) { +FF_T_SINT32 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_SINT32 FF_CreateShortName(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *ShortName, FF_T_INT8 *LongName) { #endif FF_T_UINT8 caseAttrib = 0; #if defined(FF_SHORTNAME_CASE) @@ -1826,8 +1954,9 @@ #endif FF_T_UINT16 NameLen; FF_T_BOOL FitsShort = FF_TRUE; + FF_T_BOOL SizeOk = FF_TRUE; FF_DIRENT MyDir; - FF_T_BOOL found; +// FF_T_BOOL found; //FF_T_SINT8 RetVal = 0; FF_T_INT8 NumberBuf[6]; FF_ERROR Error; @@ -1849,7 +1978,7 @@ } if (NameLen > 12 || NameLen-x > 1 || NameLen-last_dot > 4 || last_dot > 8) { - FitsShort = FF_FALSE; + SizeOk = FF_FALSE; } for(i = 0, x = 0; i < 11; x++) { @@ -1857,6 +1986,9 @@ if (!ch) break; if (x == last_dot) { + // Remember where we put the first space + if (first_tilde > i) + first_tilde = i; while (i < 8) ShortName[i++] = 0x20; #if defined(FF_SHORTNAME_CASE) @@ -1864,13 +1996,19 @@ #endif } else { if (i == 8) { - x = last_dot; - ch = (FF_T_INT8) LongName[x]; - if (ch) + // HT change + // Code hung with this filename: + // 'Chopin, Frederic - The Piano Works Op. 55, Op. 62, Op' + if (x <= last_dot) { + x = last_dot; + ch = (FF_T_INT8) LongName[x]; + if (!ch) + break; ch = (FF_T_INT8) LongName[++x]; #if defined(FF_SHORTNAME_CASE) - testAttrib = FF_FAT_CASE_ATTR_EXT; + testAttrib = FF_FAT_CASE_ATTR_EXT; #endif + } } if (!FF_ValidShortChar (ch)) { FitsShort = FF_FALSE; @@ -1902,33 +2040,35 @@ // Tail : memcpy(MyShortName, ShortName, 11); FF_ProcessShortName(MyShortName); - 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 && SizeOk) { + if (!FF_FindEntryInDir(pIoman, DirCluster, MyShortName, 0x00, &MyDir, &Error)) { + if(FF_isERR(Error)) { + return Error; + } + return caseAttrib | 0x01; + } + return FF_ERR_DIR_OBJECT_EXISTS | FF_CREATESHORTNAME; } - 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]; + for(i = (SizeOk ? 0 : 1); i < 0x0000FFFF; i++) { // Max Number of Entries in a DIR! + // In the first round, check if the original name can be used + // Makefile will be stored as "makefile" and not as "makefi~1" + if (i) { + 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) { + if(!FF_ShortNameExists(pIoman, DirCluster, MyShortName, &Error)) { +/* +// HT: will do this later when everything has been checked +// if not, hash entries might become incorrect #ifdef FF_HASH_CACHE #if FF_HASH_FUNCTION == CRC16 FF_AddDirentHash(pIoman, DirCluster, (FF_T_UINT32) FF_GetCRC16((FF_T_UINT8*)MyShortName, strlen(MyShortName))); @@ -1936,20 +2076,33 @@ FF_AddDirentHash(pIoman, DirCluster, (FF_T_UINT32) FF_GetCRC8((FF_T_UINT8*)MyShortName, strlen(MyShortName))); #endif #endif - return 0; +*/ + + if(FF_isERR(Error)) { + return Error; + } + return FF_ERR_NONE; } } // Add a tail and special number until we're happy :D - return FF_ERR_DIR_DIRECTORY_FULL; + return FF_ERR_DIR_DIRECTORY_FULL | FF_CREATESHORTNAME; } #ifdef FF_LFN_SUPPORT -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) { - +static FF_T_SINT8 FF_CreateLFNEntry(FF_T_UINT8 *EntryBuffer, FF_T_UINT8 *Name, FF_T_UINT uiNameLen, FF_T_UINT uiLFN, FF_T_UINT8 CheckSum) { + /* + * HT for JW: + * Changed *Name from 16- to of 8-bits + * The caller of this function doesn't need an expensive + * FF_T_UINT16 usUtf16Name[FF_MAX_FILENAME + 1]; + * in case UNICODE isn't used + * Also did quite a bit of optimisation here + * and tested well + */ FF_T_UINT i, x; - + memset(EntryBuffer, 0, 32); FF_putChar(EntryBuffer, FF_FAT_LFN_ORD, (FF_T_UINT8) ((uiLFN & ~0x40))); @@ -1957,114 +2110,50 @@ 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 < 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]; + i = 0; + for(x = FF_FAT_LFN_NAME_1; i < 5; i++, x += 2) { + if (i < uiNameLen) { + EntryBuffer[x] = *(Name++); +#if defined(FF_UNICODE_SUPPORT) || defined(FF_UNICODE_UTF8_SUPPORT) + EntryBuffer[x + 1] = *(Name++); +#endif + } else if (i > uiNameLen) { + EntryBuffer[x] = 0xFF; + EntryBuffer[x + 1] = 0xFF; } - 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) < 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; + for(x = FF_FAT_LFN_NAME_2; i < 11; i++, x += 2) { + if (i < uiNameLen) { + EntryBuffer[x] = *(Name++); +#if defined(FF_UNICODE_SUPPORT) || defined(FF_UNICODE_UTF8_SUPPORT) + EntryBuffer[x + 1] = *(Name++); +#endif + } else if (i > uiNameLen) { + EntryBuffer[x] = 0xFF; + EntryBuffer[x + 1] = 0xFF; } } // Name_3 - for(i = 0, x = 0; i < 2; i++, x += 2) { - 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; - } - } - - return FF_ERR_NONE; -} + for(x = FF_FAT_LFN_NAME_3; i < 13; i++, x += 2) { + if(i < uiNameLen) { + EntryBuffer[x] = *(Name++); +#if defined(FF_UNICODE_SUPPORT) || defined(FF_UNICODE_UTF8_SUPPORT) + EntryBuffer[x + 1] = *(Name++); #endif - -/* -#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 ++; - } else { - 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); - EntryBuffer[0] |= 0x40; - } else { - FF_CreateLFNEntry(EntryBuffer, (Name + (13 * (i - 1))), 13, i, CheckSum); + } else if (i > uiNameLen) { + EntryBuffer[x] = 0xFF; + EntryBuffer[x + 1] = 0xFF; } - - 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 -*/ - +#ifdef FF_LFN_SUPPORT #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 @@ -2081,21 +2170,30 @@ #ifndef FF_UNICODE_SUPPORT #ifndef FF_UNICODE_UTF8_SUPPORT - FF_T_UINT16 *pUtf16; + //FF_T_UINT16 *pUtf16; #endif #endif FF_FETCH_CONTEXT FetchContext; FF_T_UINT8 EntryBuffer[32]; + // HT: Save a stack-expensive declaration of "usUtf16Name" +#if defined(FF_UNICODE_SUPPORT) || defined(FF_UNICODE_UTF8_SUPPORT) FF_T_UINT16 usUtf16Name[FF_MAX_FILENAME + 1]; - +#endif +#ifndef FF_UNICODE_SUPPORT + FF_T_INT8 *NamePtr; +#else + FF_T_INT16 *NamePtr; +#endif + + #ifdef FF_UNICODE_SUPPORT #if WCHAR_MAX <= 0xFFFF y = wcslen(Name); if(y > FF_MAX_FILENAME) { - return FF_ERR_DIR_NAME_TOO_LONG; + return FF_ERR_DIR_NAME_TOO_LONG | FF_CREATELFNS; } wcsncpy(usUtf16Name, Name, FF_MAX_FILENAME); #else @@ -2106,12 +2204,11 @@ y += FF_GetUtf16SequenceLen(usUtf16Name[y]); i++; if(y > FF_MAX_FILENAME) { - return FF_ERR_DIR_NAME_TOO_LONG; + return FF_ERR_DIR_NAME_TOO_LONG | FF_CREATELFNS; } } #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. @@ -2126,23 +2223,16 @@ } y += FF_GetUtf16SequenceLen(usUtf16Name[y]); if(y > FF_MAX_FILENAME) { - return FF_ERR_DIR_NAME_TOO_LONG; + return FF_ERR_DIR_NAME_TOO_LONG | FF_CREATELFNS; } } -#else -#ifndef FF_UNICODE_SUPPORT - i = 0; +#elif !defined(FF_UNICODE_SUPPORT) + // Just check the length y = strlen(Name); if(y > FF_MAX_FILENAME) { - return FF_ERR_DIR_NAME_TOO_LONG; + return FF_ERR_DIR_NAME_TOO_LONG | FF_CREATELFNS; } - 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. @@ -2157,74 +2247,88 @@ } Error = FF_InitEntryFetch(pIoman, DirCluster, &FetchContext); - if(Error) { + if(FF_isERR(Error)) { return Error; } - +#if defined(FF_UNICODE_SUPPORT) + NamePtr = (FF_T_INT16*)(usUtf16Name + 13 * (uiNumLFNs-1)); +#elif defined(FF_UNICODE_UTF8_SUPPORT) + NamePtr = (FF_T_INT8*)(usUtf16Name + 13 * (uiNumLFNs-1)); +#else + NamePtr = Name + 13 * (uiNumLFNs-1); +#endif // 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); + FF_CreateLFNEntry(EntryBuffer, (FF_T_UINT8 *) NamePtr, uiEndPos, i, CheckSum); EntryBuffer[0] |= 0x40; } else { - FF_CreateLFNEntry(EntryBuffer, (usUtf16Name + (13 * (i - 1))), 13, i, CheckSum); + FF_CreateLFNEntry(EntryBuffer, (FF_T_UINT8 *) NamePtr, 13, i, CheckSum); } - +#if defined(FF_UNICODE_SUPPORT) || defined(FF_UNICODE_UTF8_SUPPORT) + NamePtr -= 13 * sizeof *usUtf16Name; +#else + NamePtr -= 13 * sizeof *Name; +#endif Error = FF_PushEntryWithContext(pIoman, nEntry + (uiNumLFNs - i), &FetchContext, EntryBuffer); - if(Error) { - FF_CleanupEntryFetch(pIoman, &FetchContext); + if(FF_isERR(Error)) { + FF_CleanupEntryFetch(pIoman, &FetchContext); // Dont override error! return Error; } } - FF_CleanupEntryFetch(pIoman, &FetchContext); + Error = FF_CleanupEntryFetch(pIoman, &FetchContext); + if(FF_isERR(Error)) { + return Error; + } return FF_ERR_NONE; } +#endif FF_ERROR FF_ExtendDirectory(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster) { FF_T_UINT32 CurrentCluster; FF_T_UINT32 NextCluster; FF_ERROR Error; + FF_FatBuffers FatBuf; if(pIoman->pPartition->Type != FF_T_FAT32) { if(DirCluster == pIoman->pPartition->RootDirCluster) { - return FF_ERR_DIR_CANT_EXTEND_ROOT_DIR; + return FF_ERR_DIR_CANT_EXTEND_ROOT_DIR | FF_EXTENDDIRECTORY; } } if(!pIoman->pPartition->FreeClusterCount) { pIoman->pPartition->FreeClusterCount = FF_CountFreeClusters(pIoman, &Error); - if(Error) { + if(FF_isERR(Error)) { return Error; } if(pIoman->pPartition->FreeClusterCount == 0) { - return FF_ERR_FAT_NO_FREE_CLUSTERS; + return FF_ERR_FAT_NO_FREE_CLUSTERS | FF_EXTENDDIRECTORY; } } - + FF_lockFAT(pIoman); { CurrentCluster = FF_FindEndOfChain(pIoman, DirCluster, &Error); - if(Error) { + if(FF_isERR(Error)) { FF_unlockFAT(pIoman); return Error; } NextCluster = FF_FindFreeCluster(pIoman, &Error); - if(Error) { + if(FF_isERR(Error)) { FF_unlockFAT(pIoman); return Error; } - Error = FF_putFatEntry(pIoman, CurrentCluster, NextCluster); - if(Error) { - FF_unlockFAT(pIoman); - return Error; + FF_InitFatBuffer (&FatBuf, FF_MODE_WRITE); + Error = FF_putFatEntry(pIoman, CurrentCluster, NextCluster, &FatBuf); + if(!FF_isERR(Error)) { + Error = FF_putFatEntry(pIoman, NextCluster, 0xFFFFFFFF, &FatBuf); } - - Error = FF_putFatEntry(pIoman, NextCluster, 0xFFFFFFFF); - if(Error) { + Error = FF_ReleaseFatBuffer(pIoman, &FatBuf); + if(FF_isERR(Error)) { FF_unlockFAT(pIoman); return Error; } @@ -2232,13 +2336,13 @@ FF_unlockFAT(pIoman); Error = FF_ClearCluster(pIoman, NextCluster); - if(Error) { + if(FF_isERR(Error)) { FF_unlockFAT(pIoman); return Error; } - + Error = FF_DecreaseFreeClusters(pIoman, 1); - if(Error) { + if(FF_isERR(Error)) { FF_unlockFAT(pIoman); return Error; } @@ -2246,42 +2350,43 @@ return FF_ERR_NONE; } +static const FF_T_UINT8 forbiddenChrs[] = { +// Windows says: don't use these characters: '\/:*?"<>|' +// " * / : < > ? '\' ? | + 0x22, 0x2A, 0x2F, 0x3A, 0x3C, 0x3E, 0x3F, 0x5C, 0x7F, 0x7C +}; #ifdef FF_UNICODE_SUPPORT static void FF_MakeNameCompliant(FF_T_WCHAR *Name) { #else static void FF_MakeNameCompliant(FF_T_UINT8 *Name) { #endif - + FF_T_INT index; if((FF_T_UINT8) Name[0] == 0xE5) { // Support Japanese KANJI symbol. Name[0] = 0x05; } - - while(*Name) { - if(*Name < 0x20 || *Name == 0x7F || *Name == 0x22 || *Name == 0x7C) { // Leave all extended chars as they are. - *Name = '_'; + for (; *Name; Name++) { + for (index = 0; index < sizeof forbiddenChrs; index++) { + if (*Name == forbiddenChrs[index]) { + *Name = '_'; + break; + } } - if(*Name >= 0x2A && *Name <= 0x2F && *Name != 0x2B && *Name != 0x2E && *Name != 0x2D) { - *Name = '_'; - } - if(*Name >= 0x3A && *Name <= 0x3F) { - *Name = '_'; - } - if(*Name >= 0x5B && *Name <= 0x5C) { - *Name = '_'; - } - Name++; } } FF_ERROR FF_CreateDirent(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent) { - + FF_T_UINT8 EntryBuffer[32]; +#ifdef FF_HASH_CACHE + FF_T_INT8 ShortName[13]; +#endif #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); + // HT calculate with roundup + FF_T_UINT8 numLFNs = (FF_T_UINT8) ((NameLen+12) / 13); FF_T_SINT32 FreeEntry; FF_ERROR RetVal = FF_ERR_NONE; FF_T_UINT8 Entries; @@ -2296,9 +2401,9 @@ 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; - }*/ + //if(FF_Utf32GetUtf16Len((FF_T_UINT32 *) pDirent->FileName) > FF_MAX_FILENAME) { + // return FF_ERR_UNICODE_CONVERSION_EXCEEDED; + //} #endif #endif @@ -2308,15 +2413,11 @@ #else FF_MakeNameCompliant((FF_T_UINT8 *)pDirent->FileName); // Ensure we don't break the Dir tables. #endif - memset(EntryBuffer, 0, 32); + memset(EntryBuffer, 0, sizeof EntryBuffer); - if(NameLen % 13) { - numLFNs ++; - } - #ifdef FF_LFN_SUPPORT // Create and push the LFN's - Entries = numLFNs + 1; // Find enough places for the LFNs and the ShortName + Entries = numLFNs + 1; // Find enough places for the LFNs and the ShortName #else Entries = 1; #endif @@ -2324,67 +2425,101 @@ // Create the ShortName FF_lockDIR(pIoman); { - if((FreeEntry = FF_FindFreeDirent(pIoman, DirCluster, Entries)) >= 0) { + // HT: As CreateShortName() can fail, it should be called before + // finding a free dir entry #ifdef FF_UNICODE_SUPPORT - //FF_cstrntowcs(UTF16EntryBuffer, (FF_T_INT8 *) EntryBuffer, 32); - RetVal = FF_CreateShortName(pIoman, DirCluster, UTF16EntryBuffer, pDirent->FileName); + //FF_cstrntowcs(UTF16EntryBuffer, (FF_T_INT8 *) EntryBuffer, 32); + FF_T_SINT32 FitShort = FF_CreateShortName(pIoman, DirCluster, UTF16EntryBuffer, pDirent->FileName); #else - RetVal = FF_CreateShortName(pIoman, DirCluster, (FF_T_INT8 *) EntryBuffer, pDirent->FileName); + FF_T_SINT32 FitShort = FF_CreateShortName(pIoman, DirCluster, (FF_T_INT8 *) EntryBuffer, pDirent->FileName); #endif - - //if(!RetVal) { + if (FF_isERR(FitShort)) { + RetVal = FitShort; + FF_unlockDIR(pIoman); + return RetVal; + } + if (FitShort) { + numLFNs = 0; + Entries = 1; + } + FreeEntry = FF_FindFreeDirent(pIoman, DirCluster, Entries); + if (FF_isERR(FreeEntry)) { + RetVal = FreeEntry; + } else { #ifdef FF_LFN_SUPPORT #ifdef FF_UNICODE_SUPPORT - FF_wcsntocstr((FF_T_INT8 *) EntryBuffer, UTF16EntryBuffer, 11); + FF_wcsntocstr((FF_T_INT8 *) EntryBuffer, UTF16EntryBuffer, 11); #endif + if (numLFNs) { CheckSum = FF_CreateChkSum(EntryBuffer); - FF_CreateLFNs(pIoman, DirCluster, pDirent->FileName, CheckSum, (FF_T_UINT16) FreeEntry); + RetVal = FF_CreateLFNs(pIoman, DirCluster, pDirent->FileName, CheckSum, (FF_T_UINT16) FreeEntry); + } #else - numLFNs = 0; -#endif - + numLFNs = 0; +#endif // FF_LFN_SUPPORT + if (!FF_isERR(RetVal)) { #ifdef FF_TIME_SUPPORT - FF_PlaceTime(EntryBuffer, FF_FAT_DIRENT_CREATE_TIME); - FF_PlaceDate(EntryBuffer, FF_FAT_DIRENT_CREATE_DATE); - FF_PlaceTime(EntryBuffer, FF_FAT_DIRENT_LASTMOD_TIME); - FF_PlaceDate(EntryBuffer, FF_FAT_DIRENT_LASTMOD_DATE); + FF_GetSystemTime(&pDirent->CreateTime); ///< Date and Time Created. + pDirent->ModifiedTime = pDirent->CreateTime; ///< Date and Time Modified. + pDirent->AccessedTime = pDirent->CreateTime; ///< Date of Last Access. + FF_PlaceTime(EntryBuffer, FF_FAT_DIRENT_CREATE_TIME, &pDirent->CreateTime); + FF_PlaceDate(EntryBuffer, FF_FAT_DIRENT_CREATE_DATE, &pDirent->CreateTime); + FF_PlaceTime(EntryBuffer, FF_FAT_DIRENT_LASTMOD_TIME, &pDirent->ModifiedTime); + FF_PlaceDate(EntryBuffer, FF_FAT_DIRENT_LASTMOD_DATE, &pDirent->ModifiedTime); #endif - FF_putChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB), pDirent->Attrib); - FF_putShort(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_HIGH), (FF_T_UINT16)(pDirent->ObjectCluster >> 16)); - 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_putChar(EntryBuffer, FF_FAT_DIRENT_ATTRIB, pDirent->Attrib); +#if defined(FF_SHORTNAME_CASE) + FF_putChar(EntryBuffer, FF_FAT_CASE_OFFS, FitShort & (FF_FAT_CASE_ATTR_BASE|FF_FAT_CASE_ATTR_EXT)); +#endif + FF_putShort(EntryBuffer, FF_FAT_DIRENT_CLUS_HIGH, (FF_T_UINT16)(pDirent->ObjectCluster >> 16)); + FF_putShort(EntryBuffer, FF_FAT_DIRENT_CLUS_LOW, (FF_T_UINT16)(pDirent->ObjectCluster)); + FF_putLong(EntryBuffer, FF_FAT_DIRENT_FILESIZE, pDirent->Filesize); RetVal = FF_InitEntryFetch(pIoman, DirCluster, &FetchContext); - if(RetVal) { + if(FF_isERR(RetVal)) { FF_unlockDIR(pIoman); return RetVal; } RetVal = FF_PushEntryWithContext(pIoman, (FF_T_UINT16) (FreeEntry + numLFNs), &FetchContext, EntryBuffer); - FF_CleanupEntryFetch(pIoman, &FetchContext); - if(RetVal) { + if(FF_isERR(RetVal)) { + FF_CleanupEntryFetch(pIoman, &FetchContext); FF_unlockDIR(pIoman); return RetVal; } - /*} else { - FF_unlockDIR(pIoman); - return RetVal; - }*/ - }else { - FF_unlockDIR(pIoman); - return FreeEntry; + + RetVal = FF_CleanupEntryFetch(pIoman, &FetchContext); + if(FF_isERR(RetVal)) { + FF_unlockDIR(pIoman); + return RetVal; + } +#ifdef FF_HASH_CACHE + if(!FF_DirHashed(pIoman, DirCluster)) { + // Hash the directory + FF_HashDir(pIoman, DirCluster); + } + + memcpy (ShortName, EntryBuffer, 11); + FF_ProcessShortName(ShortName); // Format the shortname to 8.3 +#if FF_HASH_FUNCTION == CRC16 + FF_AddDirentHash(pIoman, DirCluster, (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 + } } } FF_unlockDIR(pIoman); - if(RetVal) { + if(FF_isERR(RetVal)) { return RetVal; } if(pDirent) { pDirent->CurrentItem = (FF_T_UINT16) (FreeEntry + numLFNs); } - + return FF_ERR_NONE; } @@ -2395,6 +2530,7 @@ 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; + memset (&MyFile, '\0', sizeof MyFile); *pError = FF_ERR_NONE; #ifdef FF_UNICODE_SUPPORT wcsncpy(MyFile.FileName, FileName, FF_MAX_FILENAME); @@ -2402,25 +2538,34 @@ strncpy(MyFile.FileName, FileName, FF_MAX_FILENAME); #endif - MyFile.Attrib = 0x00; - MyFile.Filesize = 0; MyFile.ObjectCluster = FF_CreateClusterChain(pIoman, pError); - if(*pError) { - FF_UnlinkClusterChain(pIoman, MyFile.ObjectCluster, 0); - FF_FlushCache(pIoman); + if(FF_isERR(*pError)) { + // HT: TODO: can we unlink what we didn't create? + // JW: This is ok, because if the item item has a 0 in it, the no unlinking will occur. + // JW: I added the if statement, to ensure we don't unlink with 0. + if(MyFile.ObjectCluster) { + FF_lockFAT(pIoman); + { + FF_UnlinkClusterChain(pIoman, MyFile.ObjectCluster, 0); + } + FF_unlockFAT(pIoman); + } + FF_FlushCache(pIoman); // Don't override error; return 0; } - MyFile.CurrentItem = 0; *pError = FF_CreateDirent(pIoman, DirCluster, &MyFile); - - if(*pError) { - FF_UnlinkClusterChain(pIoman, MyFile.ObjectCluster, 0); - FF_FlushCache(pIoman); + if(FF_isERR(*pError)) { + FF_lockFAT(pIoman); + { + FF_UnlinkClusterChain(pIoman, MyFile.ObjectCluster, 0); + } + FF_unlockFAT(pIoman); + FF_FlushCache(pIoman); // Don't override error; return 0; } - FF_FlushCache(pIoman); + *pError = FF_FlushCache(pIoman); if(pDirent) { memcpy(pDirent, &MyFile, sizeof(FF_DIRENT)); @@ -2449,9 +2594,9 @@ FF_DIRENT MyDir; FF_T_UINT32 DirCluster; #ifdef FF_UNICODE_SUPPORT - FF_T_WCHAR DirName[FF_MAX_FILENAME]; + const FF_T_WCHAR *DirName; #else - FF_T_INT8 DirName[FF_MAX_FILENAME]; + const FF_T_INT8 *DirName; #endif FF_T_UINT8 EntryBuffer[32]; FF_T_UINT32 DotDotCluster; @@ -2461,7 +2606,7 @@ FF_FETCH_CONTEXT FetchContext; if(!pIoman) { - return FF_ERR_NULL_POINTER; + return FF_ERR_NULL_POINTER | FF_MKDIR; } #ifdef FF_UNICODE_SUPPORT @@ -2478,9 +2623,11 @@ } #ifdef FF_UNICODE_SUPPORT - wcsncpy(DirName, (Path + i + 1), FF_MAX_FILENAME); +// wcsncpy(DirName, (Path + i + 1), FF_MAX_FILENAME); + DirName = (Path + i + 1); #else - strncpy(DirName, (Path + i + 1), FF_MAX_FILENAME); +// strncpy(DirName, (Path + i + 1), FF_MAX_FILENAME); + DirName = (Path + i + 1); #endif if(i == 0) { @@ -2489,109 +2636,136 @@ DirCluster = FF_FindDir(pIoman, Path, i, &Error); - if(Error) { + if(FF_isERR(Error)) { return Error; } - if(DirCluster) { - if(FF_FindEntryInDir(pIoman, DirCluster, DirName, 0x00, &MyDir, &Error)) { - return FF_ERR_DIR_OBJECT_EXISTS; - } + if(!DirCluster) { + return FF_ERR_DIR_INVALID_PATH | FF_MKDIR; + } + memset (&MyDir, '\0', sizeof MyDir); - if(Error && Error != FF_ERR_DIR_END_OF_DIR) { - return Error; + if(FF_FindEntryInDir(pIoman, DirCluster, DirName, 0x00, &MyDir, &Error)) { + if(FF_isERR(Error)) { + return Error; } + return FF_ERR_DIR_OBJECT_EXISTS | FF_MKDIR; + } + if((FF_isERR(Error)) && FF_GETERROR (Error) != FF_ERR_DIR_END_OF_DIR) { + return Error; + } + #ifdef FF_UNICODE_SUPPORT - wcsncpy(MyDir.FileName, DirName, FF_MAX_FILENAME); + wcsncpy(MyDir.FileName, DirName, FF_MAX_FILENAME); #else - strncpy(MyDir.FileName, DirName, FF_MAX_FILENAME); + strncpy(MyDir.FileName, DirName, FF_MAX_FILENAME); #endif - MyDir.Filesize = 0; - MyDir.Attrib = FF_FAT_ATTR_DIR; - MyDir.ObjectCluster = FF_CreateClusterChain(pIoman, &Error); - if(Error) { - return Error; + MyDir.Filesize = 0; + MyDir.Attrib = FF_FAT_ATTR_DIR; + MyDir.ObjectCluster = FF_CreateClusterChain(pIoman, &Error); + if(FF_isERR(Error)) { + return Error; + } + if(!MyDir.ObjectCluster) { + // Couldn't allocate any space for the dir! + return FF_ERR_DIR_EXTEND_FAILED | FF_MKDIR; + } + Error = FF_ClearCluster(pIoman, MyDir.ObjectCluster); + if(FF_isERR(Error)) { + FF_lockFAT(pIoman); + { + FF_UnlinkClusterChain(pIoman, MyDir.ObjectCluster, 0); } - 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; - } + FF_unlockFAT(pIoman); + FF_FlushCache(pIoman); // Don't override error; + return Error; + } - Error = FF_CreateDirent(pIoman, DirCluster, &MyDir); + Error = FF_CreateDirent(pIoman, DirCluster, &MyDir); - if(Error) { + if(FF_isERR(Error)) { + FF_lockFAT(pIoman); + { FF_UnlinkClusterChain(pIoman, MyDir.ObjectCluster, 0); - FF_FlushCache(pIoman); - return Error; } - - memset(EntryBuffer, 0, 32); - EntryBuffer[0] = '.'; - for(i = 1; i < 11; i++) { - EntryBuffer[i] = 0x20; - } - FF_putChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB), FF_FAT_ATTR_DIR); - FF_putShort(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_HIGH), (FF_T_UINT16)(MyDir.ObjectCluster >> 16)); - 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_unlockFAT(pIoman); + FF_FlushCache(pIoman); // Don't override error; + return Error; + } - Error = FF_InitEntryFetch(pIoman, MyDir.ObjectCluster, &FetchContext); - if(Error) { + EntryBuffer[0] = '.'; + memset(EntryBuffer + 1, ' ', 10); + memset(EntryBuffer + 11, 0, 21); + + FF_putChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB), FF_FAT_ATTR_DIR); + FF_putShort(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_HIGH), (FF_T_UINT16)(MyDir.ObjectCluster >> 16)); + 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); + + Error = FF_InitEntryFetch(pIoman, MyDir.ObjectCluster, &FetchContext); + if(FF_isERR(Error)) { + FF_lockFAT(pIoman); + { FF_UnlinkClusterChain(pIoman, MyDir.ObjectCluster, 0); - FF_FlushCache(pIoman); - return Error; } - - Error = FF_PushEntryWithContext(pIoman, 0, &FetchContext, EntryBuffer); - if(Error) { + FF_unlockFAT(pIoman); + FF_FlushCache(pIoman); // Don't override error; + return Error; + } + + Error = FF_PushEntryWithContext(pIoman, 0, &FetchContext, EntryBuffer); + if(FF_isERR(Error)) { + FF_lockFAT(pIoman); + { FF_UnlinkClusterChain(pIoman, MyDir.ObjectCluster, 0); - FF_FlushCache(pIoman); - FF_CleanupEntryFetch(pIoman, &FetchContext); - return Error; } + FF_unlockFAT(pIoman); + FF_FlushCache(pIoman); // Don't override error; + FF_CleanupEntryFetch(pIoman, &FetchContext); // Don't override error! + return Error; + } - memset(EntryBuffer, 0, 32); - EntryBuffer[0] = '.'; - EntryBuffer[1] = '.'; - for(i = 2; i < 11; i++) { - EntryBuffer[i] = 0x20; - } - - if(DirCluster == pIoman->pPartition->RootDirCluster) { - DotDotCluster = 0; - } else { - DotDotCluster = DirCluster; - } + EntryBuffer[0] = '.'; + EntryBuffer[1] = '.'; + memset(EntryBuffer + 2, ' ', 9); + memset(EntryBuffer + 11, 0, 21); - FF_putChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB), FF_FAT_ATTR_DIR); - FF_putShort(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_HIGH), (FF_T_UINT16)(DotDotCluster >> 16)); - 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); - Error = FF_PushEntryWithContext(pIoman, 1, &FetchContext, EntryBuffer); - if(Error) { + if(DirCluster == pIoman->pPartition->RootDirCluster) { + DotDotCluster = 0; + } else { + DotDotCluster = DirCluster; + } + + FF_putChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB), FF_FAT_ATTR_DIR); + FF_putShort(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_HIGH), (FF_T_UINT16)(DotDotCluster >> 16)); + 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); + Error = FF_PushEntryWithContext(pIoman, 1, &FetchContext, EntryBuffer); + if(FF_isERR(Error)) { + FF_lockFAT(pIoman); + { FF_UnlinkClusterChain(pIoman, MyDir.ObjectCluster, 0); - FF_FlushCache(pIoman); - FF_CleanupEntryFetch(pIoman, &FetchContext); - return Error; } - FF_CleanupEntryFetch(pIoman, &FetchContext); + FF_unlockFAT(pIoman); + FF_FlushCache(pIoman); // Don't override error; + FF_CleanupEntryFetch(pIoman, &FetchContext); // Don't override error! + return Error; + } + Error = FF_CleanupEntryFetch(pIoman, &FetchContext); + if(FF_isERR(Error)) { + FF_FlushCache(pIoman); // Ensure dir was flushed to the disk! // Don't override error; + return Error; + } - FF_FlushCache(pIoman); // Ensure dir was flushed to the disk! + Error = FF_FlushCache(pIoman); // Ensure dir was flushed to the disk! + if(FF_isERR(Error)) { + return Error; + } - return FF_ERR_NONE; - } - - return FF_ERR_DIR_INVALID_PATH; + return FF_ERR_NONE; } @@ -2601,18 +2775,22 @@ FF_ERROR Error; FF_T_UINT8 EntryBuffer[32]; + if(usDirEntry == 0) { + return FF_ERR_NONE; + } + usDirEntry--; do { Error = FF_FetchEntryWithContext(pIoman, usDirEntry, pContext, EntryBuffer); - if(Error) { + if(FF_isERR(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); Error = FF_PushEntryWithContext(pIoman, usDirEntry, pContext, EntryBuffer); - if(Error) { + if(FF_isERR(Error)) { return Error; } } Index: ff_error.c =================================================================== --- ff_error.c (revision 58178) +++ ff_error.c (working copy) @@ -1,7 +1,19 @@ /***************************************************************************** - * FullFAT - High Performance, Thread-Safe Embedded FAT File-System * - * Copyright (C) 2009 James Walmsley (james@worm.me.uk) * + * FullFAT - High Performance, Thread-Safe Embedded FAT File-System * * * + * Copyright(C) 2009 James Walmsley * + * Copyright(C) 2011 Hein Tibosch * + * * + * See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT. * + * * + * WARNING : COMMERCIAL PROJECTS MUST COMPLY WITH THE GNU GPL LICENSE. * + * * + * Projects that cannot comply with the GNU GPL terms are legally obliged * + * to seek alternative licensing. Contact James Walmsley for details. * + * * + ***************************************************************************** + * See http://www.fullfat-fs.co.uk/ for more information. * + ***************************************************************************** * 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 * @@ -15,18 +27,14 @@ * 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. * + * The Copyright of Hein Tibosch on this project recognises his efforts in * + * contributing to this project. The right to license the project under * + * any other terms (other than the GNU GPL license) remains with the * + * original copyright holder (James Walmsley) only. * * * - * 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. * + * Modification/Extensions/Bugfixes/Improvements to FullFAT must be sent to * + * James Walmsley for integration into the main development branch. * *****************************************************************************/ /** @@ -38,56 +46,183 @@ * @brief Used to return pretty strings for FullFAT error codes. * **/ +#include + #include "ff_config.h" #include "ff_types.h" #include "ff_error.h" +#define ARRAY_SIZE(x) (int)(sizeof(x)/sizeof(x)[0]) + #ifdef FF_DEBUG +const struct _FFMODULETAB +{ + const FF_T_INT8 * const strModuleName; + const FF_T_UINT8 ucModuleID; +} gcpFullFATModuleTable[] = +{ + {"Unknown Module", 1}, // 1 here is ok, as the GetError functions start at the end of the table. + {"ff_ioman.c", FF_GETMODULE(FF_MODULE_IOMAN)}, + {"ff_dir.c", FF_GETMODULE(FF_MODULE_DIR)}, + {"ff_file.c", FF_GETMODULE(FF_MODULE_FILE)}, + {"ff_fat.c", FF_GETMODULE(FF_MODULE_FAT)}, + {"ff_crc.c", FF_GETMODULE(FF_MODULE_CRC)}, + {"ff_format.c", FF_GETMODULE(FF_MODULE_FORMAT)}, + {"ff_hash.c", FF_GETMODULE(FF_MODULE_HASH)}, + {"ff_memory.c", FF_GETMODULE(FF_MODULE_MEMORY)}, + {"ff_string.c", FF_GETMODULE(FF_MODULE_STRING)}, + {"ff_unicode.c", FF_GETMODULE(FF_MODULE_UNICODE)}, + {"ff_safety.c", FF_GETMODULE(FF_MODULE_SAFETY)}, + {"ff_time.c", FF_GETMODULE(FF_MODULE_TIME)}, + {"Platform Driver", FF_GETMODULE(FF_MODULE_DRIVER)}, +}; + +const struct _FFFUNCTIONTAB +{ + const FF_T_INT8 * const strFunctionName; + const FF_T_UINT16 ucFunctionID; +} gcpFullFATFunctionTable[] = +{ + {"Unknown Function", 1}, +//----- FF_IOMAN - The FullFAT I/O Manager + {"FF_CreateIOMAN", FF_GETMOD_FUNC(FF_CREATEIOMAN) }, + {"FF_DestroyIOMAN", FF_GETMOD_FUNC(FF_DESTROYIOMAN) }, + {"FF_RegisterBlkDevice", FF_GETMOD_FUNC(FF_REGISTERBLKDEVICE) }, + {"FF_UnregisterBlkDevice", FF_GETMOD_FUNC(FF_UNREGISTERBLKDEVICE) }, + {"FF_MountPartition", FF_GETMOD_FUNC(FF_MOUNTPARTITION) }, + {"FF_UnmountPartition", FF_GETMOD_FUNC(FF_UNMOUNTPARTITION) }, + {"FF_FlushCache", FF_GETMOD_FUNC(FF_FLUSHCACHE) }, + {"FF_GetPartitionBlockSize", FF_GETMOD_FUNC(FF_GETPARTITIONBLOCKSIZE) }, + {"FF_BlockRead", FF_GETMOD_FUNC(FF_BLOCKREAD) }, + {"FF_BlockWrite", FF_GETMOD_FUNC(FF_BLOCKWRITE) }, + {"FF_DetermineFatType", FF_GETMOD_FUNC(FF_DETERMINEFATTYPE) }, + {"FF_GetEfiPartitionEntry", FF_GETMOD_FUNC(FF_GETEFIPARTITIONENTRY) }, + {"FF_UserDriver", FF_GETMOD_FUNC(FF_USERDRIVER) }, + +//----- FF_DIR - The FullFAT directory handling routines + {"FF_FindNextInDir", FF_GETMOD_FUNC(FF_FINDNEXTINDIR) }, + {"FF_FetchEntryWithContext", FF_GETMOD_FUNC(FF_FETCHENTRYWITHCONTEXT) }, + {"FF_PushEntryWithContext", FF_GETMOD_FUNC(FF_PUSHENTRYWITHCONTEXT) }, + {"FF_GetEntry", FF_GETMOD_FUNC(FF_GETENTRY) }, + {"FF_FindFirst", FF_GETMOD_FUNC(FF_FINDFIRST) }, + {"FF_FindNext", FF_GETMOD_FUNC(FF_FINDNEXT) }, + {"FF_RewindFind", FF_GETMOD_FUNC(FF_REWINDFIND) }, + {"FF_FindFreeDirent", FF_GETMOD_FUNC(FF_FINDFREEDIRENT) }, + {"FF_PutEntry", FF_GETMOD_FUNC(FF_PUTENTRY) }, + {"FF_CreateShortName", FF_GETMOD_FUNC(FF_CREATESHORTNAME) }, + {"FF_CreateLFNs", FF_GETMOD_FUNC(FF_CREATELFNS) }, + {"FF_ExtendDirectory", FF_GETMOD_FUNC(FF_EXTENDDIRECTORY) }, + {"FF_MkDir", FF_GETMOD_FUNC(FF_MKDIR) }, + +//----- FF_FILE - The FullFAT file handling routines + {"FF_GetModeBits", FF_GETMOD_FUNC(FF_GETMODEBITS) }, + {"FF_Open", FF_GETMOD_FUNC(FF_OPEN) }, + {"FF_isDirEmpty", FF_GETMOD_FUNC(FF_ISDIREMPTY) }, + {"FF_RmDir", FF_GETMOD_FUNC(FF_RMDIR) }, + {"FF_RmFile", FF_GETMOD_FUNC(FF_RMFILE) }, + {"FF_Move", FF_GETMOD_FUNC(FF_MOVE) }, + {"FF_isEOF", FF_GETMOD_FUNC(FF_ISEOF) }, + {"FF_GetSequentialClusters", FF_GETMOD_FUNC(FF_GETSEQUENTIALCLUSTERS) }, + {"FF_ReadClusters", FF_GETMOD_FUNC(FF_READCLUSTERS) }, + {"FF_ExtendFile", FF_GETMOD_FUNC(FF_EXTENDFILE) }, + {"FF_WriteClusters", FF_GETMOD_FUNC(FF_WRITECLUSTERS) }, + {"FF_Read", FF_GETMOD_FUNC(FF_READ) }, + {"FF_GetC", FF_GETMOD_FUNC(FF_GETC) }, + {"FF_GetLine", FF_GETMOD_FUNC(FF_GETLINE) }, + {"FF_Tell", FF_GETMOD_FUNC(FF_TELL) }, + {"FF_Write", FF_GETMOD_FUNC(FF_WRITE) }, + {"FF_PutC", FF_GETMOD_FUNC(FF_PUTC) }, + {"FF_Seek", FF_GETMOD_FUNC(FF_SEEK) }, + {"FF_Invalidate", FF_GETMOD_FUNC(FF_INVALIDATE) }, + {"FF_CheckValid", FF_GETMOD_FUNC(FF_CHECKVALID) }, + {"FF_Close", FF_GETMOD_FUNC(FF_CLOSE) }, + {"FF_SetTime", FF_GETMOD_FUNC(FF_SETTIME) }, + {"FF_BytesLeft", FF_GETMOD_FUNC(FF_BYTESLEFT) }, + {"FF_SetFileTime", FF_GETMOD_FUNC(FF_SETFILETIME) }, + +//----- FF_FAT - The FullFAT FAT handling routines + {"FF_getFatEntry", FF_GETMOD_FUNC(FF_GETFATENTRY) }, + {"FF_ClearCluster", FF_GETMOD_FUNC(FF_CLEARCLUSTER) }, + {"FF_putFatEntry", FF_GETMOD_FUNC(FF_PUTFATENTRY) }, + {"FF_FindFreeCluster", FF_GETMOD_FUNC(FF_FINDFREECLUSTER) }, + {"FF_CountFreeClusters", FF_GETMOD_FUNC(FF_COUNTFREECLUSTERS) }, + +//----- FF_HASH - The FullFAT hashing routines + {"FF_ClearHashTable", FF_GETMOD_FUNC(FF_CLEARHASHTABLE) }, + {"FF_SetHash", FF_GETMOD_FUNC(FF_SETHASH) }, + {"FF_ClearHash", FF_GETMOD_FUNC(FF_CLEARHASH) }, + {"FF_DestroyHashTable", FF_GETMOD_FUNC(FF_DESTROYHASHTABLE) }, + +//----- FF_UNICODE - The FullFAT hashing routines + {"FF_Utf8ctoUtf16c", FF_GETMOD_FUNC(FF_UTF8CTOUTF16C) }, + {"FF_Utf16ctoUtf8c", FF_GETMOD_FUNC(FF_UTF16CTOUTF8C) }, + {"FF_Utf32ctoUtf16c", FF_GETMOD_FUNC(FF_UTF32CTOUTF16C) }, + {"FF_Utf16ctoUtf32c", FF_GETMOD_FUNC(FF_UTF16CTOUTF32C) }, + +//----- FF_FORMAT - The FullFAT format routine + {"FF_FormatPartition", FF_GETMOD_FUNC(FF_FORMATPARTITION) }, +}; + const struct _FFERRTAB { - const FF_T_INT8 * const strErrorString; - const FF_T_SINT32 iErrorCode; - + const FF_T_INT8 * const strErrorString; + const FF_T_UINT8 ucErrorCode; // Currently there are less then 256 errors, so lets keep this table small. } gcpFullFATErrorTable[] = { - {"Unknown or Generic Error! - Please contact FullFAT DEV - james@worm.me.uk", -1000}, - {"No Error.", FF_ERR_NONE}, - {"Null Pointer provided, (probably for IOMAN).", FF_ERR_NULL_POINTER}, - {"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 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}, - {"The provided partition number is out-of-range (0 - 3).", FF_ERR_IOMAN_INVALID_PARTITION_NUM}, - {"The selected partition / volume doesn't appear to be FAT formatted.", FF_ERR_IOMAN_NOT_FAT_FORMATTED}, - {"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}, - {"Cannot open for writing: File is marked as Read-Only.", FF_ERR_FILE_IS_READ_ONLY}, - {"Path not found.", FF_ERR_FILE_INVALID_PATH}, - {"A file or folder of the same name already exists.", FF_ERR_DIR_OBJECT_EXISTS}, + {"Unknown or Generic Error! - Please contact james@fullfat-fs.co.uk", 1}, + {"No Error", FF_ERR_NONE}, + {"Null Pointer provided, (probably for IOMAN)", FF_ERR_NULL_POINTER}, + {"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 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}, + {"The provided partition number is out-of-range (0 - 3)", FF_ERR_IOMAN_INVALID_PARTITION_NUM}, + {"The selected partition / volume doesn't appear to be FAT formatted", FF_ERR_IOMAN_NOT_FAT_FORMATTED}, + {"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}, + {"Disk full", 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}, + {"I/O driver is busy", FF_ERR_IOMAN_DRIVER_BUSY}, + {"I/O driver returned fatal error", FF_ERR_IOMAN_DRIVER_FATAL_ERROR}, + + {"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}, + {"Cannot open for writing: File is marked as Read-Only", FF_ERR_FILE_IS_READ_ONLY}, + {"Path not found", FF_ERR_FILE_INVALID_PATH}, + {"File operation failed - the file was not opened for writing", FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE}, + {"File operation failed - the file was not opened for reading", FF_ERR_FILE_NOT_OPENED_IN_READ_MODE}, + {"File operation failed - could not extend file", FF_ERR_FILE_EXTEND_FAILED}, + {"Destination file already exists", FF_ERR_FILE_DESTINATION_EXISTS}, + {"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}, + {"A file handle was invalid", FF_ERR_FILE_BAD_HANDLE}, +#ifdef FF_REMOVABLE_MEDIA + {"File handle got invalid because media was removed", FF_ERR_FILE_MEDIA_REMOVED}, +#endif + {"A file or folder of the same name already exists", FF_ERR_DIR_OBJECT_EXISTS}, {"FF_ERR_DIR_DIRECTORY_FULL", FF_ERR_DIR_DIRECTORY_FULL}, {"FF_ERR_DIR_END_OF_DIR", FF_ERR_DIR_END_OF_DIR}, - {"The directory is not empty.", FF_ERR_DIR_NOT_EMPTY}, + {"The directory is not empty", FF_ERR_DIR_NOT_EMPTY}, {"Could not extend File or Folder - No Free Space!", FF_ERR_FAT_NO_FREE_CLUSTERS}, - {"Could not find the directory specified by the path.", FF_ERR_DIR_INVALID_PATH}, - {"The Root Dir is full, and cannot be extended on Fat12 or 16 volumes.", FF_ERR_DIR_CANT_EXTEND_ROOT_DIR}, - {"File operation failed - the file was not opened for writing.", FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE}, - {"File operation failed - the file was not opened for reading.", FF_ERR_FILE_NOT_OPENED_IN_READ_MODE}, - {"File operation failed - could not extend file.", FF_ERR_FILE_EXTEND_FAILED}, - {"Destination file already exists.", FF_ERR_FILE_DESTINATION_EXISTS}, - {"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}, + {"Could not find the directory specified by the path", FF_ERR_DIR_INVALID_PATH}, + {"The Root Dir is full, and cannot be extended on Fat12 or 16 volumes", FF_ERR_DIR_CANT_EXTEND_ROOT_DIR}, + {"Not enough space to extend the directory.", FF_ERR_DIR_EXTEND_FAILED}, + {"Name exceeds the number of allowed charachters for a filename", FF_ERR_DIR_NAME_TOO_LONG}, + +#ifdef FF_UNICODE_SUPPORT + {"An invalid Unicode charachter was provided!", FF_ERR_UNICODE_INVALID_CODE}, + {"Not enough space in the UTF-16 buffer to encode the entire sequence", FF_ERR_UNICODE_DEST_TOO_SMALL}, + {"An invalid UTF-16 sequence was encountered", FF_ERR_UNICODE_INVALID_SEQUENCE}, + {"Filename exceeds MAX long-filename length when converted to UTF-16", FF_ERR_UNICODE_CONVERSION_EXCEEDED}, +#endif }; /** @@ -100,12 +235,46 @@ * **/ const FF_T_INT8 *FF_GetErrMessage(FF_ERROR iErrorCode) { - FF_T_UINT32 stCount = sizeof (gcpFullFATErrorTable) / sizeof ( struct _FFERRTAB); + FF_T_UINT32 stCount = ARRAY_SIZE(gcpFullFATErrorTable); while (stCount--){ - if (gcpFullFATErrorTable[stCount].iErrorCode == iErrorCode) { + if (((FF_T_UINT) gcpFullFATErrorTable[stCount].ucErrorCode) == FF_GETERROR(iErrorCode)) { return gcpFullFATErrorTable[stCount].strErrorString; } } return gcpFullFATErrorTable[0].strErrorString; } + +const FF_T_INT8 *FF_GetErrModule(FF_ERROR iErrorCode) { + FF_T_UINT32 stCount = ARRAY_SIZE(gcpFullFATModuleTable); + while (stCount--) { + if(gcpFullFATModuleTable[stCount].ucModuleID == FF_GETMODULE(iErrorCode)) { + return gcpFullFATModuleTable[stCount].strModuleName; + } + } + return gcpFullFATModuleTable[0].strModuleName; +} + +const FF_T_INT8 *FF_GetErrFunction(FF_ERROR iErrorCode) { + FF_T_UINT32 stCount = ARRAY_SIZE(gcpFullFATFunctionTable); + FF_T_UINT16 ModuleFunc = FF_GETMOD_FUNC(iErrorCode); + while (stCount--) { + if(gcpFullFATFunctionTable[stCount].ucFunctionID == ModuleFunc) { + return gcpFullFATFunctionTable[stCount].strFunctionName; + } + } + return gcpFullFATFunctionTable[0].strFunctionName; +} + +const FF_T_INT8 *FF_GetErrDescription(FF_ERROR iErrorCode, char *apBuf, int aMaxlen) { + if (FF_isERR(iErrorCode)) { + snprintf (apBuf, aMaxlen, "%s::%s::%s", + FF_GetErrModule(iErrorCode), + FF_GetErrFunction(iErrorCode), + FF_GetErrMessage(iErrorCode)); + } else { + snprintf (apBuf, aMaxlen, "No error"); + } + return apBuf; +} + #endif Index: ff_fat.c =================================================================== --- ff_fat.c (revision 58178) +++ ff_fat.c (working copy) @@ -1,7 +1,19 @@ /***************************************************************************** - * FullFAT - High Performance, Thread-Safe Embedded FAT File-System * - * Copyright (C) 2009 James Walmsley (james@worm.me.uk) * + * FullFAT - High Performance, Thread-Safe Embedded FAT File-System * * * + * Copyright(C) 2009 James Walmsley * + * Copyright(C) 2011 Hein Tibosch * + * * + * See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT. * + * * + * WARNING : COMMERCIAL PROJECTS MUST COMPLY WITH THE GNU GPL LICENSE. * + * * + * Projects that cannot comply with the GNU GPL terms are legally obliged * + * to seek alternative licensing. Contact James Walmsley for details. * + * * + ***************************************************************************** + * See http://www.fullfat-fs.co.uk/ for more information. * + ***************************************************************************** * 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 * @@ -15,18 +27,14 @@ * 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. * + * The Copyright of Hein Tibosch on this project recognises his efforts in * + * contributing to this project. The right to license the project under * + * any other terms (other than the GNU GPL license) remains with the * + * original copyright holder (James Walmsley) only. * * * - * 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. * + * Modification/Extensions/Bugfixes/Improvements to FullFAT must be sent to * + * James Walmsley for integration into the main development branch. * *****************************************************************************/ /** @@ -44,6 +52,8 @@ #include "ff_config.h" #include +struct SFatStat fatStat; + void FF_lockFAT(FF_IOMAN *pIoman) { FF_PendSemaphore(pIoman->pSemaphore); // Use Semaphore to protect FAT modifications. { @@ -107,23 +117,50 @@ return cluster; } + +FF_ERROR FF_ReleaseFatBuffer (FF_IOMAN *pIoman, FF_FatBuffers *pBuffer) +{ + FF_T_INT i; + FF_ERROR Error = FF_ERR_NONE; + for (i = 0; i < BUF_STORE_COUNT; i++) { + if (pBuffer->pBuffers[i]) { + Error = FF_ReleaseBuffer(pIoman, pBuffer->pBuffers[i]); + if(FF_isERR(Error)) { + break; + } + pBuffer->pBuffers[i] = NULL; + } + } + fatStat.clearCount++; + + return Error; +} + /** * @private **/ -FF_T_UINT32 FF_getFatEntry(FF_IOMAN *pIoman, FF_T_UINT32 nCluster, FF_ERROR *pError) { +FF_T_UINT32 FF_getFatEntry(FF_IOMAN *pIoman, FF_T_UINT32 nCluster, FF_ERROR *pError, FF_FatBuffers *pFatBuf) { - FF_BUFFER *pBuffer; + FF_BUFFER *pBuffer = NULL; FF_T_UINT32 FatOffset; FF_T_UINT32 FatSector; FF_T_UINT32 FatSectorEntry; FF_T_UINT32 FatEntry; - FF_T_UINT8 LBAadjust; - FF_T_UINT16 relClusterEntry; + FF_T_UINT LBAadjust; + FF_T_UINT32 relClusterEntry; + // preferred mode, user might want to update this entry + FF_T_UINT8 Mode = pFatBuf ? pFatBuf->Mode : FF_MODE_READ; #ifdef FF_FAT12_SUPPORT FF_T_UINT8 F12short[2]; // For FAT12 FAT Table Across sector boundary traversal. #endif - + *pError = FF_ERR_NONE; + + if (nCluster >= pIoman->pPartition->NumClusters) { + // HT: find a more specific error code + *pError = FF_ERR_IOMAN_NOT_ENOUGH_FREE_SPACE | FF_GETFATENTRY; + return 0; + } if(pIoman->pPartition->Type == FF_T_FAT32) { FatOffset = nCluster * 4; } else if(pIoman->pPartition->Type == FF_T_FAT16) { @@ -135,35 +172,41 @@ FatSector = pIoman->pPartition->FatBeginLBA + (FatOffset / pIoman->pPartition->BlkSize); FatSectorEntry = FatOffset % pIoman->pPartition->BlkSize; - LBAadjust = (FF_T_UINT8) (FatSectorEntry / pIoman->BlkSize); - relClusterEntry = (FF_T_UINT32) (FatSectorEntry % pIoman->BlkSize); + LBAadjust = (FF_T_UINT) (FatSectorEntry / pIoman->BlkSize); + relClusterEntry = FatSectorEntry % pIoman->BlkSize; - FatSector = FF_getRealLBA(pIoman, FatSector); + FatSector = FF_getRealLBA(pIoman, FatSector) + LBAadjust; #ifdef FF_FAT12_SUPPORT if(pIoman->pPartition->Type == FF_T_FAT12) { - if(relClusterEntry == (FF_T_UINT32)(pIoman->BlkSize - 1)) { + if(relClusterEntry == (FF_T_UINT32)((pIoman->BlkSize - 1))) { // Fat Entry SPANS a Sector! // First Buffer get the last Byte in buffer (first byte of our address)! - pBuffer = FF_GetBuffer(pIoman, FatSector + LBAadjust, FF_MODE_READ); + pBuffer = FF_GetBuffer(pIoman, FatSector, Mode); { if(!pBuffer) { - *pError = FF_ERR_DEVICE_DRIVER_FAILED; + *pError = FF_ERR_DEVICE_DRIVER_FAILED | FF_GETFATENTRY; return 0; } F12short[0] = FF_getChar(pBuffer->pBuffer, (FF_T_UINT16)(pIoman->BlkSize - 1)); } - FF_ReleaseBuffer(pIoman, pBuffer); + *pError = FF_ReleaseBuffer(pIoman, pBuffer); + if(FF_isERR(*pError)) { + return 0; + } // Second Buffer get the first Byte in buffer (second byte of out address)! - pBuffer = FF_GetBuffer(pIoman, FatSector + LBAadjust + 1, FF_MODE_READ); + pBuffer = FF_GetBuffer(pIoman, FatSector + 1, Mode); { if(!pBuffer) { - *pError = FF_ERR_DEVICE_DRIVER_FAILED; + *pError = FF_ERR_DEVICE_DRIVER_FAILED | FF_GETFATENTRY; return 0; } F12short[1] = FF_getChar(pBuffer->pBuffer, 0); } - FF_ReleaseBuffer(pIoman, pBuffer); + *pError = FF_ReleaseBuffer(pIoman, pBuffer); + if(FF_isERR(*pError)) { + return 0; + } FatEntry = (FF_T_UINT32) FF_getShort((FF_T_UINT8*)&F12short, 0); // Guarantee correct Endianess! @@ -175,10 +218,29 @@ } } #endif - pBuffer = FF_GetBuffer(pIoman, FatSector + LBAadjust, FF_MODE_READ); + if (pFatBuf) { + FF_BUFFER *buf = pFatBuf->pBuffers[0]; + if (buf) { + if (buf->Sector == FatSector) { + pBuffer = buf; + fatStat.reuseCount[0]++; + } else { + *pError = FF_ReleaseBuffer(pIoman, buf); + if(FF_isERR(*pError)) { + return 0; + } + pFatBuf->pBuffers[0] = NULL; + fatStat.missCount[0]++; + } + } else { + fatStat.getCount[0]++; + } + } + if (!pBuffer) + pBuffer = FF_GetBuffer(pIoman, FatSector, Mode); { if(!pBuffer) { - *pError = FF_ERR_DEVICE_DRIVER_FAILED; + *pError = FF_ERR_DEVICE_DRIVER_FAILED | FF_GETFATENTRY; return 0; } @@ -206,31 +268,50 @@ break; } } - FF_ReleaseBuffer(pIoman, pBuffer); + if (pFatBuf) { + pFatBuf->pBuffers[0] = pBuffer; + } else { + *pError = FF_ReleaseBuffer(pIoman, pBuffer); + if(FF_isERR(*pError)) { + return 0; + } + } return (FF_T_SINT32) FatEntry; } FF_ERROR FF_ClearCluster(FF_IOMAN *pIoman, FF_T_UINT32 nCluster) { - FF_BUFFER *pBuffer; - FF_T_UINT16 i; + FF_BUFFER *pBuffer = NULL; + FF_T_INT i; FF_T_UINT32 BaseLBA; + FF_ERROR slRetVal = FF_ERR_NONE; BaseLBA = FF_Cluster2LBA(pIoman, nCluster); BaseLBA = FF_getRealLBA(pIoman, BaseLBA); for(i = 0; i < pIoman->pPartition->SectorsPerCluster; i++) { - pBuffer = FF_GetBuffer(pIoman, BaseLBA++, FF_MODE_WRITE); - { + if (i == 0) { + pBuffer = FF_GetBuffer(pIoman, BaseLBA, FF_MODE_WR_ONLY); if(!pBuffer) { - return FF_ERR_DEVICE_DRIVER_FAILED; + return FF_ERR_DEVICE_DRIVER_FAILED | FF_CLEARCLUSTER; } - memset(pBuffer->pBuffer, 0x00, 512); + memset(pBuffer->pBuffer, 0x00, pIoman->BlkSize); } + slRetVal = FF_BlockWrite(pIoman, BaseLBA+i, 1, pBuffer->pBuffer, FF_FALSE); + if(slRetVal < 0) { + break; + } + } + pBuffer->Modified = FF_FALSE; + + if(FF_isERR(slRetVal)) { FF_ReleaseBuffer(pIoman, pBuffer); + return slRetVal; } - return FF_ERR_NONE; + slRetVal = FF_ReleaseBuffer(pIoman, pBuffer); + + return slRetVal; } /** @@ -248,21 +329,25 @@ FF_T_UINT32 i; FF_T_UINT32 fatEntry = Start, currentCluster = Start; + FF_FatBuffers FatBuf; + FF_InitFatBuffer (&FatBuf, FF_MODE_READ); *pError = FF_ERR_NONE; for(i = 0; i < Count; i++) { - fatEntry = FF_getFatEntry(pIoman, currentCluster, pError); - if(*pError) { - return 0; + fatEntry = FF_getFatEntry(pIoman, currentCluster, pError, &FatBuf); + if(FF_isERR(*pError)) { + fatEntry = 0; + break; } if(FF_isEndOfChain(pIoman, fatEntry)) { - return currentCluster; - } else { - currentCluster = fatEntry; - } + fatEntry = currentCluster; + break; + } + currentCluster = fatEntry; } + *pError = FF_ReleaseFatBuffer(pIoman, &FatBuf); return fatEntry; } @@ -270,20 +355,24 @@ FF_T_UINT32 FF_FindEndOfChain(FF_IOMAN *pIoman, FF_T_UINT32 Start, FF_ERROR *pError) { FF_T_UINT32 fatEntry = Start, currentCluster = Start; + FF_FatBuffers FatBuf; + FF_InitFatBuffer (&FatBuf, FF_MODE_READ); *pError = FF_ERR_NONE; while(!FF_isEndOfChain(pIoman, fatEntry)) { - fatEntry = FF_getFatEntry(pIoman, currentCluster, pError); - if(*pError) { - return 0; + fatEntry = FF_getFatEntry(pIoman, currentCluster, pError, &FatBuf); + if(FF_isERR(*pError)) { + fatEntry = 0; + break; } if(FF_isEndOfChain(pIoman, fatEntry)) { - return currentCluster; - } else { - currentCluster = fatEntry; - } + fatEntry = currentCluster; + break; + } + currentCluster = fatEntry; } + *pError = FF_ReleaseFatBuffer(pIoman, &FatBuf); return fatEntry; } @@ -329,19 +418,27 @@ * @param nCluster Cluster Number to be modified. * @param Value The Value to store. **/ -FF_ERROR 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_FatBuffers *pFatBuf) { - FF_BUFFER *pBuffer; + FF_BUFFER *pBuffer = NULL; FF_T_UINT32 FatOffset; FF_T_UINT32 FatSector; FF_T_UINT32 FatSectorEntry; FF_T_UINT32 FatEntry; - FF_T_UINT8 LBAadjust; + FF_T_UINT LBAadjust; FF_T_UINT32 relClusterEntry; + FF_ERROR Error; #ifdef FF_FAT12_SUPPORT FF_T_UINT8 F12short[2]; // For FAT12 FAT Table Across sector boundary traversal. #endif + + FF_T_INT i; + // HT: avoid corrupting the disk + if (!nCluster || nCluster >= pIoman->pPartition->NumClusters) { + // find a more specific error code + return FF_ERR_IOMAN_NOT_ENOUGH_FREE_SPACE | FF_PUTFATENTRY; + } if(pIoman->pPartition->Type == FF_T_FAT32) { FatOffset = nCluster * 4; } else if(pIoman->pPartition->Type == FF_T_FAT16) { @@ -353,95 +450,159 @@ FatSector = pIoman->pPartition->FatBeginLBA + (FatOffset / pIoman->pPartition->BlkSize); FatSectorEntry = FatOffset % pIoman->pPartition->BlkSize; - LBAadjust = (FF_T_UINT8) (FatSectorEntry / pIoman->BlkSize); - relClusterEntry = (FF_T_UINT32)(FatSectorEntry % pIoman->BlkSize); + LBAadjust = (FF_T_UINT) (FatSectorEntry / pIoman->BlkSize); + relClusterEntry = FatSectorEntry % pIoman->BlkSize; - FatSector = FF_getRealLBA(pIoman, FatSector); + FatSector = FF_getRealLBA(pIoman, FatSector); // LBA * pIoman->pPartition->BlkFactor; + FatSector += LBAadjust; #ifdef FF_FAT12_SUPPORT - if(pIoman->pPartition->Type == FF_T_FAT12) { - if(relClusterEntry == (FF_T_UINT32)(pIoman->BlkSize - 1)) { - // Fat Entry SPANS a Sector! - // First Buffer get the last Byte in buffer (first byte of our address)! - pBuffer = FF_GetBuffer(pIoman, FatSector + LBAadjust, FF_MODE_READ); - { - if(!pBuffer) { - return FF_ERR_DEVICE_DRIVER_FAILED; + if(pIoman->pPartition->Type == FF_T_FAT12) { + if(relClusterEntry == (FF_T_UINT32) (pIoman->BlkSize - 1)) { + + // Fat Entry SPANS a Sector! + // First Buffer get the last Byte in buffer (first byte of our address)! + pBuffer = FF_GetBuffer(pIoman, FatSector, FF_MODE_READ); + { + if(!pBuffer) { + return FF_ERR_DEVICE_DRIVER_FAILED | FF_PUTFATENTRY; + } + F12short[0] = FF_getChar(pBuffer->pBuffer, pIoman->BlkSize - 1); } - F12short[0] = FF_getChar(pBuffer->pBuffer, (FF_T_UINT16)(pIoman->BlkSize - 1)); - } - FF_ReleaseBuffer(pIoman, pBuffer); - // Second Buffer get the first Byte in buffer (second byte of out address)! - pBuffer = FF_GetBuffer(pIoman, FatSector + LBAadjust + 1, FF_MODE_READ); - { - if(!pBuffer) { - return FF_ERR_DEVICE_DRIVER_FAILED; + Error = FF_ReleaseBuffer(pIoman, pBuffer); + if(FF_isERR(Error)) { + return Error; } - F12short[1] = FF_getChar(pBuffer->pBuffer, (FF_T_UINT16) 0x0000); - } - FF_ReleaseBuffer(pIoman, pBuffer); - + // Second Buffer get the first Byte in buffer (second byte of out address)! + pBuffer = FF_GetBuffer(pIoman, FatSector + 1, FF_MODE_READ); + { + if(!pBuffer) { + return FF_ERR_DEVICE_DRIVER_FAILED | FF_PUTFATENTRY; + } + F12short[1] = FF_getChar(pBuffer->pBuffer, (FF_T_UINT16) 0x0000); + } + Error = FF_ReleaseBuffer(pIoman, pBuffer); + if(FF_isERR(Error)) { + return Error; + } - FatEntry = FF_getShort((FF_T_UINT8*)&F12short, (FF_T_UINT16) 0x0000); // Guarantee correct Endianess! - if(nCluster & 0x0001) { - FatEntry &= 0x000F; - Value = (Value << 4); - Value &= 0xFFF0; - } else { - FatEntry &= 0xF000; - Value &= 0x0FFF; - } + FatEntry = FF_getShort((FF_T_UINT8*)&F12short, (FF_T_UINT16) 0x0000); // Guarantee correct Endianess! + if(nCluster & 0x0001) { + FatEntry &= 0x000F; + Value = (Value << 4); + Value &= 0xFFF0; + } else { + FatEntry &= 0xF000; + Value &= 0x0FFF; + } - FF_putShort((FF_T_UINT8 *)F12short, 0x0000, (FF_T_UINT16) (FatEntry | Value)); + FF_putShort((FF_T_UINT8 *)F12short, 0x0000, (FF_T_UINT16) (FatEntry | Value)); - pBuffer = FF_GetBuffer(pIoman, FatSector + LBAadjust, FF_MODE_WRITE); - { - if(!pBuffer) { - return FF_ERR_DEVICE_DRIVER_FAILED; +#ifdef FF_WRITE_BOTH_FATS + for (i = 0; i < pIoman->pPartition->NumFATS; i++) { + FatSector += (i * pIoman->pPartition->SectorsPerFAT); +#endif + + pBuffer = FF_GetBuffer(pIoman, FatSector, FF_MODE_WRITE); + { + if(!pBuffer) { + return FF_ERR_DEVICE_DRIVER_FAILED | FF_PUTFATENTRY; + } + FF_putChar(pBuffer->pBuffer, (FF_T_UINT16)(pIoman->BlkSize - 1), F12short[0]); + } + Error = FF_ReleaseBuffer(pIoman, pBuffer); + if(FF_isERR(Error)) { + return Error; + } + + // Second Buffer get the first Byte in buffer (second byte of out address)! + pBuffer = FF_GetBuffer(pIoman, FatSector + 1, FF_MODE_WRITE); // changed to MODE_WRITE -- BUG??? + { + if(!pBuffer) { + return FF_ERR_DEVICE_DRIVER_FAILED | FF_PUTFATENTRY; + } + FF_putChar(pBuffer->pBuffer, 0x0000, F12short[1]); + } + Error = FF_ReleaseBuffer(pIoman, pBuffer); + if(FF_isERR(Error)) { + return Error; + } + +#ifdef FF_WRITE_BOTH_FATS } - FF_putChar(pBuffer->pBuffer, (FF_T_UINT16)(pIoman->BlkSize - 1), F12short[0]); +#endif + + return FF_ERR_NONE; + } + } +#endif + +#ifdef FF_WRITE_BOTH_FATS + for (i = 0; i < pIoman->pPartition->NumFATS; + i++, FatSector += pIoman->pPartition->SectorsPerFAT) +#else + // Will be optimized away by compiler + for (i = 0; i < 1; i++) +#endif + { + + if (i < BUF_STORE_COUNT && pFatBuf) { + FF_BUFFER *buf = pFatBuf->pBuffers[i]; + if (buf) { + if (buf->Sector == FatSector && (buf->Mode & FF_MODE_WRITE)) { + // Same sector, correct mode: we can reuse it + pBuffer = buf; + fatStat.reuseCount[1]++; + } else { + Error = FF_ReleaseBuffer(pIoman, buf); + if(FF_isERR(Error)) { + return Error; + } + pFatBuf->pBuffers[i] = NULL; + fatStat.missCount[1]++; + pBuffer = NULL; + } + } else { + fatStat.getCount[1]++; } - FF_ReleaseBuffer(pIoman, pBuffer); - // Second Buffer get the first Byte in buffer (second byte of out address)! - pBuffer = FF_GetBuffer(pIoman, FatSector + LBAadjust + 1, FF_MODE_READ); - { - if(!pBuffer) { - return FF_ERR_DEVICE_DRIVER_FAILED; + } + if (!pBuffer) + pBuffer = FF_GetBuffer(pIoman, FatSector, FF_MODE_WRITE); + { + if(!pBuffer) { + return FF_ERR_DEVICE_DRIVER_FAILED | FF_PUTFATENTRY; + } + if(pIoman->pPartition->Type == FF_T_FAT32) { + Value &= 0x0fffffff; // Clear the top 4 bits. + FF_putLong(pBuffer->pBuffer, relClusterEntry, Value); + } else if(pIoman->pPartition->Type == FF_T_FAT16) { + FF_putShort(pBuffer->pBuffer, relClusterEntry, (FF_T_UINT16) Value); + } else { + FatEntry = (FF_T_UINT32) FF_getShort(pBuffer->pBuffer, relClusterEntry); + if(nCluster & 0x0001) { + FatEntry &= 0x000F; + Value = (Value << 4); + Value &= 0xFFF0; + } else { + FatEntry &= 0xF000; + Value &= 0x0FFF; } - FF_putChar(pBuffer->pBuffer, 0x0000, F12short[1]); + + FF_putShort(pBuffer->pBuffer, relClusterEntry, (FF_T_UINT16) (FatEntry | Value)); } - FF_ReleaseBuffer(pIoman, pBuffer); - - return FF_ERR_NONE; } - } -#endif - - pBuffer = FF_GetBuffer(pIoman, FatSector + LBAadjust, FF_MODE_WRITE); - { - if(!pBuffer) { - return FF_ERR_DEVICE_DRIVER_FAILED; - } - if(pIoman->pPartition->Type == FF_T_FAT32) { - Value &= 0x0fffffff; // Clear the top 4 bits. - FF_putLong(pBuffer->pBuffer, relClusterEntry, Value); - } else if(pIoman->pPartition->Type == FF_T_FAT16) { - FF_putShort(pBuffer->pBuffer, relClusterEntry, (FF_T_UINT16) Value); + if (i < BUF_STORE_COUNT && pFatBuf) { + // Store it for later use + pFatBuf->pBuffers[i] = pBuffer; + pFatBuf->Mode = FF_MODE_WRITE; } else { - FatEntry = (FF_T_UINT32) FF_getShort(pBuffer->pBuffer, relClusterEntry); - if(nCluster & 0x0001) { - FatEntry &= 0x000F; - Value = (Value << 4); - Value &= 0xFFF0; - } else { - FatEntry &= 0xF000; - Value &= 0x0FFF; + Error = FF_ReleaseBuffer(pIoman, pBuffer); + if(FF_isERR(Error)) { + return Error; } - - FF_putShort(pBuffer->pBuffer, relClusterEntry, (FF_T_UINT16) (FatEntry | Value)); } + pBuffer = NULL; } - FF_ReleaseBuffer(pIoman, pBuffer); return FF_ERR_NONE; } @@ -458,34 +619,41 @@ * @return 0 on error. **/ #ifdef FF_FAT12_SUPPORT -static FF_T_UINT32 FF_FindFreeClusterOLD(FF_IOMAN *pIoman, FF_ERROR *pError) { - FF_T_UINT32 nCluster; +FF_T_UINT32 FF_FindFreeClusterOLD(FF_IOMAN *pIoman, FF_ERROR *pError) { + FF_T_UINT32 nCluster = 0; FF_T_UINT32 fatEntry; + FF_FatBuffers FatBuf; + FF_InitFatBuffer (&FatBuf, FF_MODE_READ); *pError = FF_ERR_NONE; for(nCluster = pIoman->pPartition->LastFreeCluster; nCluster < pIoman->pPartition->NumClusters; nCluster++) { - fatEntry = FF_getFatEntry(pIoman, nCluster, pError); - if(*pError) { - return 0; + fatEntry = FF_getFatEntry(pIoman, nCluster, pError, &FatBuf); + if(FF_isERR(*pError)) { + nCluster = 0; + break; } if(fatEntry == 0x00000000) { pIoman->pPartition->LastFreeCluster = nCluster; - return nCluster; + break; + } } - return 0; + *pError = FF_ReleaseFatBuffer(pIoman, &FatBuf); + return nCluster; } #endif 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 x, nCluster = pIoman->pPartition->LastFreeCluster; FF_T_UINT32 FatOffset; FF_T_UINT32 FatSector; FF_T_UINT32 FatSectorEntry; FF_T_UINT32 EntriesPerSector; FF_T_UINT32 FatEntry = 1; + const FF_T_INT EntrySize = (pIoman->pPartition->Type == FF_T_FAT32) ? 4 : 2; + const FF_T_UINT32 uNumClusters = pIoman->pPartition->NumClusters; *pError = FF_ERR_NONE; @@ -495,59 +663,58 @@ } #endif - if(pIoman->pPartition->Type == FF_T_FAT32) { - EntriesPerSector = pIoman->BlkSize / 4; - FatOffset = nCluster * 4; - } else { - EntriesPerSector = pIoman->BlkSize / 2; - FatOffset = nCluster * 2; - } + EntriesPerSector = pIoman->BlkSize / EntrySize; + FatOffset = nCluster * EntrySize; - // 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); + for(FatSector = (FatOffset / pIoman->pPartition->BlkSize); + FatSector < pIoman->pPartition->SectorsPerFAT; + FatSector++) { + pBuffer = FF_GetBuffer(pIoman, pIoman->pPartition->FatBeginLBA + FatSector, FF_MODE_READ); { if(!pBuffer) { - *pError = FF_ERR_DEVICE_DRIVER_FAILED; + *pError = FF_ERR_DEVICE_DRIVER_FAILED | FF_FINDFREECLUSTER; return 0; } for(x = nCluster % EntriesPerSector; x < EntriesPerSector; x++) { + // HT double-check: don't use non-existing clusters + if (nCluster >= uNumClusters) { + FF_ReleaseBuffer(pIoman, pBuffer); // Returning an error already, so don't check error here. + *pError = FF_ERR_IOMAN_NOT_ENOUGH_FREE_SPACE | FF_FINDFREECLUSTER; + return 0; + } + FatSectorEntry = FatOffset % pIoman->pPartition->BlkSize; if(pIoman->pPartition->Type == FF_T_FAT32) { - FatOffset = x * 4; - FatSectorEntry = FatOffset % pIoman->pPartition->BlkSize; - FatEntry = FF_getLong(pBuffer->pBuffer, (FF_T_UINT16)FatSectorEntry); + FatEntry = FF_getLong(pBuffer->pBuffer, FatSectorEntry); FatEntry &= 0x0fffffff; // Clear the top 4 bits. } else { - FatOffset = x * 2; - FatSectorEntry = FatOffset % pIoman->pPartition->BlkSize; - FatEntry = (FF_T_UINT32) FF_getShort(pBuffer->pBuffer, (FF_T_UINT16)FatSectorEntry); + FatEntry = (FF_T_UINT32) FF_getShort(pBuffer->pBuffer, FatSectorEntry); } if(FatEntry == 0x00000000) { - FF_ReleaseBuffer(pIoman, pBuffer); + *pError = FF_ReleaseBuffer(pIoman, pBuffer); + if(FF_isERR(*pError)) { + return 0; + } pIoman->pPartition->LastFreeCluster = nCluster; - return nCluster; } - + FatOffset += EntrySize; nCluster++; } } - FF_ReleaseBuffer(pIoman, pBuffer); + *pError = FF_ReleaseBuffer(pIoman, pBuffer); + if(FF_isERR(*pError)) { + return 0; + } } - + *pError = FF_ERR_IOMAN_NOT_ENOUGH_FREE_SPACE | FF_FINDFREECLUSTER; return 0; } /** * @private * @brief Create's a Cluster Chain + * @return > 0 New created cluster + * @return = 0 See pError **/ FF_T_UINT32 FF_CreateClusterChain(FF_IOMAN *pIoman, FF_ERROR *pError) { FF_T_UINT32 iStartCluster; @@ -557,15 +724,15 @@ FF_lockFAT(pIoman); { iStartCluster = FF_FindFreeCluster(pIoman, &Error); - if(Error) { + if(FF_isERR(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) { + Error = FF_putFatEntry(pIoman, iStartCluster, 0xFFFFFFFF, NULL); // Mark the cluster as End-Of-Chain + if(FF_isERR(Error)) { *pError = Error; FF_unlockFAT(pIoman); return 0; @@ -576,7 +743,7 @@ if(iStartCluster) { Error = FF_DecreaseFreeClusters(pIoman, 1); - if(Error) { + if(FF_isERR(Error)) { *pError = Error; return 0; } @@ -587,15 +754,18 @@ FF_T_UINT32 FF_GetChainLength(FF_IOMAN *pIoman, FF_T_UINT32 pa_nStartCluster, FF_T_UINT32 *piEndOfChain, FF_ERROR *pError) { FF_T_UINT32 iLength = 0; + FF_FatBuffers FatBuf; + FF_InitFatBuffer (&FatBuf, FF_MODE_READ); *pError = FF_ERR_NONE; FF_lockFAT(pIoman); { while(!FF_isEndOfChain(pIoman, pa_nStartCluster)) { - pa_nStartCluster = FF_getFatEntry(pIoman, pa_nStartCluster, pError); - if(*pError) { - return 0; + pa_nStartCluster = FF_getFatEntry(pIoman, pa_nStartCluster, pError, &FatBuf); + if(FF_isERR(*pError)) { + iLength = 0; + break; } iLength++; } @@ -603,110 +773,76 @@ *piEndOfChain = pa_nStartCluster; } } + *pError = FF_ReleaseFatBuffer(pIoman, &FatBuf); FF_unlockFAT(pIoman); - return iLength; } /** * @private - * @brief Extend a Cluster chain by Count number of Clusters - * - * @param pIoman IOMAN object. - * @param StartCluster Cluster Number that starts the chain. - * @param Count Number of clusters to extend the chain with. - * - **/ -/* -FF_T_UINT32 FF_ExtendClusterChain(FF_IOMAN *pIoman, FF_T_UINT32 StartCluster, FF_T_UINT32 Count) { - - FF_T_UINT32 currentCluster = StartCluster, nextCluster; - FF_T_UINT32 clusEndOfChain; - FF_T_UINT32 i; - - clusEndOfChain = FF_FindEndOfChain(pIoman, StartCluster); - - nextCluster = FF_FindFreeCluster(pIoman); // Find Free clusters! - - FF_putFatEntry(pIoman, clusEndOfChain, nextCluster); - - for(i = 0; i <= Count; i++) { - currentCluster = nextCluster; - if(i == Count) { - FF_putFatEntry(pIoman, currentCluster, 0xFFFFFFFF); - break; - } - - nextCluster = FF_FindFreeCluster(pIoman); - FF_putFatEntry(pIoman, currentCluster, ++nextCluster); - } - FF_FlushCache(pIoman); - return currentCluster; -}*/ - - -/** - * @private * @brief Free's Disk space by freeing unused links on Cluster Chains * * @param pIoman, IOMAN object. * @param StartCluster Cluster Number that starts the chain. * @param Count Number of Clusters from the end of the chain to unlink. * @param Count 0 Means Free the entire chain (delete file). + * @param Count 1 Means mark the start cluster with EOF. * * @return 0 On Success. * @return -1 If the device driver failed to provide access. * **/ -FF_ERROR 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_BOOL bTruncate) { FF_T_UINT32 fatEntry; - FF_T_UINT32 currentCluster, chainLength = 0; + FF_T_UINT32 currentCluster; FF_T_UINT32 iLen = 0; FF_T_UINT32 lastFree = StartCluster; /* HT addition : reset LastFreeCluster */ - FF_ERROR Error; + FF_ERROR Error = FF_ERR_NONE; + FF_FatBuffers FatBuf; + FF_InitFatBuffer (&FatBuf, FF_MODE_WRITE); fatEntry = StartCluster; - if(Count == 0) { - // Free all clusters in the chain! - currentCluster = StartCluster; - fatEntry = currentCluster; - do { - fatEntry = FF_getFatEntry(pIoman, fatEntry, &Error); - if(Error) { - return Error; - } - Error = FF_putFatEntry(pIoman, currentCluster, 0x00000000); - if(Error) { - return Error; - } + // Free all clusters in the chain! + currentCluster = StartCluster; + fatEntry = currentCluster; + do { + // Sector will now be fetched in write-mode + fatEntry = FF_getFatEntry(pIoman, fatEntry, &Error, &FatBuf); + if(FF_isERR(Error)) { + goto out; + } - if (lastFree > currentCluster) { - lastFree = currentCluster; - } - currentCluster = fatEntry; - iLen ++; - }while(!FF_isEndOfChain(pIoman, fatEntry)); - if (pIoman->pPartition->LastFreeCluster > lastFree) { - pIoman->pPartition->LastFreeCluster = lastFree; + if(bTruncate && currentCluster == StartCluster) { + Error = FF_putFatEntry(pIoman, currentCluster, 0xFFFFFFFF, &FatBuf); + }else { + Error = FF_putFatEntry(pIoman, currentCluster, 0x00000000, &FatBuf); } - Error = FF_IncreaseFreeClusters(pIoman, iLen); - if(Error) { - return Error; + if(FF_isERR(Error)) { + goto out; } - } else { - // Truncation - This is quite hard, because we can only do it backwards. - do { - fatEntry = FF_getFatEntry(pIoman, fatEntry, &Error); - if(Error) { - return Error; - } - chainLength++; - }while(!FF_isEndOfChain(pIoman, fatEntry)); + + if (lastFree > currentCluster) { + lastFree = currentCluster; + } + currentCluster = fatEntry; + iLen ++; + + }while(!FF_isEndOfChain(pIoman, fatEntry)); + + if (pIoman->pPartition->LastFreeCluster > lastFree) { + pIoman->pPartition->LastFreeCluster = lastFree; } +out: + Error = FF_ReleaseFatBuffer(pIoman, &FatBuf); + if(FF_isERR(Error)) { + FF_IncreaseFreeClusters(pIoman, iLen); + return Error; + } - return FF_ERR_NONE; + Error = FF_IncreaseFreeClusters(pIoman, iLen); + return Error; } #ifdef FF_FAT12_SUPPORT @@ -719,8 +855,8 @@ *pError = FF_ERR_NONE; for(i = 0; i < TotalClusters; i++) { - FatEntry = FF_getFatEntry(pIoman, i, pError); - if(*pError) { + FatEntry = FF_getFatEntry(pIoman, i, pError, NULL); + if(FF_isERR(*pError)) { return 0; } if(!FatEntry) { @@ -735,20 +871,17 @@ 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; - FF_T_UINT32 FatSector; - FF_T_UINT32 FatSectorEntry; + FF_T_UINT32 i, x; + FF_T_UINT32 FatEntry; FF_T_UINT32 EntriesPerSector; - FF_T_UINT32 FatEntry = 1; FF_T_UINT32 FreeClusters = 0; - + FF_T_UINT32 ClusterNum = 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! FreeClusters = FF_CountFreeClustersOLD(pIoman, pError); - if(*pError) { + if(FF_isERR(*pError)) { return 0; } } @@ -756,42 +889,44 @@ if(pIoman->pPartition->Type == FF_T_FAT32) { EntriesPerSector = pIoman->BlkSize / 4; - FatOffset = nCluster * 4; } else { EntriesPerSector = pIoman->BlkSize / 2; - FatOffset = nCluster * 2; } - FatSector = (FatOffset / pIoman->pPartition->BlkSize); + if (!pIoman->pPartition->BlkSize) + return 0; // better double-check than... 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; + *pError = FF_ERR_DEVICE_DRIVER_FAILED | FF_COUNTFREECLUSTERS; return 0; } - for(x = nCluster % EntriesPerSector; x < EntriesPerSector; x++) { + for(x = 0; x < EntriesPerSector; x++) { if(pIoman->pPartition->Type == FF_T_FAT32) { - FatOffset = x * 4; - FatSectorEntry = FatOffset % pIoman->pPartition->BlkSize; - FatEntry = FF_getLong(pBuffer->pBuffer, (FF_T_UINT16)FatSectorEntry); - FatEntry &= 0x0fffffff; // Clear the top 4 bits. + FatEntry = FF_getLong(pBuffer->pBuffer, x * 4) & 0x0fffffff; // Clearing the top 4 bits. } else { - FatOffset = x * 2; - FatSectorEntry = FatOffset % pIoman->pPartition->BlkSize; - FatEntry = (FF_T_UINT32) FF_getShort(pBuffer->pBuffer, FatSectorEntry); + FatEntry = (FF_T_UINT32) FF_getShort(pBuffer->pBuffer, x * 2); } - if(FatEntry == 0x00000000) { - FreeClusters += 1; + if (!FatEntry) { + FreeClusters++; } - - nCluster++; + if(ClusterNum > pIoman->pPartition->NumClusters) { // FAT table might not be cluster aligned + break; // Stop counting if thats the case. + } + ClusterNum++; } } - FF_ReleaseBuffer(pIoman, pBuffer); + *pError = FF_ReleaseBuffer(pIoman, pBuffer); + if(FF_isERR(*pError)) { + return 0; + } + if(ClusterNum > pIoman->pPartition->NumClusters) { + break; // Break out of 2nd loop too ^^ + } } - + // FreeClusters is -2 because the first 2 fat entries in the table are reserved. return FreeClusters <= pIoman->pPartition->NumClusters ? FreeClusters : pIoman->pPartition->NumClusters; } @@ -806,7 +941,7 @@ { if(!pIoman->pPartition->FreeClusterCount) { pIoman->pPartition->FreeClusterCount = FF_CountFreeClusters(pIoman, &Error); - if(Error) { + if(FF_isERR(Error)) { if(pError) { *pError = Error; } @@ -823,7 +958,7 @@ return 0; } #else -FF_T_UINT32 FF_GetFreeSize(FF_IOMAN *pIoman) { +FF_T_UINT32 FF_GetFreeSize(FF_IOMAN *pIoman, FF_ERROR *pError) { FF_T_UINT32 FreeClusters; FF_T_UINT32 FreeSize; @@ -831,7 +966,11 @@ FF_lockFAT(pIoman); { if(!pIoman->pPartition->FreeClusterCount) { - pIoman->pPartition->FreeClusterCount = FF_CountFreeClusters(pIoman); + pIoman->pPartition->FreeClusterCount = FF_CountFreeClusters(pIoman, pError); + if(FF_isERR(*pError)) { + FF_unlockFAT(pIoman); + return 0; + } } FreeClusters = pIoman->pPartition->FreeClusterCount; } @@ -841,4 +980,4 @@ } return 0; } -#endif \ No newline at end of file +#endif Index: ff_file.c =================================================================== --- ff_file.c (revision 58178) +++ ff_file.c (working copy) @@ -1,7 +1,19 @@ /***************************************************************************** - * FullFAT - High Performance, Thread-Safe Embedded FAT File-System * - * Copyright (C) 2009 James Walmsley (james@worm.me.uk) * + * FullFAT - High Performance, Thread-Safe Embedded FAT File-System * * * + * Copyright(C) 2009 James Walmsley * + * Copyright(C) 2011 Hein Tibosch * + * * + * See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT. * + * * + * WARNING : COMMERCIAL PROJECTS MUST COMPLY WITH THE GNU GPL LICENSE. * + * * + * Projects that cannot comply with the GNU GPL terms are legally obliged * + * to seek alternative licensing. Contact James Walmsley for details. * + * * + ***************************************************************************** + * See http://www.fullfat-fs.co.uk/ for more information. * + ***************************************************************************** * 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 * @@ -15,18 +27,14 @@ * 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. * + * The Copyright of Hein Tibosch on this project recognises his efforts in * + * contributing to this project. The right to license the project under * + * any other terms (other than the GNU GPL license) remains with the * + * original copyright holder (James Walmsley) only. * * * - * 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. * + * Modification/Extensions/Bugfixes/Improvements to FullFAT must be sent to * + * James Walmsley for integration into the main development branch. * *****************************************************************************/ /** @@ -157,7 +165,7 @@ 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 @@ -168,25 +176,37 @@ FF_T_UINT16 i; if(pError) { - *pError = 0; + *pError = FF_ERR_NONE; } - + if(!pIoman) { if(pError) { - *pError = FF_ERR_NULL_POINTER; + *pError = (FF_ERR_NULL_POINTER | FF_OPEN); } return (FF_FILE *)NULL; } pFile = FF_MALLOC(sizeof(FF_FILE)); if(!pFile) { if(pError) { - *pError = FF_ERR_NOT_ENOUGH_MEMORY; + *pError = (FF_ERR_NOT_ENOUGH_MEMORY | FF_OPEN); } return (FF_FILE *)NULL; } + memset (pFile, 0, sizeof *pFile); // Get the Mode Bits. pFile->Mode = Mode; +#ifdef FF_OPTIMISE_UNALIGNED_ACCESS + pFile->pBuf = (FF_T_UINT8 *) FF_MALLOC(pIoman->BlkSize); + if (pFile->pBuf == NULL) { + if(pError) { + *pError = FF_ERR_NOT_ENOUGH_MEMORY | FF_OPEN; + } + FF_FREE(pFile); + return (FF_FILE *)NULL; + } + memset(pFile->pBuf, 0, pIoman->BlkSize); +#endif #ifdef FF_UNICODE_SUPPORT i = (FF_T_UINT16) wcslen(path); @@ -212,140 +232,143 @@ DirCluster = FF_FindDir(pIoman, path, i, &Error); - if(Error) { + if(FF_isERR(Error)) { if(pError) { *pError = Error; } - FF_FREE(pFile); - return (FF_FILE *) NULL; + goto out; } - if(DirCluster) { + if(!DirCluster) { + if(pError) { + *pError = (FF_ERR_FILE_INVALID_PATH | FF_OPEN); + } + goto out; + } - FileCluster = FF_FindEntryInDir(pIoman, DirCluster, filename, 0x00, &Object, &Error); - if(Error) { - if(pError) { - *pError = Error; - } - FF_FREE(pFile); - return (FF_FILE *) NULL; + FileCluster = FF_FindEntryInDir(pIoman, DirCluster, filename, 0x00, &Object, &Error); + if(FF_isERR(Error)) { + if(pError) { + *pError = Error; } + goto out; + } - if(!FileCluster) { // If 0 was returned, it might be because the file has no allocated cluster + 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) { + 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) { + 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; - } - } + // The file really was found! + FileCluster = 1; + } } + } - if(!FileCluster) { - if((pFile->Mode & FF_MODE_CREATE)) { - FileCluster = FF_CreateFile(pIoman, DirCluster, filename, &Object, &Error); - if(Error) { - if(pError) { - *pError = Error; - } - FF_FREE(pFile); - return (FF_FILE *) NULL; + if(!FileCluster) { + if((pFile->Mode & FF_MODE_CREATE)) { + FileCluster = FF_CreateFile(pIoman, DirCluster, filename, &Object, &Error); + if(FF_isERR(Error)) { + if(pError) { + *pError = Error; } - Object.CurrentItem += 1; + goto out; } + Object.CurrentItem += 1; } - - if(FileCluster) { - if(Object.Attrib == FF_FAT_ATTR_DIR) { - if(!(pFile->Mode & FF_MODE_DIR)) { - // Not the object, File Not Found! - FF_FREE(pFile); - if(pError) { - *pError = FF_ERR_FILE_OBJECT_IS_A_DIR; - } - return (FF_FILE *) NULL; - } - } - - //---------- Ensure Read-Only files don't get opened for Writing. - if((pFile->Mode & FF_MODE_WRITE) || (pFile->Mode & FF_MODE_APPEND)) { - if((Object.Attrib & FF_FAT_ATTR_READONLY)) { - FF_FREE(pFile); - if(pError) { - *pError = FF_ERR_FILE_IS_READ_ONLY; - } - return (FF_FILE *) NULL; - } - } - pFile->pIoman = pIoman; - pFile->FilePointer = 0; - pFile->ObjectCluster = Object.ObjectCluster; - pFile->Filesize = Object.Filesize; - pFile->CurrentCluster = 0; - pFile->AddrCurrentCluster = pFile->ObjectCluster; - //pFile->Mode = Mode; - pFile->Next = NULL; - pFile->DirCluster = DirCluster; - pFile->DirEntry = Object.CurrentItem - 1; - nBytesPerCluster = pFile->pIoman->pPartition->SectorsPerCluster / pIoman->BlkSize; - pFile->iChainLength = 0; - pFile->iEndOfChain = 0; - pFile->FileDeleted = FF_FALSE; + } + + if(!FileCluster) { + if(pError) { + *pError = (FF_ERR_FILE_NOT_FOUND | FF_OPEN); + } + goto out; + } - // File Permission Processing - // Only "w" and "w+" mode strings can erase a file's contents. - // Any other combinations will not cause an erase. - if((pFile->Mode & FF_MODE_TRUNCATE)) { - pFile->Filesize = 0; - pFile->FilePointer = 0; - } + // So now we have a FileCluster - /* - Add pFile onto the end of our linked list of FF_FILE objects. - */ - FF_PendSemaphore(pIoman->pSemaphore); - { - if(!pIoman->FirstFile) { - pIoman->FirstFile = pFile; - } else { - pFileChain = (FF_FILE *) pIoman->FirstFile; - do { - if(pFileChain->ObjectCluster == pFile->ObjectCluster) { - // File is already open! DON'T ALLOW IT! - FF_ReleaseSemaphore(pIoman->pSemaphore); - FF_FREE(pFile); - if(pError) { - *pError = FF_ERR_FILE_ALREADY_OPEN; - } - return (FF_FILE *) NULL; - } - if(!pFileChain->Next) { - pFileChain->Next = pFile; - break; - } - pFileChain = (FF_FILE *) pFileChain->Next; - }while(pFileChain != NULL); - } + // Check the Mode flags + if(Object.Attrib == FF_FAT_ATTR_DIR) { + if(!(pFile->Mode & FF_MODE_DIR)) { + // Not the object, File Not Found! + if(pError) { + *pError = (FF_ERR_FILE_OBJECT_IS_A_DIR | FF_OPEN); } - FF_ReleaseSemaphore(pIoman->pSemaphore); - - return pFile; - }else { - FF_FREE(pFile); + goto out; + } + } + + //---------- Ensure Read-Only files don't get opened for Writing. + if(pFile->Mode & (FF_MODE_WRITE | FF_MODE_APPEND)) { + if((Object.Attrib & FF_FAT_ATTR_READONLY)) { if(pError) { - *pError = FF_ERR_FILE_NOT_FOUND; + *pError = (FF_ERR_FILE_IS_READ_ONLY | FF_OPEN); } - return (FF_FILE *) NULL; - } + goto out; + } } - if(pError) { - *pError = FF_ERR_FILE_INVALID_PATH; + pFile->pIoman = pIoman; + pFile->FilePointer = 0; + pFile->ObjectCluster = Object.ObjectCluster; + pFile->Filesize = Object.Filesize; + pFile->CurrentCluster = 0; + pFile->AddrCurrentCluster = pFile->ObjectCluster; + //pFile->Mode = Mode; + pFile->Next = NULL; + pFile->DirCluster = DirCluster; + pFile->DirEntry = Object.CurrentItem - 1; + pFile->iChainLength = 0; + pFile->iEndOfChain = 0; + pFile->ValidFlags &= ~(FF_VALID_FLAG_DELETED); //FF_FALSE; + + // File Permission Processing + // Only "w" and "w+" mode strings can erase a file's contents. + // Any other combinations will not cause an erase. + if((pFile->Mode & FF_MODE_TRUNCATE)) { + pFile->Filesize = 0; + pFile->FilePointer = 0; } + /* + Add pFile onto the end of our linked list of FF_FILE objects. + */ + FF_PendSemaphore(pIoman->pSemaphore); + { + if(!pIoman->FirstFile) { + pIoman->FirstFile = pFile; + } else { + pFileChain = (FF_FILE *) pIoman->FirstFile; + do { + if(pFileChain->ObjectCluster == pFile->ObjectCluster) { + // HT: Only fail if any of them has write access... + // Why not have 2 open read handles to a single file? + if ((pFileChain->Mode | pFile->Mode) & (FF_MODE_WRITE | FF_MODE_APPEND)) { + // File is already open! DON'T ALLOW IT! + FF_ReleaseSemaphore(pIoman->pSemaphore); + if(pError) { + *pError = (FF_ERR_FILE_ALREADY_OPEN | FF_OPEN); + } + goto out; + } + } + if(!pFileChain->Next) { + pFileChain->Next = pFile; + break; + } + pFileChain = (FF_FILE *) pFileChain->Next; + }while(pFileChain != NULL); + } + } + FF_ReleaseSemaphore(pIoman->pSemaphore); + + return pFile; +out: +#ifdef FF_OPTIMISE_UNALIGNED_ACCESS + FF_FREE(pFile->pBuf); +#endif FF_FREE(pFile); return (FF_FILE *)NULL; @@ -394,13 +417,13 @@ FF_ERROR Error = FF_ERR_NONE; FF_T_UINT8 EntryBuffer[32]; FF_FETCH_CONTEXT FetchContext; - FF_T_SINT8 RetVal = FF_ERR_NONE; + FF_ERROR RetVal = FF_ERR_NONE; #ifdef FF_PATH_CACHE FF_T_UINT32 i; #endif if(!pIoman) { - return FF_ERR_NULL_POINTER; + return (FF_ERR_NULL_POINTER | FF_RMDIR); } pFile = FF_Open(pIoman, path, FF_MODE_DIR, &Error); @@ -409,7 +432,7 @@ return Error; // File in use or File not found! } - pFile->FileDeleted = FF_TRUE; + pFile->ValidFlags |= FF_VALID_FLAG_DELETED;//FF_TRUE; FF_lockDIR(pIoman); { @@ -420,7 +443,7 @@ } FF_unlockFAT(pIoman); - if(Error) { + if(FF_isERR(Error)) { FF_unlockDIR(pIoman); FF_Close(pFile); return Error; @@ -429,7 +452,7 @@ // Initialise the dirent Fetch Context object for faster removal of dirents. Error = FF_InitEntryFetch(pIoman, pFile->DirCluster, &FetchContext); - if(Error) { + if(FF_isERR(Error)) { FF_unlockDIR(pIoman); FF_Close(pFile); return Error; @@ -437,23 +460,23 @@ // Edit the Directory Entry! (So it appears as deleted); Error = FF_RmLFNs(pIoman, pFile->DirEntry, &FetchContext); - if(Error) { - FF_CleanupEntryFetch(pIoman, &FetchContext); + if(FF_isERR(Error)) { + FF_CleanupEntryFetch(pIoman, &FetchContext); // Don't override error! FF_unlockDIR(pIoman); FF_Close(pFile); return Error; } Error = FF_FetchEntryWithContext(pIoman, pFile->DirEntry, &FetchContext, EntryBuffer); - if(Error) { - FF_CleanupEntryFetch(pIoman, &FetchContext); + if(FF_isERR(Error)) { + FF_CleanupEntryFetch(pIoman, &FetchContext); // Don't override error! FF_unlockDIR(pIoman); FF_Close(pFile); return Error; } EntryBuffer[0] = 0xE5; Error = FF_PushEntryWithContext(pIoman, pFile->DirEntry, &FetchContext, EntryBuffer); - if(Error) { - FF_CleanupEntryFetch(pIoman, &FetchContext); + if(FF_isERR(Error)) { + FF_CleanupEntryFetch(pIoman, &FetchContext); // Don't override error! FF_unlockDIR(pIoman); FF_Close(pFile); return Error; @@ -477,29 +500,33 @@ #endif Error = FF_IncreaseFreeClusters(pIoman, pFile->iChainLength); - if(Error) { - FF_CleanupEntryFetch(pIoman, &FetchContext); + if(FF_isERR(Error)) { + FF_CleanupEntryFetch(pIoman, &FetchContext); // Don't override error! FF_unlockDIR(pIoman); FF_Close(pFile); return Error; } - FF_CleanupEntryFetch(pIoman, &FetchContext); + Error = FF_CleanupEntryFetch(pIoman, &FetchContext); + if(FF_isERR(Error)) { + FF_unlockDIR(pIoman); + FF_Close(pFile); + return Error; + } Error = FF_FlushCache(pIoman); - if(Error) { + if(FF_isERR(Error)) { FF_unlockDIR(pIoman); FF_Close(pFile); return Error; } } else { - RetVal = FF_ERR_DIR_NOT_EMPTY; + RetVal = (FF_ERR_DIR_NOT_EMPTY | FF_RMDIR); } } FF_unlockDIR(pIoman); Error = FF_Close(pFile); // Free the file pointer resources - - if(Error) { + if(FF_isERR(Error)) { return Error; } @@ -517,13 +544,13 @@ FF_T_UINT8 EntryBuffer[32]; FF_FETCH_CONTEXT FetchContext; - pFile = FF_Open(pIoman, path, FF_MODE_READ, &Error); + pFile = FF_Open(pIoman, path, FF_MODE_WRITE, &Error); if(!pFile) { return Error; // File in use or File not found! } - pFile->FileDeleted = FF_TRUE; + pFile->ValidFlags |= FF_VALID_FLAG_DELETED;//FF_TRUE; if(pFile->ObjectCluster) { // Ensure there is actually a cluster chain to delete! FF_lockFAT(pIoman); // Lock the FAT so its thread-safe. @@ -532,7 +559,7 @@ } FF_unlockFAT(pIoman); - if(Error) { + if(FF_isERR(Error)) { FF_Close(pFile); return Error; } @@ -542,21 +569,21 @@ FF_lockDIR(pIoman); { Error = FF_InitEntryFetch(pIoman, pFile->DirCluster, &FetchContext); - if(Error) { + if(FF_isERR(Error)) { FF_unlockDIR(pIoman); FF_Close(pFile); return Error; } - Error = FF_RmLFNs(pIoman, pFile->DirEntry, &FetchContext); - if(Error) { - FF_CleanupEntryFetch(pIoman, &FetchContext); + Error = FF_RmLFNs(pIoman, (FF_T_UINT16)pFile->DirEntry, &FetchContext); + if(FF_isERR(Error)) { + FF_CleanupEntryFetch(pIoman, &FetchContext); // Don't override error! FF_unlockDIR(pIoman); FF_Close(pFile); return Error; } Error = FF_FetchEntryWithContext(pIoman, pFile->DirEntry, &FetchContext, EntryBuffer); - if(Error) { - FF_CleanupEntryFetch(pIoman, &FetchContext); + if(FF_isERR(Error)) { + FF_CleanupEntryFetch(pIoman, &FetchContext); // Don't override error! FF_unlockDIR(pIoman); FF_Close(pFile); return Error; @@ -564,24 +591,30 @@ EntryBuffer[0] = 0xE5; Error = FF_PushEntryWithContext(pIoman, pFile->DirEntry, &FetchContext, EntryBuffer); - if(Error) { - FF_CleanupEntryFetch(pIoman, &FetchContext); + if(FF_isERR(Error)) { + FF_CleanupEntryFetch(pIoman, &FetchContext); // Don't override error! FF_unlockDIR(pIoman); FF_Close(pFile); return Error; } - FF_CleanupEntryFetch(pIoman, &FetchContext); + Error = FF_CleanupEntryFetch(pIoman, &FetchContext); + if(FF_isERR(Error)) { + FF_unlockDIR(pIoman); + FF_Close(pFile); + return Error; + } } FF_unlockDIR(pIoman); Error = FF_FlushCache(pIoman); - if(Error) { + if(FF_isERR(Error)) { FF_Close(pFile); return Error; } Error = FF_Close(pFile); // Free the file pointer resources + return Error; } @@ -614,20 +647,23 @@ FF_FETCH_CONTEXT FetchContext; if(!pIoman) { - return FF_ERR_NULL_POINTER; + return (FF_ERR_NULL_POINTER | FF_MOVE); } // Check destination file doesn't exist! pDestFile = FF_Open(pIoman, szDestinationFile, FF_MODE_READ, &Error); - if(pDestFile || (Error == FF_ERR_FILE_OBJECT_IS_A_DIR)) { - FF_Close(pDestFile); - return FF_ERR_FILE_DESTINATION_EXISTS; // YES -- FAIL + if(pDestFile || (FF_GETERROR(Error) == FF_ERR_FILE_OBJECT_IS_A_DIR)) { + if (pDestFile) { + FF_Close(pDestFile); + } + + return (FF_ERR_FILE_DESTINATION_EXISTS | FF_MOVE); // YES -- FAIL } pSrcFile = FF_Open(pIoman, szSourceFile, FF_MODE_READ, &Error); - if(Error == FF_ERR_FILE_OBJECT_IS_A_DIR) { + if(FF_GETERROR(Error) == FF_ERR_FILE_OBJECT_IS_A_DIR) { // Open a directory for moving! pSrcFile = FF_Open(pIoman, szSourceFile, FF_MODE_DIR, &Error); } @@ -636,108 +672,116 @@ return Error; } - if(pSrcFile) { - // Create the new dirent. - 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; + // Create the new dirent. + Error = FF_InitEntryFetch(pIoman, pSrcFile->DirCluster, &FetchContext); + if(FF_isERR(Error)) { + FF_Close(pSrcFile); + return Error; + } + Error = FF_FetchEntryWithContext(pIoman, pSrcFile->DirEntry, &FetchContext, EntryBuffer); + if(FF_isERR(Error)) { + FF_Close(pSrcFile); + FF_CleanupEntryFetch(pIoman, &FetchContext); // Don't override error! + 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); + i = (FF_T_UINT16) wcslen(szDestinationFile); #else - i = (FF_T_UINT16) strlen(szDestinationFile); + i = (FF_T_UINT16) strlen(szDestinationFile); #endif - while(i != 0) { - if(szDestinationFile[i] == '\\' || szDestinationFile[i] == '/') { - break; - } - i--; + while(i != 0) { + if(szDestinationFile[i] == '\\' || szDestinationFile[i] == '/') { + break; } + i--; + } #ifdef FF_UNICODE_SUPPORT - wcsncpy(MyFile.FileName, (szDestinationFile + i + 1), FF_MAX_FILENAME); + wcsncpy(MyFile.FileName, (szDestinationFile + i + 1), FF_MAX_FILENAME); #else - strncpy(MyFile.FileName, (szDestinationFile + i + 1), FF_MAX_FILENAME); + strncpy(MyFile.FileName, (szDestinationFile + i + 1), FF_MAX_FILENAME); #endif - if(i == 0) { - i = 1; - } - + if(i == 0) { + i = 1; + } + - DirCluster = FF_FindDir(pIoman, szDestinationFile, i, &Error); - if(Error) { + DirCluster = FF_FindDir(pIoman, szDestinationFile, i, &Error); + if(FF_isERR(Error)) { + FF_Close(pSrcFile); + FF_CleanupEntryFetch(pIoman, &FetchContext); // Don't override error! + return Error; + } + + if(DirCluster) { + // HT: Cleaup because FF_CreateDirent might want to write the same sector + Error = FF_CleanupEntryFetch(pIoman, &FetchContext); + if(FF_isERR(Error)) { FF_Close(pSrcFile); - FF_CleanupEntryFetch(pIoman, &FetchContext); return Error; } - - if(DirCluster) { + // Destination Dir was found, we can now create the new entry. + Error = FF_CreateDirent(pIoman, DirCluster, &MyFile); + if(FF_isERR(Error)) { + FF_Close(pSrcFile); + FF_CleanupEntryFetch(pIoman, &FetchContext); // TODO: Is this required?? + return Error; // FAILED + } - // Destination Dir was found, we can now create the new entry. - Error = FF_CreateDirent(pIoman, DirCluster, &MyFile); - if(Error) { + // Edit the Directory Entry! (So it appears as deleted); + FF_lockDIR(pIoman); + { + + Error = FF_RmLFNs(pIoman, pSrcFile->DirEntry, &FetchContext); + if(FF_isERR(Error)) { + FF_unlockDIR(pIoman); FF_Close(pSrcFile); - FF_CleanupEntryFetch(pIoman, &FetchContext); - return Error; // FAILED + FF_CleanupEntryFetch(pIoman, &FetchContext); // Don't override error! + return Error; } - - // Edit the Directory Entry! (So it appears as deleted); - FF_lockDIR(pIoman); - { - - 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); - 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); + Error = FF_FetchEntryWithContext(pIoman, pSrcFile->DirEntry, &FetchContext, EntryBuffer); + if(FF_isERR(Error)) { + FF_unlockDIR(pIoman); + FF_Close(pSrcFile); + FF_CleanupEntryFetch(pIoman, &FetchContext); // Don't override error! + return Error; } - FF_unlockDIR(pIoman); - FF_Close(pSrcFile); + EntryBuffer[0] = 0xE5; + //FF_PushEntry(pIoman, pSrcFile->DirCluster, pSrcFile->DirEntry, EntryBuffer); + Error = FF_PushEntryWithContext(pIoman, pSrcFile->DirEntry, &FetchContext, EntryBuffer); + if(FF_isERR(Error)) { + FF_unlockDIR(pIoman); + FF_Close(pSrcFile); + FF_CleanupEntryFetch(pIoman, &FetchContext); // Don't override error! + return Error; + } + Error = FF_CleanupEntryFetch(pIoman, &FetchContext); + if(FF_isERR(Error)) { + FF_unlockDIR(pIoman); + FF_Close(pSrcFile); + return Error; + } + } + FF_unlockDIR(pIoman); + FF_Close(pSrcFile); - FF_FlushCache(pIoman); - - return FF_ERR_NONE; + Error = FF_FlushCache(pIoman); + if(FF_isERR(Error)) { + return Error; } - return FF_ERR_FILE_DIR_NOT_FOUND; + return FF_ERR_NONE; + } - } - - return FF_ERR_FILE_SOURCE_NOT_FOUND; // Source not found! + return (FF_ERR_FILE_DIR_NOT_FOUND | FF_MOVE); } @@ -762,18 +806,46 @@ } } +/** + * @public + * @brief Checks the number of bytes left on a read handle + * + * @param pFile An open file handle + * + * @return Less than zero: an error code + * @return Number of bytes left to read from handle + **/ +FF_T_SINT32 FF_BytesLeft(FF_FILE *pFile) { + if(!pFile) { + return FF_ERR_NULL_POINTER | FF_BYTESLEFT; + } + if(!(pFile->Mode & FF_MODE_READ)) { + return FF_ERR_FILE_NOT_OPENED_IN_READ_MODE | FF_BYTESLEFT; + } + + if(pFile->FilePointer >= pFile->Filesize) { + return 0; + } else { + return pFile->Filesize - pFile->FilePointer; + } +} + + 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; + FF_FatBuffers FatBuf; + FF_InitFatBuffer (&FatBuf, FF_MODE_READ); *pError = FF_ERR_NONE; do { CurrentCluster = NextCluster; - NextCluster = FF_getFatEntry(pIoman, CurrentCluster, pError); - if(*pError) { - return 0; + NextCluster = FF_getFatEntry(pIoman, CurrentCluster, pError, &FatBuf); + if(FF_isERR(*pError)) { + i = 0; + break; } if(NextCluster == (CurrentCluster + 1)) { i++; @@ -787,6 +859,7 @@ } } }while(NextCluster == (CurrentCluster + 1)); + *pError = FF_ReleaseFatBuffer(pIoman, &FatBuf); return i; } @@ -801,7 +874,7 @@ while(Count != 0) { if((Count - 1) > 0) { SequentialClusters = FF_GetSequentialClusters(pFile->pIoman, pFile->AddrCurrentCluster, (Count - 1), &Error); - if(Error) { + if(FF_isERR(Error)) { return Error; } } @@ -809,14 +882,14 @@ nItemLBA = FF_Cluster2LBA(pFile->pIoman, pFile->AddrCurrentCluster); nItemLBA = FF_getRealLBA(pFile->pIoman, nItemLBA); - slRetVal = FF_BlockRead(pFile->pIoman, nItemLBA, ulSectors, buffer); + slRetVal = FF_BlockRead(pFile->pIoman, nItemLBA, ulSectors, buffer, FF_FALSE); if(slRetVal < 0) { return slRetVal; } Count -= (SequentialClusters + 1); pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->AddrCurrentCluster, (SequentialClusters + 1), &Error); - if(Error) { + if(FF_isERR(Error)) { return Error; } pFile->CurrentCluster += (SequentialClusters + 1); @@ -831,35 +904,34 @@ static FF_ERROR FF_ExtendFile(FF_FILE *pFile, FF_T_UINT32 Size) { FF_IOMAN *pIoman = pFile->pIoman; FF_T_UINT32 nBytesPerCluster = pIoman->pPartition->BlkSize * pIoman->pPartition->SectorsPerCluster; - FF_T_UINT32 nTotalClustersNeeded = Size / nBytesPerCluster; + FF_T_UINT32 nTotalClustersNeeded = (Size + nBytesPerCluster-1) / nBytesPerCluster; FF_T_UINT32 nClusterToExtend; FF_T_UINT32 CurrentCluster, NextCluster; FF_T_UINT32 i; FF_DIRENT OriginalEntry; - FF_ERROR Error; + FF_ERROR Error = FF_ERR_NONE; + FF_FatBuffers FatBuf; if((pFile->Mode & FF_MODE_WRITE) != FF_MODE_WRITE) { - return FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE; + return (FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE | FF_EXTENDFILE); } if(pFile->Filesize == 0 && pFile->ObjectCluster == 0) { // No Allocated clusters. // Create a Cluster chain! pFile->AddrCurrentCluster = FF_CreateClusterChain(pFile->pIoman, &Error); - if(Error) { + if(FF_isERR(Error)) { return Error; } Error = FF_GetEntry(pIoman, pFile->DirEntry, pFile->DirCluster, &OriginalEntry); - if(!Error) { + if(!FF_isERR(Error)) { OriginalEntry.ObjectCluster = pFile->AddrCurrentCluster; Error = FF_PutEntry(pIoman, pFile->DirEntry, pFile->DirCluster, &OriginalEntry); - } else { - return Error; } - if(Error) { + if(FF_isERR(Error)) { return Error; } @@ -869,13 +941,9 @@ pFile->iEndOfChain = pFile->AddrCurrentCluster; } - if(Size % nBytesPerCluster) { - nTotalClustersNeeded += 1; - } - if(pFile->iChainLength == 0) { // First extension requiring the chain length, pFile->iChainLength = FF_GetChainLength(pIoman, pFile->ObjectCluster, &pFile->iEndOfChain, &Error); - if(Error) { + if(FF_isERR(Error)) { return Error; } } @@ -887,53 +955,64 @@ NextCluster = pFile->AddrCurrentCluster; FF_lockFAT(pIoman); { - for(i = 0; i <= nClusterToExtend; i++) { + // HT This "<=" issue is now solved by asing for 1 extra byte + // Thus not always asking for 1 extra cluster + for(i = 0; i < nClusterToExtend; i++) { CurrentCluster = FF_FindEndOfChain(pIoman, NextCluster, &Error); - if(Error) { - FF_unlockFAT(pIoman); - FF_DecreaseFreeClusters(pIoman, i); - return Error; + if(FF_isERR(Error)) { + break; } NextCluster = FF_FindFreeCluster(pIoman, &Error); - if(Error) { - FF_unlockFAT(pIoman); - FF_DecreaseFreeClusters(pIoman, i); - return Error; + if(!FF_isERR(Error) && !NextCluster) { + Error = FF_ERR_FAT_NO_FREE_CLUSTERS | FF_EXTENDFILE; } - if(!NextCluster) { - FF_unlockFAT(pIoman); - FF_DecreaseFreeClusters(pIoman, i); - return FF_ERR_FAT_NO_FREE_CLUSTERS; + if(FF_isERR(Error)) { + break; } - - Error = FF_putFatEntry(pIoman, CurrentCluster, NextCluster); - if(Error) { - FF_unlockFAT(pIoman); - FF_DecreaseFreeClusters(pIoman, i); - return Error; + // Can not use this buffer earlier because of FF_FindEndOfChain/FF_FindFreeCluster + FF_InitFatBuffer (&FatBuf, FF_MODE_WRITE); + Error = FF_putFatEntry(pIoman, CurrentCluster, NextCluster, &FatBuf); + if(!FF_isERR(Error)) { + Error = FF_putFatEntry(pIoman, NextCluster, 0xFFFFFFFF, &FatBuf); } - Error = FF_putFatEntry(pIoman, NextCluster, 0xFFFFFFFF); - if(Error) { - FF_unlockFAT(pIoman); - FF_DecreaseFreeClusters(pIoman, i); - return Error; - } + Error = FF_ReleaseFatBuffer(pIoman, &FatBuf); + if(FF_isERR(Error)) + break; } + if(FF_isERR(Error)) { + FF_unlockFAT(pIoman); + FF_DecreaseFreeClusters(pIoman, i); + return Error; + } pFile->iEndOfChain = FF_FindEndOfChain(pIoman, NextCluster, &Error); - if(Error) { + if(FF_isERR(Error)) { FF_unlockFAT(pIoman); FF_DecreaseFreeClusters(pIoman, i); return Error; } } FF_unlockFAT(pIoman); - pFile->iChainLength += i; Error = FF_DecreaseFreeClusters(pIoman, i); // Keep Tab of Numbers for fast FreeSize() - if(Error) { + if(FF_isERR(Error)) { return Error; } + + /** + * We must ensure that the AddrCurrentCluster is not out-of-sync with the CurrentCluster number. + * This could have occured in append mode, where the file was opened with a filesize % clustersize == 0 + * because of a seek, where the AddrCurrentCluster was not updated after extending. This caused the data to + * be written to the previous cluster(s). + **/ + if(pFile->CurrentCluster == pFile->iChainLength-1 && pFile->AddrCurrentCluster != pFile->iEndOfChain) { + pFile->AddrCurrentCluster = pFile->iEndOfChain; + } + + Error = FF_FlushCache(pIoman); + if (Error) { + return Error; + } } return FF_ERR_NONE; @@ -949,7 +1028,7 @@ while(Count != 0) { if((Count - 1) > 0) { SequentialClusters = FF_GetSequentialClusters(pFile->pIoman, pFile->AddrCurrentCluster, (Count - 1), &Error); - if(Error) { + if(FF_isERR(Error)) { return Error; } } @@ -957,7 +1036,7 @@ nItemLBA = FF_Cluster2LBA(pFile->pIoman, pFile->AddrCurrentCluster); nItemLBA = FF_getRealLBA(pFile->pIoman, nItemLBA); - slRetVal = FF_BlockWrite(pFile->pIoman, nItemLBA, ulSectors, buffer); + slRetVal = FF_BlockWrite(pFile->pIoman, nItemLBA, ulSectors, buffer, FF_FALSE); if(slRetVal < 0) { return slRetVal; @@ -965,7 +1044,7 @@ Count -= (SequentialClusters + 1); pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->AddrCurrentCluster, (SequentialClusters + 1), &Error); - if(Error) { + if(FF_isERR(Error)) { return Error; } pFile->CurrentCluster += (SequentialClusters + 1); @@ -977,6 +1056,62 @@ } /** + * @private + * @brief Calculate the Logical Block Address (LBA) + * + * @param pFile The file handle + * + * @return LBA + * + * Must be set: + * - pFile->FilePointer : byte offset in file + * - pFile->AddrCurrentCluster : fysical cluster on the partition + **/ +static FF_T_UINT32 FF_FileLBA (FF_FILE *pFile) { + FF_T_UINT32 nItemLBA; + nItemLBA = FF_Cluster2LBA(pFile->pIoman, pFile->AddrCurrentCluster); + nItemLBA += FF_getMajorBlockNumber(pFile->pIoman, pFile->FilePointer, 1); + nItemLBA = FF_getRealLBA(pFile->pIoman, nItemLBA); + nItemLBA += FF_getMinorBlockNumber(pFile->pIoman, pFile->FilePointer, 1); + return nItemLBA; +} + +/** + * @private + * @brief Depending on FilePointer, calculate CurrentCluster + * @brief and traverse the FAT to find the right AddrCurrentCluster + * + * @param pFile The file handle + * + * @return FF_ERR_NONE on success + * @return Possible error returned by FF_TraverseFAT() or END_OF_DIR + * + * Side effects: + * - pFile->CurrentCluster : relative cluster number (0 <= Num < ulChainLength) + * - pFile->AddrCurrentCluster : fysical cluster on the partition + **/ + +static FF_T_UINT32 FF_SetCluster (FF_FILE *pFile, FF_ERROR *pError) { + FF_IOMAN *pIoman = pFile->pIoman; + FF_T_UINT32 nNewCluster = FF_getClusterChainNumber(pIoman, pFile->FilePointer, 1); + int bTraverse = 0; + + *pError = FF_ERR_NONE; + + if(nNewCluster > pFile->CurrentCluster || bTraverse) { + pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nNewCluster - pFile->CurrentCluster, pError); + } else if(nNewCluster < pFile->CurrentCluster) { + pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->ObjectCluster, nNewCluster, pError); + } else { + // Well positioned + } + if(FF_isERR(*pError)) + return 0; + pFile->CurrentCluster = nNewCluster; + return FF_FileLBA(pFile); +} + +/** * @public * @brief Equivalent to fread() * @@ -993,209 +1128,225 @@ FF_T_UINT32 nBytesRead = 0; FF_T_UINT32 nBytesToRead; FF_IOMAN *pIoman; +#ifndef FF_OPTIMISE_UNALIGNED_ACCESS FF_BUFFER *pBuffer; +#endif FF_T_UINT32 nRelBlockPos; FF_T_UINT32 nItemLBA; FF_T_SINT32 RetVal = 0; FF_T_UINT16 sSectors; FF_T_UINT32 nRelClusterPos; FF_T_UINT32 nBytesPerCluster; - FF_T_UINT32 nClusterDiff; FF_ERROR Error; if(!pFile) { - return FF_ERR_NULL_POINTER; + return (FF_ERR_NULL_POINTER | FF_READ); } + Error = FF_CheckValid (pFile); + if (Error) + return Error; if(!(pFile->Mode & FF_MODE_READ)) { - return FF_ERR_FILE_NOT_OPENED_IN_READ_MODE; + return (FF_ERR_FILE_NOT_OPENED_IN_READ_MODE | FF_READ); } pIoman = pFile->pIoman; - if(pFile->FilePointer == pFile->Filesize) { + if(pFile->FilePointer >= pFile->Filesize) { return 0; } if((pFile->FilePointer + nBytes) > pFile->Filesize) { nBytes = pFile->Filesize - pFile->FilePointer; } - - 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, &Error); - if(Error) { - return Error; - } - pFile->CurrentCluster += nClusterDiff; - } + nItemLBA = FF_SetCluster (pFile, &Error); + if(FF_isERR(Error)) { + return Error; } nRelBlockPos = FF_getMinorBlockEntry(pIoman, pFile->FilePointer, 1); // Get the position within a block. - nItemLBA = FF_Cluster2LBA(pIoman, pFile->AddrCurrentCluster); - nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1); - if((nRelBlockPos + nBytes) < pIoman->BlkSize) { // Bytes to read are within a block and less than a block size. +#ifdef FF_OPTIMISE_UNALIGNED_ACCESS + if(!(pFile->ucState & FF_BUFSTATE_VALID)) { + Error = FF_BlockRead(pIoman, nItemLBA, 1, pFile->pBuf, FF_FALSE); + if(FF_isERR(Error)) return Error; + pFile->ucState = FF_BUFSTATE_VALID; + } + memcpy(buffer, (pFile->pBuf + nRelBlockPos), nBytes); +#else pBuffer = FF_GetBuffer(pIoman, nItemLBA, FF_MODE_READ); { if(!pBuffer) { - return FF_ERR_DEVICE_DRIVER_FAILED; + return (FF_ERR_DEVICE_DRIVER_FAILED | FF_READ); } memcpy(buffer, (pBuffer->pBuffer + nRelBlockPos), nBytes); } - FF_ReleaseBuffer(pIoman, pBuffer); + Error = FF_ReleaseBuffer(pIoman, pBuffer); + if(FF_isERR(Error)) { + return Error; + } +#endif pFile->FilePointer += nBytes; - return nBytes; // Return the number of bytes read. + } - } else { + //---------- Read (memcpy) to a Sector Boundary + if(nRelBlockPos != 0) { // Not on a sector boundary, at this point the LBA is known. + nBytesToRead = pIoman->BlkSize - nRelBlockPos; +#ifdef FF_OPTIMISE_UNALIGNED_ACCESS + if(!(pFile->ucState & FF_BUFSTATE_VALID)) { + Error = FF_BlockRead(pIoman, nItemLBA, 1, pFile->pBuf, FF_FALSE); + if(FF_isERR(Error)) return Error; + pFile->ucState = FF_BUFSTATE_VALID; + } + memcpy(buffer, pFile->pBuf + nRelBlockPos, nBytesToRead); + // Now we read to the sector boundary we need to invalidate the buffer! - //---------- Read (memcpy) to a Sector Boundary - if(nRelBlockPos != 0) { // Not on a sector boundary, at this point the LBA is known. - 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); + // HT: Sure about this check for FF_BUFSTATE_WRITTEN? + // I thought file access is either Rd or Wr-only? + if(pFile->ucState & FF_BUFSTATE_WRITTEN) { + Error = FF_BlockWrite(pIoman, nItemLBA, 1, pFile->pBuf, FF_FALSE); + if(FF_isERR(Error)) return Error; + } + pFile->ucState = FF_BUFSTATE_INVALID; + +#else + pBuffer = FF_GetBuffer(pIoman, nItemLBA, FF_MODE_READ); + { + if(!pBuffer) { + return (FF_ERR_DEVICE_DRIVER_FAILED | FF_READ); } - FF_ReleaseBuffer(pIoman, pBuffer); + // Here we copy to the sector boudary. + memcpy(buffer, (pBuffer->pBuffer + nRelBlockPos), nBytesToRead); + } + Error = FF_ReleaseBuffer(pIoman, pBuffer); + if(FF_isERR(Error)) { + return Error; + } +#endif + nBytes -= nBytesToRead; + nBytesRead += nBytesToRead; + pFile->FilePointer += nBytesToRead; + buffer += nBytesToRead; + + } - nBytes -= nBytesToRead; - nBytesRead += nBytesToRead; - pFile->FilePointer += nBytesToRead; - buffer += nBytesToRead; - + //---------- Read to a Cluster Boundary + + nRelClusterPos = FF_getClusterPosition(pIoman, pFile->FilePointer, 1); + nBytesPerCluster = (pIoman->pPartition->SectorsPerCluster * pIoman->BlkSize); + if(nRelClusterPos != 0 && nRelClusterPos + nBytes >= nBytesPerCluster) { // Need to get to cluster boundary + nItemLBA = FF_SetCluster (pFile, &Error); + if(FF_isERR(Error)) { + return Error; } - - //---------- Read to a Cluster Boundary + + sSectors = (FF_T_UINT16) (pIoman->pPartition->SectorsPerCluster - (nRelClusterPos / pIoman->BlkSize)); - nRelClusterPos = FF_getClusterPosition(pIoman, pFile->FilePointer, 1); - nBytesPerCluster = (pIoman->pPartition->SectorsPerCluster * pIoman->BlkSize); - if(nRelClusterPos != 0 && nBytes >= nBytesPerCluster) { // Need to get to cluster boundary - - 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, &Error); - if(Error) { - return Error; - } - pFile->CurrentCluster += nClusterDiff; - } - } + RetVal = FF_BlockRead(pIoman, nItemLBA, (FF_T_UINT32) sSectors, buffer, FF_FALSE); + if(RetVal < 0) { + return RetVal; + } - nItemLBA = FF_Cluster2LBA(pIoman, pFile->AddrCurrentCluster); - nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1); + nBytesToRead = sSectors * pIoman->BlkSize; + nBytes -= nBytesToRead; + buffer += nBytesToRead; + nBytesRead += nBytesToRead; + pFile->FilePointer += nBytesToRead; - sSectors = (FF_T_UINT16) (pIoman->pPartition->SectorsPerCluster - (nRelClusterPos / pIoman->BlkSize)); - - RetVal = FF_BlockRead(pIoman, nItemLBA, (FF_T_UINT32) sSectors, buffer); - - nBytesToRead = sSectors * pIoman->BlkSize; - nBytes -= nBytesToRead; - buffer += nBytesToRead; - nBytesRead += nBytesToRead; - pFile->FilePointer += nBytesToRead; + } + //---------- Read Clusters + if(nBytes >= nBytesPerCluster) { + //----- Thanks to Christopher Clark of DigiPen Institute of Technology in Redmond, US adding this traversal check. + FF_SetCluster (pFile, &Error); + if(FF_isERR(Error)) { + return Error; } + //----- End of Contributor fix. - //---------- Read Clusters - if(nBytes >= nBytesPerCluster) { - //----- Thanks to Christopher Clark of DigiPen Institute of Technology in Redmond, US adding this traversal check. - 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, &Error); - if(Error) { - return Error; - } - pFile->CurrentCluster += nClusterDiff; - } - } - //----- End of Contributor fix. + RetVal = FF_ReadClusters(pFile, (nBytes / nBytesPerCluster), buffer); + if(RetVal < 0) { + return RetVal; + } + nBytesToRead = (nBytesPerCluster * (nBytes / nBytesPerCluster)); - RetVal = FF_ReadClusters(pFile, (nBytes / nBytesPerCluster), buffer); - if(RetVal < 0) { - return RetVal; - } - nBytesToRead = (nBytesPerCluster * (nBytes / nBytesPerCluster)); + pFile->FilePointer += nBytesToRead; - pFile->FilePointer += nBytesToRead; + nBytes -= nBytesToRead; + buffer += nBytesToRead; + nBytesRead += nBytesToRead; + } - nBytes -= nBytesToRead; - buffer += nBytesToRead; - nBytesRead += nBytesToRead; + //---------- Read Remaining Blocks + while (nBytes >= pIoman->BlkSize) { + sSectors = (FF_T_UINT16) (nBytes / pIoman->BlkSize); + { + // HT: I'd leave these pPart/ucOffset for readability + // and shorter code lines + FF_PARTITION *pPart = pIoman->pPartition; + FF_T_UINT ucOffset = (pFile->FilePointer / pIoman->BlkSize) % pPart->SectorsPerCluster; + FF_T_UINT ucRemain = pPart->SectorsPerCluster - ucOffset; + if (sSectors > ucRemain) { + sSectors = ucRemain; + } } + + nItemLBA = FF_SetCluster (pFile, &Error); + if(FF_isERR(Error)) { + return Error; + } + + RetVal = FF_BlockRead(pIoman, nItemLBA, (FF_T_UINT32) sSectors, buffer, FF_FALSE); - //---------- Read Remaining Blocks - if(nBytes >= pIoman->BlkSize) { - sSectors = (FF_T_UINT16) (nBytes / pIoman->BlkSize); - - 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, &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); + if(FF_isERR(Error)) { + return RetVal; + } + + nBytesToRead = sSectors * pIoman->BlkSize; + pFile->FilePointer += nBytesToRead; + nBytes -= nBytesToRead; + buffer += nBytesToRead; + nBytesRead += nBytesToRead; + } - RetVal = FF_BlockRead(pIoman, nItemLBA, (FF_T_UINT32) sSectors, buffer); + //---------- Read (memcpy) Remaining Bytes + if(nBytes > 0) { + + nItemLBA = FF_SetCluster (pFile, &Error); + if(FF_isERR(Error)) { + return Error; + } + +#ifdef FF_OPTIMISE_UNALIGNED_ACCESS + if(!(pFile->ucState & FF_BUFSTATE_VALID)) { + Error = FF_BlockRead(pIoman, nItemLBA, 1, pFile->pBuf, FF_FALSE); + if(FF_isERR(Error)) return Error; + pFile->ucState = FF_BUFSTATE_VALID; + } + memcpy(buffer, pFile->pBuf, nBytes); - if(RetVal < 0) { - return RetVal; +#else + pBuffer = FF_GetBuffer(pIoman, nItemLBA, FF_MODE_READ); + { + if(!pBuffer) { + return (FF_ERR_DEVICE_DRIVER_FAILED | FF_READ); } - - nBytesToRead = sSectors * pIoman->BlkSize; - pFile->FilePointer += nBytesToRead; - nBytes -= nBytesToRead; - buffer += nBytesToRead; - nBytesRead += nBytesToRead; + memcpy(buffer, pBuffer->pBuffer, nBytes); } + Error = FF_ReleaseBuffer(pIoman, pBuffer); + if(FF_isERR(Error)) { + return Error; + } +#endif + nBytesToRead = nBytes; + pFile->FilePointer += nBytesToRead; + nBytes -= nBytesToRead; + buffer += nBytesToRead; + nBytesRead += nBytesToRead; - //---------- Read (memcpy) Remaining Bytes - if(nBytes > 0) { - - 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, &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); - 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); - - nBytesToRead = nBytes; - pFile->FilePointer += nBytesToRead; - nBytes -= nBytesToRead; - buffer += nBytesToRead; - nBytesRead += nBytesToRead; - - } } return nBytesRead; @@ -1211,26 +1362,26 @@ * @param pFile FF_FILE object that was created by FF_Open(). * * @return The character that was read (cast as a 32-bit interger). -1 on EOF. - * @return -2 If a null file pointer was provided. - * @return -3 Device access failed. + * @return FF_ERROR code. (Check with if(FF_isERR(RetVal)) {}). + * @return -1 EOF (end of file). * **/ FF_T_SINT32 FF_GetC(FF_FILE *pFile) { FF_T_UINT32 fileLBA; +#ifndef FF_OPTIMISE_UNALIGNED_ACCESS FF_BUFFER *pBuffer; +#endif FF_T_UINT8 retChar; FF_T_UINT32 relMinorBlockPos; - FF_T_UINT32 clusterNum; - FF_T_UINT32 nClusterDiff; - FF_ERROR Error; + FF_ERROR Error; if(!pFile) { - return FF_ERR_NULL_POINTER; + return (FF_ERR_NULL_POINTER | FF_GETC); // Ensure this is a signed error. } if(!(pFile->Mode & FF_MODE_READ)) { - return FF_ERR_FILE_NOT_OPENED_IN_READ_MODE; + return (FF_ERR_FILE_NOT_OPENED_IN_READ_MODE | FF_GETC); } if(pFile->FilePointer >= pFile->Filesize) { @@ -1238,35 +1389,43 @@ } relMinorBlockPos = FF_getMinorBlockEntry(pFile->pIoman, pFile->FilePointer, 1); - clusterNum = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1); - 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, &Error); - if(Error) { - return Error; - } - pFile->CurrentCluster += nClusterDiff; - } + fileLBA = FF_SetCluster (pFile, &Error); + if(FF_isERR(Error)) { + return Error; } - - fileLBA = FF_Cluster2LBA(pFile->pIoman, pFile->AddrCurrentCluster) + FF_getMajorBlockNumber(pFile->pIoman, pFile->FilePointer, (FF_T_UINT16) 1); - fileLBA = FF_getRealLBA (pFile->pIoman, fileLBA) + FF_getMinorBlockNumber(pFile->pIoman, pFile->FilePointer, (FF_T_UINT16) 1); - +#ifdef FF_OPTIMISE_UNALIGNED_ACCESS + if(!(pFile->ucState & FF_BUFSTATE_VALID)) { + Error = FF_BlockRead(pFile->pIoman, fileLBA, 1, pFile->pBuf, FF_FALSE); + if(FF_isERR(Error)) return Error; + pFile->ucState |= FF_BUFSTATE_VALID; + } + retChar = pFile->pBuf[relMinorBlockPos]; +#else pBuffer = FF_GetBuffer(pFile->pIoman, fileLBA, FF_MODE_READ); { if(!pBuffer) { - return FF_ERR_DEVICE_DRIVER_FAILED; + return (FF_ERR_DEVICE_DRIVER_FAILED | FF_GETC); } retChar = pBuffer->pBuffer[relMinorBlockPos]; } FF_ReleaseBuffer(pFile->pIoman, pBuffer); - +#endif pFile->FilePointer += 1; - return (FF_T_INT32) retChar; +#ifdef FF_OPTIMISE_UNALIGNED_ACCESS + relMinorBlockPos = FF_getMinorBlockEntry(pFile->pIoman, pFile->FilePointer, 1); + if(!relMinorBlockPos) { + if(pFile->ucState & FF_BUFSTATE_WRITTEN) { + Error = FF_BlockWrite(pFile->pIoman, fileLBA, 1, pFile->pBuf, FF_FALSE); + if(FF_isERR(Error)) return Error; + } + pFile->ucState = FF_BUFSTATE_INVALID; + } +#endif + + return (FF_T_SINT32) retChar; } @@ -1289,11 +1448,11 @@ * **/ FF_T_SINT32 FF_GetLine(FF_FILE *pFile, FF_T_INT8 *szLine, FF_T_UINT32 ulLimit) { - FF_T_SINT32 c; + FF_T_SINT32 c = 0; FF_T_UINT32 i; if(!pFile || !szLine) { - return FF_ERR_NULL_POINTER; + return (FF_ERR_NULL_POINTER | FF_GETLINE); } for(i = 0; i < (ulLimit - 1) && (c=FF_GetC(pFile)) >= 0 && c != '\n'; ++i) { @@ -1304,15 +1463,26 @@ } } - szLine[i] = '\0'; + szLine[i] = '\0'; // Always do this before sending the err, we don't know what the user will + // do with this buffer if they don't see the error. + + if(FF_isERR(c)) { + return c; // Return 'c' as an error code. + } + return i; } -FF_T_UINT32 FF_Tell(FF_FILE *pFile) { - return pFile->FilePointer; -} +// HT made inline +/*FF_T_UINT32 FF_Tell(FF_FILE *pFile) { + if(pFile) { + return pFile->FilePointer; + } + return 0; +}*/ + /** * @public * @brief Writes data to a File. @@ -1329,27 +1499,36 @@ FF_T_UINT32 nBytesWritten = 0; FF_T_UINT32 nBytesToWrite; FF_IOMAN *pIoman; +#ifndef FF_OPTIMISE_UNALIGNED_ACCESS FF_BUFFER *pBuffer; +#endif FF_T_UINT32 nRelBlockPos; FF_T_UINT32 nItemLBA; FF_T_SINT32 slRetVal = 0; FF_T_UINT16 sSectors; FF_T_UINT32 nRelClusterPos; - FF_T_UINT32 nBytesPerCluster, nClusterDiff, nClusters; + FF_T_UINT32 nBytesPerCluster, nClusters; FF_ERROR Error; if(!pFile) { - return FF_ERR_NULL_POINTER; + return (FF_ERR_NULL_POINTER | FF_WRITE); } + Error = FF_CheckValid (pFile); + if (Error) + return Error; + if(!(pFile->Mode & FF_MODE_WRITE)) { - return FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE; + return (FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE | FF_WRITE); } // Make sure a write is after the append point. if((pFile->Mode & FF_MODE_APPEND)) { if(pFile->FilePointer < pFile->Filesize) { - FF_Seek(pFile, 0, FF_SEEK_END); + Error = FF_Seek(pFile, 0, FF_SEEK_END); + if(FF_isERR(Error)) { + return Error; + } } } @@ -1359,190 +1538,229 @@ // Extend File for atleast nBytes! // Handle file-space allocation - Error = FF_ExtendFile(pFile, pFile->FilePointer + nBytes); - if(Error) { + // HT: + 1 byte because the code assumes there is always a next cluster + Error = FF_ExtendFile(pFile, pFile->FilePointer + nBytes + 1); + if(FF_isERR(Error)) { return Error; } nRelBlockPos = FF_getMinorBlockEntry(pIoman, pFile->FilePointer, 1); // Get the position within a block. - 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, &Error); - if(Error) { - return Error; - } - pFile->CurrentCluster += nClusterDiff; - } + nItemLBA = FF_SetCluster (pFile, &Error); + if(FF_isERR(Error)) { + return Error; } - nItemLBA = FF_Cluster2LBA(pIoman, pFile->AddrCurrentCluster); - nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1); - - 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((nRelBlockPos + nBytes) < pIoman->BlkSize) { // Bytes to write are within a block and less than a block size. +#ifdef FF_OPTIMISE_UNALIGNED_ACCESS + /** + * In this case we are within a block, and the write finishes within the block. + * We only need to read in the case that the buffer is invalid, and we are starting somewhere within the middle + * of a block. + * + * Also the case that the file pointer is less than the filesize, we must ensure that we read the block + * otherwise we might overwrite valid data. + * + * We always leave here with a written valid sector, where the file pointer is within a block. + **/ + // HT: Only read if we access existing data + if(!(pFile->ucState & FF_BUFSTATE_VALID) && (nRelBlockPos || pFile->FilePointer < pFile->Filesize)) { + Error = FF_BlockRead(pIoman, nItemLBA, 1, pFile->pBuf, FF_FALSE); + if(FF_isERR(Error)) return Error; + } + memcpy(pFile->pBuf + nRelBlockPos, buffer, nBytes); + pFile->ucState |= FF_BUFSTATE_WRITTEN | FF_BUFSTATE_VALID; +#else + if (!nRelBlockPos && pFile->FilePointer >= pFile->Filesize) { + pBuffer = FF_GetBuffer(pIoman, nItemLBA, FF_MODE_WR_ONLY); + } else { + pBuffer = FF_GetBuffer(pIoman, nItemLBA, FF_MODE_WRITE); + } { if(!pBuffer) { - return FF_ERR_DEVICE_DRIVER_FAILED; + return (FF_ERR_DEVICE_DRIVER_FAILED | FF_WRITE); } memcpy((pBuffer->pBuffer + nRelBlockPos), buffer, nBytes); } - FF_ReleaseBuffer(pIoman, pBuffer); - + Error = FF_ReleaseBuffer(pIoman, pBuffer); + if(FF_isERR(Error)) { + return Error; + } +#endif pFile->FilePointer += nBytes; nBytesWritten = nBytes; - //return nBytes; // Return the number of bytes read. + // HT: restored return here to de-indent the remaining part of this function + if(pFile->FilePointer > pFile->Filesize) { + pFile->Filesize = pFile->FilePointer; + } + return nBytes; // Return the number of bytes written. + } - } else { - - //---------- Write (memcpy) to a Sector Boundary - if(nRelBlockPos != 0) { // Not on a sector boundary, at this point the LBA is known. - 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); + //---------- Write (memcpy) to a Sector Boundary + if(nRelBlockPos != 0) { // Not on a sector boundary, at this point the LBA is known. + nBytesToWrite = pIoman->BlkSize - nRelBlockPos; +#ifdef FF_OPTIMISE_UNALIGNED_ACCESS + /** + * Here we must only check that the buffer is valid. If not we must read in the block. + * If the buffer is valid (From the previous case), we will then write up to the end + * of the block, write the buffer to disk and invalidate the buffer. + **/ + // HT: Only read if we access existing data + if(!(pFile->ucState & FF_BUFSTATE_VALID)) { + Error = FF_BlockRead(pIoman, nItemLBA, 1, pFile->pBuf, FF_FALSE); + if(FF_isERR(Error)) return Error; + } + memcpy(pFile->pBuf+nRelBlockPos, buffer, nBytesToWrite); + Error = FF_BlockWrite(pIoman, nItemLBA, 1, pFile->pBuf, FF_FALSE); + pFile->ucState = FF_BUFSTATE_INVALID; + if(FF_isERR(Error)) return Error; +#else + pBuffer = FF_GetBuffer(pIoman, nItemLBA, FF_MODE_WRITE); + { + if(!pBuffer) { + return (FF_ERR_DEVICE_DRIVER_FAILED | FF_WRITE); } - FF_ReleaseBuffer(pIoman, pBuffer); + // Here we copy to the sector boudary. + memcpy((pBuffer->pBuffer + nRelBlockPos), buffer, nBytesToWrite); + } + Error = FF_ReleaseBuffer(pIoman, pBuffer); + if(FF_isERR(Error)) { + return Error; + } +#endif + nBytes -= nBytesToWrite; + nBytesWritten += nBytesToWrite; + pFile->FilePointer += nBytesToWrite; + buffer += nBytesToWrite; + } - nBytes -= nBytesToWrite; - nBytesWritten += nBytesToWrite; - pFile->FilePointer += nBytesToWrite; - buffer += nBytesToWrite; + //---------- Write to a Cluster Boundary + nRelClusterPos = FF_getClusterPosition(pIoman, pFile->FilePointer, 1); + if(nRelClusterPos != 0 && nRelClusterPos + nBytes >= nBytesPerCluster) { // Need to get to cluster boundary + + nItemLBA = FF_SetCluster (pFile, &Error); + if(FF_isERR(Error)) { + return Error; } + + sSectors = (FF_T_UINT16) (pIoman->pPartition->SectorsPerCluster - (nRelClusterPos / pIoman->BlkSize)); - //---------- Write to a Cluster Boundary + slRetVal = FF_BlockWrite(pFile->pIoman, nItemLBA, sSectors, buffer, FF_FALSE); + if(slRetVal < 0) { + return slRetVal; + } - nRelClusterPos = FF_getClusterPosition(pIoman, pFile->FilePointer, 1); - if(nRelClusterPos != 0 && nBytes >= nBytesPerCluster) { // Need to get to cluster boundary - - 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, &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); + nBytesToWrite = sSectors * pIoman->BlkSize; + nBytes -= nBytesToWrite; + buffer += nBytesToWrite; + nBytesWritten += nBytesToWrite; + pFile->FilePointer += nBytesToWrite; - sSectors = (FF_T_UINT16) (pIoman->pPartition->SectorsPerCluster - (nRelClusterPos / pIoman->BlkSize)); + } - slRetVal = FF_BlockWrite(pFile->pIoman, nItemLBA, sSectors, buffer); - if(slRetVal < 0) { - return slRetVal; - } - - nBytesToWrite = sSectors * pIoman->BlkSize; - nBytes -= nBytesToWrite; - buffer += nBytesToWrite; - nBytesWritten += nBytesToWrite; - pFile->FilePointer += nBytesToWrite; + //---------- Write Clusters + if(nBytes >= nBytesPerCluster) { + //----- Thanks to Christopher Clark of DigiPen Institute of Technology in Redmond, US adding this traversal check. + FF_SetCluster (pFile, &Error); + if(FF_isERR(Error)) { + return Error; + } + //----- End of Contributor fix. + nClusters = (nBytes / nBytesPerCluster); + + slRetVal = FF_WriteClusters(pFile, nClusters, buffer); + if(slRetVal < 0) { + return slRetVal; } - //---------- Write Clusters - if(nBytes >= nBytesPerCluster) { - //----- Thanks to Christopher Clark of DigiPen Institute of Technology in Redmond, US adding this traversal check. - 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, &Error); - if(Error) { - return Error; - } - pFile->CurrentCluster += nClusterDiff; - } - } - //----- End of Contributor fix. + nBytesToWrite = (nBytesPerCluster * nClusters); + + pFile->FilePointer += nBytesToWrite; - nClusters = (nBytes / nBytesPerCluster); - - slRetVal = FF_WriteClusters(pFile, nClusters, buffer); - if(slRetVal < 0) { - return slRetVal; + nBytes -= nBytesToWrite; + buffer += nBytesToWrite; + nBytesWritten += nBytesToWrite; + } + + //---------- Write Remaining Blocks + while (nBytes >= pIoman->BlkSize) { + sSectors = (FF_T_UINT16) (nBytes / pIoman->BlkSize); + { + // HT: I'd leave these pPart/ucOffset for readability... + FF_PARTITION *pPart = pIoman->pPartition; + FF_T_UINT8 ucOffset = (pFile->FilePointer / pIoman->BlkSize) % pPart->SectorsPerCluster; + FF_T_UINT ucRemain = pPart->SectorsPerCluster - ucOffset; + if (sSectors > ucRemain) { +// logPrintf ("FF_Write: fp = %lu ofs %u sSectors %u remain %u (correcting)\n", +// pFile->FilePointer, offset, sSectors, remain); + sSectors = ucRemain; } - - nBytesToWrite = (nBytesPerCluster * nClusters); - - pFile->FilePointer += nBytesToWrite; + } - nBytes -= nBytesToWrite; - buffer += nBytesToWrite; - nBytesWritten += nBytesToWrite; + nItemLBA = FF_SetCluster (pFile, &Error); + if(FF_isERR(Error)) { + return Error; } - //---------- Write Remaining Blocks - if(nBytes >= pIoman->BlkSize) { - sSectors = (FF_T_UINT16) (nBytes / pIoman->BlkSize); - - 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, &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); - - 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; + slRetVal = FF_BlockWrite(pFile->pIoman, nItemLBA, sSectors, buffer, FF_FALSE); + if(slRetVal < 0) { + return slRetVal; } + + nBytesToWrite = sSectors * pIoman->BlkSize; + pFile->FilePointer += nBytesToWrite; + nBytes -= nBytesToWrite; + buffer += nBytesToWrite; + nBytesWritten += nBytesToWrite; + } - //---------- Write (memcpy) Remaining Bytes - if(nBytes > 0) { - - 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, &Error); - if(Error) { - return Error; - } - pFile->CurrentCluster += nClusterDiff; - } + //---------- Write (memcpy) Remaining Bytes + if(nBytes > 0) { + + nItemLBA = FF_SetCluster (pFile, &Error); + if(FF_isERR(Error)) { + return Error; + } + +#ifdef FF_OPTIMISE_UNALIGNED_ACCESS + /** + * Here we only read in the block, is the buffer is invalid AND the file-pointer is < filesize. + * This is safe because we are already on a sector boundary, so if we the end of the file, there + * is no data to load into the buffer. + * + * In all other cases, we might be on a sector boundary but inside a file, in which case data already exists. + * Or the buffer is valid, and so the buffer contains the data for this sector. + * + * It is almost certain that the buffer is invalid here. + **/ + if(!(pFile->ucState & FF_BUFSTATE_VALID) && pFile->FilePointer < pFile->Filesize) { + Error = FF_BlockRead(pIoman, nItemLBA, 1, pFile->pBuf, FF_FALSE); + if(FF_isERR(Error)) return Error; + } + memcpy(pFile->pBuf, buffer, nBytes); + pFile->ucState = FF_BUFSTATE_WRITTEN | FF_BUFSTATE_VALID; +#else + pBuffer = FF_GetBuffer(pIoman, nItemLBA, FF_MODE_WRITE); + { + if(!pBuffer) { + return (FF_ERR_DEVICE_DRIVER_FAILED | FF_WRITE); } - - nItemLBA = FF_Cluster2LBA(pIoman, pFile->AddrCurrentCluster); - 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); + memcpy(pBuffer->pBuffer, buffer, nBytes); + } + Error = FF_ReleaseBuffer(pIoman, pBuffer); + if(FF_isERR(Error)) { + return Error; + } +#endif - nBytesToWrite = nBytes; - pFile->FilePointer += nBytesToWrite; - nBytes -= nBytesToWrite; - buffer += nBytesToWrite; - nBytesWritten += nBytesToWrite; + nBytesToWrite = nBytes; + pFile->FilePointer += nBytesToWrite; + nBytes -= nBytesToWrite; + buffer += nBytesToWrite; + nBytesWritten += nBytesToWrite; - } } if(pFile->FilePointer > pFile->Filesize) { @@ -1564,62 +1782,80 @@ * **/ FF_T_SINT32 FF_PutC(FF_FILE *pFile, FF_T_UINT8 pa_cValue) { +#ifndef FF_OPTIMISE_UNALIGNED_ACCESS FF_BUFFER *pBuffer; +#endif 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; + return (FF_ERR_NULL_POINTER | FF_PUTC); } if(!(pFile->Mode & FF_MODE_WRITE)) { - return FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE; + return (FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE | FF_PUTC); } // Make sure a write is after the append point. if((pFile->Mode & FF_MODE_APPEND)) { if(pFile->FilePointer < pFile->Filesize) { - FF_Seek(pFile, 0, FF_SEEK_END); + Error = FF_Seek(pFile, 0, FF_SEEK_END); + if(FF_isERR(Error)) { + return Error; + } } } iRelPos = FF_getMinorBlockEntry(pFile->pIoman, pFile->FilePointer, 1); // Handle File Space Allocation. - Error = FF_ExtendFile(pFile, pFile->FilePointer + 1); - if(Error) { + // We'll write 1 byte and always have a next cluster reserved. + Error = FF_ExtendFile(pFile, pFile->FilePointer + 2); + if(FF_isERR(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, &Error); - if(Error) { - return Error; - } - pFile->CurrentCluster += nClusterDiff; - } + iItemLBA = FF_SetCluster (pFile, &Error); + if(FF_isERR(Error)) { + return Error; } - 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); - +#ifdef FF_OPTIMISE_UNALIGNED_ACCESS + //if(!(pFile->ucState & FF_BUFSTATE_VALID) && (iRelPos || pFile->FilePointer < pFile->Filesize) { + if(!(pFile->ucState & FF_BUFSTATE_VALID) && iRelPos) { + Error = FF_BlockRead(pFile->pIoman, iItemLBA, 1, pFile->pBuf, FF_FALSE); + if(FF_isERR(Error)) return Error; + } + + pFile->pBuf[iRelPos] = pa_cValue; + pFile->ucState |= FF_BUFSTATE_WRITTEN | FF_BUFSTATE_VALID; +#else pBuffer = FF_GetBuffer(pFile->pIoman, iItemLBA, FF_MODE_WRITE); { if(!pBuffer) { - return FF_ERR_DEVICE_DRIVER_FAILED; + return (FF_ERR_DEVICE_DRIVER_FAILED | FF_PUTC); } FF_putChar(pBuffer->pBuffer, (FF_T_UINT16) iRelPos, pa_cValue); } FF_ReleaseBuffer(pFile->pIoman, pBuffer); +#endif pFile->FilePointer += 1; if(pFile->Filesize < (pFile->FilePointer)) { pFile->Filesize += 1; } + +#ifdef FF_OPTIMISE_UNALIGNED_ACCESS + if(pFile->ucState & FF_BUFSTATE_WRITTEN) { + iRelPos = FF_getMinorBlockEntry(pFile->pIoman, pFile->FilePointer, 1); + if(!iRelPos) { + Error = FF_BlockWrite(pFile->pIoman, iItemLBA, 1, pFile->pBuf, FF_FALSE); + if(FF_isERR(Error)) return Error; + pFile->ucState = FF_BUFSTATE_INVALID; + } + } +#endif return pa_cValue; } @@ -1644,21 +1880,33 @@ FF_ERROR Error; if(!pFile) { - return FF_ERR_NULL_POINTER; + return (FF_ERR_NULL_POINTER | FF_SEEK); } Error = FF_FlushCache(pFile->pIoman); - if(Error) { + if(FF_isERR(Error)) { return Error; } +#ifdef FF_OPTIMISE_UNALIGNED_ACCESS + /* + Here we must ensure that if the user tries to seek, and we had data in the file's + write buffer that this is written to disk. + */ + + if(pFile->ucState & FF_BUFSTATE_WRITTEN) { + Error = FF_BlockWrite(pFile->pIoman, FF_FileLBA(pFile), 1, pFile->pBuf, FF_FALSE); + if(FF_isERR(Error)) return Error; + } + pFile->ucState = FF_BUFSTATE_INVALID; +#endif + 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, &Error); - if(Error) { + FF_SetCluster (pFile, &Error); + if(FF_isERR(Error)) { return Error; } } else { @@ -1669,9 +1917,8 @@ case FF_SEEK_CUR: 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, &Error); - if(Error) { + FF_SetCluster (pFile, &Error); + if(FF_isERR(Error)) { return Error; } } else { @@ -1682,9 +1929,8 @@ case FF_SEEK_END: 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, &Error); - if(Error) { + FF_SetCluster (pFile, &Error); + if(FF_isERR(Error)) { return Error; } } else { @@ -1700,9 +1946,202 @@ return 0; } +#ifdef FF_REMOVABLE_MEDIA +/** + * @public + * @brief Invalidate all file handles belonging to pIoman + * + * @param pIoMan FF_IOMAN object that was created by FF_CreateIOMAN(). + * + * @return 0 if no handles were open + * @return >0 the amount of handles that were invalidated + * @return <0 probably an invalid FF_IOMAN pointer + * + **/ +FF_T_SINT32 FF_Invalidate (FF_IOMAN *pIoman) ///< Invalidate all handles belonging to pIoman +{ + FF_T_SINT32 Result; + FF_FILE *pFileChain; + if (!pIoman) { + return (FF_ERR_NULL_POINTER | FF_INVALIDATE); + } + Result = 0; + FF_PendSemaphore(pIoman->pSemaphore); + { // Semaphore is required, or linked list might change + pFileChain = (FF_FILE *) pIoman->FirstFile; + if (pFileChain) { + // Count elements in FirstFile + do { + pFileChain->ValidFlags |= FF_VALID_FLAG_INVALID; + Result++; + pFileChain = pFileChain->Next; + } while (pFileChain); + } + } + FF_ReleaseSemaphore(pIoman->pSemaphore); + return Result; +} +#endif // FF_REMOVABLE_MEDIA + /** * @public + * @brief Check validity of file handle + * + * @param pFile FF_FILE object that was created by FF_Open(). + * + * @return 0 on sucess. + * @return FF_ERR_NULL_POINTER if a null pointer was provided. + * @return FF_ERR_FILE_BAD_HANDLE if handle is not recognized + * @return FF_ERR_FILE_MEDIA_REMOVED please call FF_Close + * + **/ +FF_ERROR FF_CheckValid (FF_FILE *pFile) +{ + FF_FILE *pFileChain; + + if (!pFile || !pFile->pIoman) { + return (FF_ERR_NULL_POINTER | FF_CHECKVALID); + } + + pFileChain = (FF_FILE *)pFile->pIoman->FirstFile; + while (pFileChain) { + if (pFileChain == pFile) { +#ifdef FF_REMOVABLE_MEDIA + if (pFileChain->ValidFlags & FF_VALID_FLAG_INVALID) { + return (FF_ERR_FILE_MEDIA_REMOVED | FF_CHECKVALID); + } +#endif + return FF_ERR_NONE; + } + pFileChain = pFileChain->Next; + } + return (FF_ERR_FILE_BAD_HANDLE | FF_CHECKVALID); +} + +#ifdef FF_TIME_SUPPORT +/** + * @public + * @brief Set the time-stamp(s) of a file entry + * + * @param pFile FF_FILE object that was created by FF_Open(). + * @param pTime FF_SYSTEMTIME the time stamp + * @param aWhat FF_T_UINT a combination of enum ETimeMask + * + * @return 0 or FF_ERROR + * + **/ +FF_ERROR FF_SetFileTime(FF_FILE *pFile, FF_SYSTEMTIME *pTime, FF_T_UINT aWhat) { + FF_DIRENT OriginalEntry; + FF_ERROR Error; + Error = FF_CheckValid (pFile); + if (Error) + return Error; + + if (pFile->ValidFlags & FF_VALID_FLAG_DELETED) { //if (pFile->FileDeleted) + return FF_ERR_FILE_NOT_FOUND | FF_SETFILETIME; + } + if (!(pFile->Mode & (FF_MODE_WRITE |FF_MODE_APPEND))) { + return FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE | FF_SETFILETIME; + } + // Update the Dirent! + Error = FF_GetEntry(pFile->pIoman, pFile->DirEntry, pFile->DirCluster, &OriginalEntry); + if (!FF_isERR(Error)) { + if (aWhat & ETimeCreate) OriginalEntry.CreateTime = *pTime; ///< Date and Time Created. + if (aWhat & ETimeMod) OriginalEntry.ModifiedTime = *pTime; ///< Date and Time Modified. + if (aWhat & ETimeAccess) OriginalEntry.AccessedTime = *pTime; ///< Date of Last Access. + Error = FF_PutEntry(pFile->pIoman, pFile->DirEntry, pFile->DirCluster, &OriginalEntry); + } + if (!FF_isERR(Error)) { + Error = FF_FlushCache(pFile->pIoman); // Ensure all modfied blocks are flushed to disk! + } + return Error; +} + +/** + * @public + * @brief Set the time-stamp(s) of a file entry (by name) + * + * @param pIoman FF_IOMAN device handle + * @param path FF_T_INT8/FF_T_WCHAR name of the file + * @param pTime FF_SYSTEMTIME the time stamp + * @param aWhat FF_T_UINT a combination of enum ETimeMask + * + * @return 0 or FF_ERROR + * + **/ +#ifdef FF_UNICODE_SUPPORT +FF_ERROR FF_SetTime(FF_IOMAN *pIoman, const FF_T_WCHAR *path, FF_SYSTEMTIME *pTime, FF_T_UINT aWhat) +#else +FF_ERROR FF_SetTime(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_SYSTEMTIME *pTime, FF_T_UINT aWhat) +#endif +{ + FF_DIRENT OriginalEntry; + FF_ERROR Error; + FF_T_UINT32 DirCluster; + FF_T_UINT32 FileCluster; + FF_T_UINT i; +#ifdef FF_UNICODE_SUPPORT + FF_T_WCHAR filename[FF_MAX_FILENAME]; +#else + FF_T_INT8 filename[FF_MAX_FILENAME]; +#endif + +#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] == '/') { + break; + } + 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, (FF_T_UINT16) i, &Error); + if (Error) + return Error; + + if (!DirCluster) { + return FF_ERR_FILE_NOT_FOUND | FF_SETTIME; + } + FileCluster = FF_FindEntryInDir(pIoman, DirCluster, filename, 0, &OriginalEntry, &Error); + if (Error) { + return Error; + } + + if (!FileCluster) { + //logPrintf ("FF_SetTime: Can not find '%s'\n", filename); + return FF_ERR_FILE_NOT_FOUND | FF_SETTIME; + } + + // Update the Dirent! + if (aWhat & ETimeCreate) OriginalEntry.CreateTime = *pTime; ///< Date and Time Created. + if (aWhat & ETimeMod) OriginalEntry.ModifiedTime = *pTime; ///< Date and Time Modified. + if (aWhat & ETimeAccess) OriginalEntry.AccessedTime = *pTime; ///< Date of Last Access. + Error = FF_PutEntry(pIoman, OriginalEntry.CurrentItem-1, DirCluster, &OriginalEntry); + + if (!FF_isERR(Error)) { + Error = FF_FlushCache(pIoman); // Ensure all modfied blocks are flushed to disk! + } + return Error; +} + +#endif // FF_TIME_SUPPORT + +/** + * @public * @brief Equivalent to fclose() * * @param pFile FF_FILE object that was created by FF_Open(). @@ -1718,50 +2157,145 @@ FF_ERROR Error; if(!pFile) { - return FF_ERR_NULL_POINTER; + return (FF_ERR_NULL_POINTER | FF_CLOSE); } - // UpDate Dirent if File-size has changed? - // Update the Dirent! - Error = FF_GetEntry(pFile->pIoman, pFile->DirEntry, pFile->DirCluster, &OriginalEntry); - if(Error) { - return Error; + /* + * HT thinks: + * It is important to check that: + * user doesn't supply invalid handle + * or a handle invalid because of "media removed" + */ + Error = FF_CheckValid (pFile); +#ifdef FF_REMOVABLE_MEDIA + if (FF_GETERROR(Error) == FF_ERR_FILE_MEDIA_REMOVED) { + FF_PendSemaphore(pFile->pIoman->pSemaphore); + { + pFileChain = (FF_FILE *) pFile->pIoman->FirstFile; + if(pFileChain == pFile) { + pFile->pIoman->FirstFile = pFile->Next; + } else { + while (pFileChain) { + if (pFileChain->Next == pFile) { + pFileChain->Next = pFile->Next; + break; + } + pFileChain = pFileChain->Next; // Forgot this one + } + } + } // Semaphore released, linked list was shortened! + FF_ReleaseSemaphore(pFile->pIoman->pSemaphore); +#ifdef FF_OPTIMISE_UNALIGNED_ACCESS + FF_FREE(pFile->pBuf); +#endif + FF_FREE(pFile); // So at least we have freed the pointer. + return FF_ERR_NONE; } +#endif + if (Error != FF_ERR_NONE) { + return Error; // FF_ERR_FILE_BAD_HANDLE or FF_ERR_NULL_POINTER + } + + /* + * So here we have a normal valid file handle + */ + + /* + * Sometimes FullFAT will leave a trailing cluster on the end of a cluster chain. + * To ensure we're compliant we shall now check for this condition and truncate it. + */ + - if(!pFile->FileDeleted) { - if(pFile->Filesize != OriginalEntry.Filesize) { - OriginalEntry.Filesize = pFile->Filesize; - Error = FF_PutEntry(pFile->pIoman, pFile->DirEntry, pFile->DirCluster, &OriginalEntry); + + // UpDate Dirent if File-size has changed? + if(!(pFile->ValidFlags & FF_VALID_FLAG_DELETED) && (pFile->Mode & (FF_MODE_WRITE | FF_MODE_APPEND | FF_MODE_CREATE))) { + // Update the Dirent! + + if(pFile->Filesize % (pFile->pIoman->pPartition->BlkSize * pFile->pIoman->pPartition->SectorsPerCluster) == 0) { + /* + * The file meets the conditions, because it is of either 0 size, or is a perfect multiple + * of the size of 1 cluster. + */ + // Calculate how many cluster we should require: + + FF_T_UINT32 nClusters = pFile->Filesize / (pFile->pIoman->pPartition->BlkSize * pFile->pIoman->pPartition->SectorsPerCluster); + FF_T_UINT32 chainLen = FF_GetChainLength(pFile->pIoman, pFile->ObjectCluster, NULL, &Error); if(Error) { - return Error; + goto skip_truncate; } + // Unlink the chain! + if(chainLen > nClusters) { + + FF_lockFAT(pFile->pIoman); + { + if(!pFile->Filesize) { + Error = FF_UnlinkClusterChain(pFile->pIoman, pFile->ObjectCluster, 0); + } else { + unsigned long truncateCluster = FF_TraverseFAT(pFile->pIoman, pFile->ObjectCluster, nClusters-1, &Error); + + if(!FF_isERR(Error)) { + Error = FF_UnlinkClusterChain(pFile->pIoman, truncateCluster, 1); + FF_DecreaseFreeClusters(pFile->pIoman, 1); + } + } + } + FF_unlockFAT(pFile->pIoman); + } + //:D } + +skip_truncate: + + if(!FF_isERR(Error)) { + Error = FF_GetEntry(pFile->pIoman, pFile->DirEntry, pFile->DirCluster, &OriginalEntry); + } + + // Error might be non-zero, but don't forget to remove handle from list + // and to free the pFile pointer + + if(!FF_isERR(Error) && ((pFile->Filesize != OriginalEntry.Filesize) || (!pFile->Filesize))) { + if(!pFile->Filesize) { + OriginalEntry.ObjectCluster = 0; + } + OriginalEntry.Filesize = pFile->Filesize; + Error = FF_PutEntry(pFile->pIoman, pFile->DirEntry, pFile->DirCluster, &OriginalEntry); + } } + if (!FF_isERR(Error)) { + Error = 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. - if(pFile->pIoman->FirstFile == pFile) { + pFileChain = (FF_FILE *) pFile->pIoman->FirstFile; + if(pFileChain == pFile) { pFile->pIoman->FirstFile = pFile->Next; } else { - pFileChain = (FF_FILE *) pFile->pIoman->FirstFile; - while(pFileChain->Next != pFile) { - pFileChain = pFileChain->Next; + while (pFileChain) { + if (pFileChain->Next == pFile) { + pFileChain->Next = pFile->Next; + break; + } + pFileChain = pFileChain->Next; // Forgot this one } - pFileChain->Next = pFile->Next; } } // Semaphore released, linked list was shortened! FF_ReleaseSemaphore(pFile->pIoman->pSemaphore); - // If file written, flush to disk - FF_FREE(pFile); - - if(Error) { - return Error; +#ifdef FF_OPTIMISE_UNALIGNED_ACCESS + // Ensure any unaligned points are pushed to the disk! + if(pFile->ucState & FF_BUFSTATE_WRITTEN) { + if(!FF_isERR(Error)) { + Error = FF_BlockWrite(pFile->pIoman, FF_FileLBA(pFile), 1, pFile->pBuf, FF_FALSE); + } else { + FF_BlockWrite(pFile->pIoman, FF_FileLBA(pFile), 1, pFile->pBuf, FF_FALSE); + } } - // Simply free the pointer! - return FF_ERR_NONE; + FF_FREE(pFile->pBuf); +#endif + FF_FREE(pFile); + + return Error; } Index: ff_format.c =================================================================== --- ff_format.c (revision 58178) +++ ff_format.c (working copy) @@ -1,7 +1,19 @@ /***************************************************************************** - * FullFAT - High Performance, Thread-Safe Embedded FAT File-System * - * Copyright (C) 2009 James Walmsley (james@worm.me.uk) * + * FullFAT - High Performance, Thread-Safe Embedded FAT File-System * * * + * Copyright(C) 2009 James Walmsley * + * Copyright(C) 2011 Hein Tibosch * + * * + * See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT. * + * * + * WARNING : COMMERCIAL PROJECTS MUST COMPLY WITH THE GNU GPL LICENSE. * + * * + * Projects that cannot comply with the GNU GPL terms are legally obliged * + * to seek alternative licensing. Contact James Walmsley for details. * + * * + ***************************************************************************** + * See http://www.fullfat-fs.co.uk/ for more information. * + ***************************************************************************** * 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 * @@ -15,18 +27,14 @@ * 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. * + * The Copyright of Hein Tibosch on this project recognises his efforts in * + * contributing to this project. The right to license the project under * + * any other terms (other than the GNU GPL license) remains with the * + * original copyright holder (James Walmsley) only. * * * - * 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. * + * Modification/Extensions/Bugfixes/Improvements to FullFAT must be sent to * + * James Walmsley for integration into the main development branch. * *****************************************************************************/ /** @@ -74,59 +82,256 @@ return count; } + +FF_ERROR FF_CreatePartitionTable(FF_IOMAN *pIoman, FF_T_UINT32 ulTotalDeviceBlocks, FF_PARTITION_TABLE *pPTable) { + FF_BUFFER *pBuffer = FF_GetBuffer(pIoman, 0, FF_MODE_WRITE); + { + if(!pBuffer) { + return FF_ERR_DEVICE_DRIVER_FAILED; + } + + + } + FF_ReleaseBuffer(pIoman, pBuffer); + + return FF_ERR_NONE; +} + + 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_SINT8 scPartitionCount; + FF_T_UINT32 maxClusters, f16MaxClusters, f32MaxClusters; + FF_T_UINT32 fatSize = 32; // Default to a fat32 format. - FF_T_UINT32 /*ulPartitionBeginLBA, ulPartitionLength,*/ ulPnum; + FF_PARTITION_ENTRY partitionGeom; + FF_T_UINT32 ulBPRLba; ///< The LBA of the boot partition record. + + FF_T_UINT32 fat32Size, fat16Size, newFat32Size, newFat16Size, finalFatSize; + FF_T_UINT32 sectorsPerCluster = ulClusterSize / pIoman->BlkSize; + + FF_T_UINT32 ulReservedSectors, ulTotalSectors; + + FF_T_UINT32 ul32DataSectors, ul16DataSectors; + FF_T_UINT32 i; + + FF_T_UINT32 ulClusterBeginLBA; + 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; + return FF_ERR_DEVICE_DRIVER_FAILED | FF_FORMATPARTITION; } + scPartitionCount = FF_PartitionCount(pBuffer->pBuffer); - ucPartitionType = FF_getChar(pBuffer->pBuffer, FF_FAT_PTBL + FF_FAT_PTBL_ID); + if(!scPartitionCount) { + // Get Partition Geom from volume boot record. + ulBPRLba = 0; + partitionGeom.ulStartLBA = FF_getShort(pBuffer->pBuffer, FF_FAT_RESERVED_SECTORS); // Get offset to start of where we can actually put the FAT table. + ulReservedSectors = partitionGeom.ulStartLBA; + partitionGeom.ulLength = (FF_T_UINT32) FF_getShort(pBuffer->pBuffer, FF_FAT_16_TOTAL_SECTORS); - if(ucPartitionType == 0xEE) { - // Handle Extended Partitions - ulPnum = 0; + if(partitionGeom.ulLength == 0) { // 32-bit entry was used. + partitionGeom.ulLength = FF_getLong(pBuffer->pBuffer, FF_FAT_32_TOTAL_SECTORS); + } + + ulTotalSectors = partitionGeom.ulLength; + + partitionGeom.ulLength -= partitionGeom.ulStartLBA; // Remove the reserved sectors from the count. + } else { - if(ulPartitionNumber > (FF_T_UINT32) scPartitionCount) { - FF_ReleaseBuffer(pIoman, pBuffer); - return FF_ERR_IOMAN_INVALID_PARTITION_NUM; + // Get partition Geom from the partition table entry. + + } + + // Calculate the max possiblenumber of clusters based on clustersize. + maxClusters = partitionGeom.ulLength / sectorsPerCluster; + + // Determine the size of a FAT table required to support this. + fat32Size = (maxClusters * 4) / pIoman->BlkSize; // Potential size in sectors of a fat32 table. + if((maxClusters * 4) % pIoman->BlkSize) { + fat32Size++; + } + fat32Size *= 2; // Officially there are 2 copies of the FAT. + + fat16Size = (maxClusters * 2) / pIoman->BlkSize; // Potential size in bytes of a fat16 table. + if((maxClusters * 2) % pIoman->BlkSize) { + fat16Size++; + } + fat16Size *= 2; + + // A real number of sectors to be available is therefore ~~ + ul16DataSectors = partitionGeom.ulLength - fat16Size; + ul32DataSectors = partitionGeom.ulLength - fat32Size; + + f16MaxClusters = ul16DataSectors / sectorsPerCluster; + f32MaxClusters = ul32DataSectors / sectorsPerCluster; + + newFat16Size = (f16MaxClusters * 2) / pIoman->BlkSize; + if((f16MaxClusters * 2) % pIoman->BlkSize) { + newFat16Size++; + } + + newFat32Size = (f32MaxClusters * 4) / pIoman->BlkSize; + if((f32MaxClusters * 4) % pIoman->BlkSize) { + newFat32Size++; + } + + // Now determine if this should be fat16/32 format? + + if(f16MaxClusters < 65525) { + fatSize = 16; + finalFatSize = newFat16Size; + } else { + fatSize = 32; + finalFatSize = newFat32Size; + } + + FF_ReleaseBuffer(pIoman, pBuffer); + for(i = 0; i < finalFatSize*2; i++) { // Ensure the FAT table is clear. + if(i == 0) { + pBuffer = FF_GetBuffer(pIoman, partitionGeom.ulStartLBA, FF_MODE_WR_ONLY); + if(!pBuffer) { + return FF_ERR_DEVICE_DRIVER_FAILED; + } + + memset(pBuffer->pBuffer, 0, pIoman->BlkSize); + } else { + FF_BlockWrite(pIoman, partitionGeom.ulStartLBA+i, 1, pBuffer->pBuffer, FF_FALSE); } - ulPnum = ulPartitionNumber; } - } - FF_ReleaseBuffer(pIoman, pBuffer); + switch(fatSize) { + case 16: { + FF_putShort(pBuffer->pBuffer, 0, 0xFFF8); // First FAT entry. + FF_putShort(pBuffer->pBuffer, 2, 0xFFFF); // RESERVED alloc. + break; + } + case 32: { + FF_putLong(pBuffer->pBuffer, 0, 0x0FFFFFF8); // FAT32 FAT sig. + FF_putLong(pBuffer->pBuffer, 4, 0xFFFFFFFF); // RESERVED alloc. + FF_putLong(pBuffer->pBuffer, 8, 0x0FFFFFFF); // Root dir allocation. + break; + } + default: + break; + } - return Error; - -} + FF_ReleaseBuffer(pIoman, pBuffer); + + + // Clear and initialise the root dir. + ulClusterBeginLBA = partitionGeom.ulStartLBA + (finalFatSize*2); -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; + for(i = 0; i < sectorsPerCluster; i++) { + if(i == 0) { + pBuffer = FF_GetBuffer(pIoman, ulClusterBeginLBA, FF_MODE_WR_ONLY); + memset(pBuffer->pBuffer, 0, pIoman->BlkSize); + } else { + FF_BlockWrite(pIoman, ulClusterBeginLBA+i, 1, pBuffer->pBuffer, FF_FALSE); + } + + } - ulTotalSectors = ulEndLBA - ulStartLBA; - ulTotalClusters = ulTotalSectors / (ulClusterSize / pIoman->BlkSize); + FF_ReleaseBuffer(pIoman, pBuffer); + + // Correctly modify the second FAT item again. + pBuffer = FF_GetBuffer(pIoman, partitionGeom.ulStartLBA + finalFatSize, FF_MODE_WRITE); + { + switch(fatSize) { + case 16: { + FF_putShort(pBuffer->pBuffer, 0, 0xFFF8); + FF_putShort(pBuffer->pBuffer, 2, 0xFFFF); + break; + } + + case 32: + FF_putLong(pBuffer->pBuffer, 0, 0x0FFFFFF8); + FF_putLong(pBuffer->pBuffer, 4, 0xFFFFFFFF); + FF_putLong(pBuffer->pBuffer, 8, 0x0FFFFFFF); // Root dir allocation. + } + } + FF_ReleaseBuffer(pIoman, pBuffer); - return -1; + // Modify the fields in the VBR/PBR for correct mounting. + pBuffer = FF_GetBuffer(pIoman, ulBPRLba, FF_MODE_WRITE); // Modify the FAT descriptions. + { + // -- First section Common vars to Fat12/16 and 32. + memset(pBuffer->pBuffer, 0, pIoman->BlkSize); // Clear the boot record. + + FF_putChar(pBuffer->pBuffer, 0, 0xEB); // Place the Jump to bootstrap x86 instruction. + FF_putChar(pBuffer->pBuffer, 1, 0x3C); // Even though we won't populate the bootstrap code. + FF_putChar(pBuffer->pBuffer, 2, 0x90); // Some devices look for this as a signature. -} \ No newline at end of file + memcpy(((FF_T_UINT8 *)pBuffer->pBuffer+3), "FULLFAT2", 8); // Place the FullFAT OEM code. + + FF_putShort(pBuffer->pBuffer, 11, pIoman->BlkSize); + FF_putChar(pBuffer->pBuffer, 13, (FF_T_UINT8) sectorsPerCluster); + + FF_putShort(pBuffer->pBuffer, FF_FAT_RESERVED_SECTORS, (FF_T_UINT16)partitionGeom.ulStartLBA); // Number of reserved sectors. (1 for fat12/16, 32 for f32). + FF_putShort(pBuffer->pBuffer, FF_FAT_NUMBER_OF_FATS, 2); // Always 2 copies. + + + //FF_putShort(pBuffer->pBuffer, 19, 0); // Number of sectors in partition if size < 32mb. + + FF_putChar(pBuffer->pBuffer, 21, 0xF8); // Media type -- HDD. + + + FF_putShort(pBuffer->pBuffer, 510, 0xAA55); // MBR sig. + FF_putLong(pBuffer->pBuffer, 32, partitionGeom.ulLength+partitionGeom.ulStartLBA); // Total sectors of this partition. + + if(fatSize == 32) { + FF_putShort(pBuffer->pBuffer, 36, (FF_T_UINT16)finalFatSize); // Number of sectors per fat. + FF_putShort(pBuffer->pBuffer, 44, 2); // Root dir cluster (2). + FF_putShort(pBuffer->pBuffer, 48, 1); // FSINFO sector at LBA1. + FF_putShort(pBuffer->pBuffer, 50, 6); // 0 for no backup boot sector. + FF_putChar(pBuffer->pBuffer, 66, 0x29); // Indicate extended signature is present. + memcpy(((FF_T_UINT8 *)pBuffer->pBuffer+71), "FullFAT2-V", 10); // Volume name. + memcpy(((FF_T_UINT8 *)pBuffer->pBuffer+81), "FAT32 ", 8); + + // Put backup boot sector. + FF_BlockWrite(pIoman, 6, 1, pBuffer->pBuffer, FF_FALSE); + } else { + FF_putChar(pBuffer->pBuffer, 38, 0x28); // Signal this contains an extended signature. + memcpy(((FF_T_UINT8 *)pBuffer->pBuffer+43), "FullFAT2-V", 10); // Volume name. + memcpy(((FF_T_UINT8 *)pBuffer->pBuffer+54), "FAT16 ", 8); + FF_putShort(pBuffer->pBuffer, FF_FAT_16_SECTORS_PER_FAT, (FF_T_UINT16) finalFatSize); + FF_putShort(pBuffer->pBuffer, 17, 512); // Number of Dir entries. (FAT32 0). + //FF_putShort(pBuffer->pBuffer, FF_FAT_ROOT_ENTRY_COUNT, + } + } + } + FF_ReleaseBuffer(pIoman, pBuffer); + + if(fatSize == 32) { + // Finally if FAT32, create an FSINFO sector. + pBuffer = FF_GetBuffer(pIoman, 1, FF_MODE_WRITE); + { + memset(pBuffer->pBuffer, 0, pIoman->BlkSize); + FF_putLong(pBuffer->pBuffer, 0, 0x41615252); // FSINFO sect magic number. + FF_putLong(pBuffer->pBuffer, 484, 0x61417272); // FSINFO second sig. + // Calculate total sectors, -1 for the root dir allocation. (Free sectors count). + FF_putLong(pBuffer->pBuffer, 488, ((ulTotalSectors - (ulReservedSectors + (2*finalFatSize))) / sectorsPerCluster)-1); + FF_putLong(pBuffer->pBuffer, 492, 2); // Hint for next free cluster. + FF_putShort(pBuffer->pBuffer, 510, 0xAA55); + } + FF_ReleaseBuffer(pIoman, pBuffer); + } + + FF_FlushCache(pIoman); + + return Error; +} + Index: ff_hash.c =================================================================== --- ff_hash.c (revision 58178) +++ ff_hash.c (working copy) @@ -1,7 +1,19 @@ /***************************************************************************** - * FullFAT - High Performance, Thread-Safe Embedded FAT File-System * - * Copyright (C) 2009 James Walmsley (james@worm.me.uk) * + * FullFAT - High Performance, Thread-Safe Embedded FAT File-System * * * + * Copyright(C) 2009 James Walmsley * + * Copyright(C) 2011 Hein Tibosch * + * * + * See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT. * + * * + * WARNING : COMMERCIAL PROJECTS MUST COMPLY WITH THE GNU GPL LICENSE. * + * * + * Projects that cannot comply with the GNU GPL terms are legally obliged * + * to seek alternative licensing. Contact James Walmsley for details. * + * * + ***************************************************************************** + * See http://www.fullfat-fs.co.uk/ for more information. * + ***************************************************************************** * 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 * @@ -15,18 +27,14 @@ * 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. * + * The Copyright of Hein Tibosch on this project recognises his efforts in * + * contributing to this project. The right to license the project under * + * any other terms (other than the GNU GPL license) remains with the * + * original copyright holder (James Walmsley) only. * * * - * 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. * + * Modification/Extensions/Bugfixes/Improvements to FullFAT must be sent to * + * James Walmsley for integration into the main development branch. * *****************************************************************************/ /** @@ -69,7 +77,7 @@ return FF_ERR_NONE; } - return FF_ERR_NULL_POINTER; + return FF_ERR_NULL_POINTER | FF_CLEARHASHTABLE; } FF_ERROR FF_SetHash(FF_HASH_TABLE pHash, FF_T_UINT32 nHash) { @@ -81,7 +89,7 @@ return FF_ERR_NONE; } - return FF_ERR_NULL_POINTER; + return FF_ERR_NULL_POINTER | FF_SETHASH; } FF_ERROR FF_ClearHash(FF_HASH_TABLE pHash, FF_T_UINT32 nHash) { @@ -93,7 +101,7 @@ return FF_ERR_NONE; } - return FF_ERR_NULL_POINTER; + return FF_ERR_NULL_POINTER | FF_CLEARHASH; } FF_T_BOOL FF_isHashSet(FF_HASH_TABLE pHash, FF_T_UINT32 nHash) { @@ -113,7 +121,7 @@ FF_FREE(pHash); return FF_ERR_NONE; } - return FF_ERR_NULL_POINTER; + return FF_ERR_NULL_POINTER | FF_DESTROYHASHTABLE; } #endif Index: ff_ioman.c =================================================================== --- ff_ioman.c (revision 58178) +++ ff_ioman.c (working copy) @@ -1,7 +1,19 @@ /***************************************************************************** - * FullFAT - High Performance, Thread-Safe Embedded FAT File-System * - * Copyright (C) 2009 James Walmsley (james@worm.me.uk) * + * FullFAT - High Performance, Thread-Safe Embedded FAT File-System * * * + * Copyright(C) 2009 James Walmsley * + * Copyright(C) 2011 Hein Tibosch * + * * + * See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT. * + * * + * WARNING : COMMERCIAL PROJECTS MUST COMPLY WITH THE GNU GPL LICENSE. * + * * + * Projects that cannot comply with the GNU GPL terms are legally obliged * + * to seek alternative licensing. Contact James Walmsley for details. * + * * + ***************************************************************************** + * See http://www.fullfat-fs.co.uk/ for more information. * + ***************************************************************************** * 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 * @@ -15,18 +27,14 @@ * 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. * + * The Copyright of Hein Tibosch on this project recognises his efforts in * + * contributing to this project. The right to license the project under * + * any other terms (other than the GNU GPL license) remains with the * + * original copyright holder (James Walmsley) only. * * * - * 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. * + * Modification/Extensions/Bugfixes/Improvements to FullFAT must be sent to * + * James Walmsley for integration into the main development branch. * *****************************************************************************/ /** @@ -42,15 +50,14 @@ * Destroying a FullFAT IO object. **/ +#include #include #include "ff_ioman.h" // Includes ff_types.h, ff_safety.h, #include "ff_fatdef.h" #include "ff_crc.h" +#include "ff_fat.h" -//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); /** @@ -69,9 +76,9 @@ FF_IOMAN *FF_CreateIOMAN(FF_T_UINT8 *pCacheMem, FF_T_UINT32 Size, FF_T_UINT16 BlkSize, FF_ERROR *pError) { FF_IOMAN *pIoman = NULL; - FF_T_UINT32 *pLong = NULL; // Force malloc to malloc memory on a 32-bit boundary. -#ifdef FF_PATH_CACHE - FF_T_UINT32 i; + FF_T_UINT32 *pLong = NULL; +#ifdef FF_HASH_CACHE + FF_T_UINT i; #endif if(pError) { @@ -116,19 +123,6 @@ memset (pIoman->pPartition, '\0', sizeof(FF_PARTITION)); pIoman->MemAllocation |= FF_IOMAN_ALLOC_PART; // If succeeded, flag that allocation. - pIoman->pPartition->LastFreeCluster = 0; - pIoman->pPartition->PartitionMounted = FF_FALSE; // This should be checked by FF_Open(); -#ifdef FF_PATH_CACHE - pIoman->pPartition->PCIndex = 0; - 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 - 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++) { @@ -150,9 +144,10 @@ pIoman->MemAllocation |= FF_IOMAN_ALLOC_BLKDEV; // Make sure all pointers are NULL - pIoman->pBlkDevice->fnpReadBlocks = NULL; - pIoman->pBlkDevice->fnpWriteBlocks = NULL; - pIoman->pBlkDevice->pParam = NULL; + // ...have been nulled by previous memset() +// pIoman->pBlkDevice->fnReadBlocks = NULL; +// pIoman->pBlkDevice->fnWriteBlocks = NULL; +// pIoman->pBlkDevice->pParam = NULL; // Organise the memory provided, or create our own! if(pCacheMem) { @@ -174,8 +169,8 @@ pIoman->BlkSize = BlkSize; pIoman->CacheSize = (FF_T_UINT16) (Size / BlkSize); - pIoman->FirstFile = NULL; - pIoman->Locks = 0; +// pIoman->FirstFile = NULL; +// pIoman->Locks = 0; /* Malloc() memory for buffer objects. (FullFAT never refers to a buffer directly but uses buffer objects instead. Allows us to provide thread safety. @@ -280,7 +275,7 @@ pIoman->LastReplaced = 0; // HT : it is assmued that pBuffer was cleared by memset () for(i = 0; i < pIoman->CacheSize; i++) { - pBuffer->pBuffer = (FF_T_UINT8 *)((pIoman->pCacheMem) + (pIoman->BlkSize * i)); + pBuffer->pBuffer = (FF_T_UINT8 *)((pIoman->pCacheMem) + (pIoman->BlkSize * i)); pBuffer++; } } @@ -307,7 +302,7 @@ for(i = 0; i < pIoman->CacheSize; i++) { if((pIoman->pBuffers + i)->NumHandles == 0 && (pIoman->pBuffers + i)->Modified == FF_TRUE) { - FF_BlockWrite(pIoman, (pIoman->pBuffers + i)->Sector, 1, (pIoman->pBuffers + i)->pBuffer); + FF_BlockWrite(pIoman, (pIoman->pBuffers + i)->Sector, 1, (pIoman->pBuffers + i)->pBuffer, FF_TRUE); // Buffer has now been flushed, mark it as a read buffer and unmodified. (pIoman->pBuffers + i)->Mode = FF_MODE_READ; @@ -330,24 +325,40 @@ return FF_ERR_NONE; } +/* + A new version of FF_GetBuffer() with a simple mechanism for timeout +*/ + +#define FF_GETBUFFER_SLEEP_TIME 10 +#define FF_GETBUFFER_WAIT_TIME (20000 / FF_GETBUFFER_SLEEP_TIME) + FF_BUFFER *FF_GetBuffer(FF_IOMAN *pIoman, FF_T_UINT32 Sector, FF_T_UINT8 Mode) { FF_BUFFER *pBuffer; - FF_BUFFER *pBufLRU = NULL; - FF_BUFFER *pBufLHITS = NULL; - FF_BUFFER *pBufMatch = NULL; + FF_BUFFER *pBufLRU; +// FF_BUFFER *pBufLHITS = NULL; // Wasn't use anymore? + FF_BUFFER *pBufMatch = NULL; + FF_T_SINT32 RetVal; + FF_T_INT LoopCount = FF_GETBUFFER_WAIT_TIME; - FF_T_UINT32 i; + FF_T_INT cacheSize = pIoman->CacheSize; + if (cacheSize <= 0) { + return NULL; + } while(!pBufMatch) { + if (!--LoopCount) { + // + // *pError = FF_ERR_IOMAN_GETBUFFER_TIMEOUT; + // + return NULL; + } FF_PendSemaphore(pIoman->pSemaphore); { - 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) { + + for(pBuffer = pIoman->pBuffers; pBuffer < pIoman->pBuffers + cacheSize; pBuffer++) { + if(pBuffer->Sector == Sector && pBuffer->Valid) { pBufMatch = pBuffer; - break; // Why look further if you found a perfect match? + break; // Don't look further if you found a perfect match } } @@ -356,86 +367,80 @@ if(Mode == FF_MODE_READ && pBufMatch->Mode == FF_MODE_READ) { pBufMatch->NumHandles += 1; pBufMatch->Persistance += 1; - FF_ReleaseSemaphore(pIoman->pSemaphore); - return pBufMatch; + break; } - if(pBufMatch->Mode == FF_MODE_WRITE && pBufMatch->NumHandles == 0) { // This buffer has no attached handles. - pBufMatch->Mode = Mode; + if(pBufMatch->NumHandles == 0) { + pBufMatch->Mode = (Mode & FF_MODE_RD_WR); + if((Mode & FF_MODE_WRITE) != 0) { // This buffer has no attached handles. + pBufMatch->Modified = FF_TRUE; + } pBufMatch->NumHandles = 1; pBufMatch->Persistance += 1; - FF_ReleaseSemaphore(pIoman->pSemaphore); - return pBufMatch; + break; } - if(pBufMatch->Mode == FF_MODE_READ && Mode == FF_MODE_WRITE && pBufMatch->NumHandles == 0) { - pBufMatch->Mode = Mode; - pBufMatch->Modified = FF_TRUE; - pBufMatch->NumHandles = 1; - pBufMatch->Persistance += 1; - FF_ReleaseSemaphore(pIoman->pSemaphore); - return pBufMatch; - } - pBufMatch = NULL; // Sector is already in use, keep yielding until its available! } else { - pBuffer = pIoman->pBuffers; - for(i = 0; i < pIoman->CacheSize; i++, pBuffer++) { - if(pBuffer->NumHandles == 0) { - pBuffer->LRU += 1; + pBufLRU = NULL; // So put them to NULL here - if(!pBufLRU) { - pBufLRU = pBuffer; - } - if(!pBufLHITS) { - pBufLHITS = pBuffer; - } + for(pBuffer = pIoman->pBuffers; pBuffer < pIoman->pBuffers + cacheSize; pBuffer++) { + if(pBuffer->NumHandles) + continue; // Occupied + pBuffer->LRU += 1; - if(pBuffer->LRU >= pBufLRU->LRU) { - if(pBuffer->LRU == pBufLRU->LRU) { - if(pBuffer->Persistance > pBufLRU->Persistance) { - pBufLRU = pBuffer; - } - } else { - pBufLRU = pBuffer; - } - } + if(!pBufLRU) { + pBufLRU = pBuffer; + } - if(pBuffer->Persistance < pBufLHITS->Persistance) { - pBufLHITS = pBuffer; - } + if(pBuffer->LRU > pBufLRU->LRU || + (pBuffer->LRU == pBufLRU->LRU && pBuffer->Persistance > pBufLRU->Persistance)) { + pBufLRU = pBuffer; } + } - + // Choose a suitable buffer! if(pBufLRU) { // Process the suitable candidate. if(pBufLRU->Modified == FF_TRUE) { - FF_BlockWrite(pIoman, pBufLRU->Sector, 1, pBufLRU->pBuffer); + // Along with the FF_TRUE parameter to indicate semapahore has been claimed + + RetVal = FF_BlockWrite(pIoman, pBufLRU->Sector, 1, pBufLRU->pBuffer, FF_TRUE); + if (RetVal < 0) { + pBufMatch = NULL; + break; + } } - pBufLRU->Mode = Mode; + if (Mode == FF_MODE_WR_ONLY) { + memset (pBufLRU->pBuffer, '\0', pIoman->BlkSize); + } else { + RetVal = FF_BlockRead(pIoman, Sector, 1, pBufLRU->pBuffer, FF_TRUE); + if (RetVal < 0) { + pBufMatch = NULL; + break; + } + } + pBufLRU->Mode = (Mode & FF_MODE_RD_WR); pBufLRU->Persistance = 1; pBufLRU->LRU = 0; pBufLRU->NumHandles = 1; pBufLRU->Sector = Sector; - if(Mode == FF_MODE_WRITE) { - pBufLRU->Modified = FF_TRUE; - } else { - pBufLRU->Modified = FF_FALSE; - } + pBufLRU->Modified = (Mode & FF_MODE_WRITE) != 0; - FF_BlockRead(pIoman, Sector, 1, pBufLRU->pBuffer); pBufLRU->Valid = FF_TRUE; - FF_ReleaseSemaphore(pIoman->pSemaphore); - return pBufLRU; + pBufMatch = pBufLRU; + break; } } } FF_ReleaseSemaphore(pIoman->pSemaphore); - FF_Yield(); // Better to go asleep to give low-priority task a chance to release buffer(s) - } + // Better to go asleep to give low-priority task a chance to release buffer(s) + FF_Sleep (FF_GETBUFFER_SLEEP_TIME); + } // while(!pBufMatch) + FF_ReleaseSemaphore(pIoman->pSemaphore); return pBufMatch; // Return the Matched Buffer! } @@ -449,7 +454,9 @@ * @param pBuffer Pointer to an FF_BUFFER object. * **/ -void FF_ReleaseBuffer(FF_IOMAN *pIoman, FF_BUFFER *pBuffer) { +FF_ERROR FF_ReleaseBuffer(FF_IOMAN *pIoman, FF_BUFFER *pBuffer) { + FF_ERROR Error = FF_ERR_NONE; + // Protect description changes with a semaphore. FF_PendSemaphore(pIoman->pSemaphore); { @@ -458,8 +465,18 @@ } else { //printf ("FF_ReleaseBuffer: buffer not claimed\n"); } +#ifdef FF_CACHE_WRITE_THROUGH + if(pBuffer->Modified == FF_TRUE) { + Error = FF_BlockWrite(pIoman, pBuffer->Sector, 1, pBuffer->pBuffer, FF_TRUE); + if(!FF_isERR(Error)) { // Ensure if an error occurs its still possible to write the block again. + pBuffer->Modified = FF_FALSE; + } + } +#endif } FF_ReleaseSemaphore(pIoman->pSemaphore); + + return Error; } /** @@ -516,52 +533,58 @@ 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 FF_BlockRead(FF_IOMAN *pIoman, FF_T_UINT32 ulSectorLBA, FF_T_UINT32 ulNumSectors, void *pBuffer, FF_T_BOOL aSemLocked) { 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); + return (FF_ERR_IOMAN_OUT_OF_BOUNDS_READ | FF_BLOCKREAD); } } - if(pIoman->pBlkDevice->fnpReadBlocks) { // Make sure we don't execute a NULL. + if(pIoman->pBlkDevice->fnpReadBlocks) do { // Make sure we don't execute a NULL. #ifdef FF_BLKDEV_USES_SEM - FF_PendSemaphore(pIoman->pBlkDevSemaphore); + if (!aSemLocked || pIoman->pSemaphore != pIoman->pBlkDevSemaphore) + FF_PendSemaphore(pIoman->pBlkDevSemaphore); #endif slRetVal = pIoman->pBlkDevice->fnpReadBlocks(pBuffer, ulSectorLBA, ulNumSectors, pIoman->pBlkDevice->pParam); #ifdef FF_BLKDEV_USES_SEM - FF_ReleaseSemaphore(pIoman->pBlkDevSemaphore); + if (!aSemLocked || pIoman->pSemaphore != pIoman->pBlkDevSemaphore) + FF_ReleaseSemaphore(pIoman->pBlkDevSemaphore); #endif - if(FF_GETERROR(slRetVal) == FF_ERR_DRIVER_BUSY) { - FF_Sleep(FF_DRIVER_BUSY_SLEEP); + if(!FF_isERR(slRetVal) && FF_GETERROR(slRetVal) != FF_ERR_DRIVER_BUSY) { + break; } - } while(FF_GETERROR(slRetVal) == FF_ERR_DRIVER_BUSY); + FF_Sleep(FF_DRIVER_BUSY_SLEEP); + } while (FF_TRUE); return slRetVal; } -FF_T_SINT32 FF_BlockWrite(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_T_BOOL aSemLocked) { 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); + return (FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_BLOCKWRITE); } } - if(pIoman->pBlkDevice->fnpWriteBlocks) { // Make sure we don't execute a NULL. + if(pIoman->pBlkDevice->fnpWriteBlocks) do { // Make sure we don't execute a NULL. #ifdef FF_BLKDEV_USES_SEM - FF_PendSemaphore(pIoman->pBlkDevSemaphore); + if (!aSemLocked || pIoman->pSemaphore != pIoman->pBlkDevSemaphore) + FF_PendSemaphore(pIoman->pBlkDevSemaphore); #endif slRetVal = pIoman->pBlkDevice->fnpWriteBlocks(pBuffer, ulSectorLBA, ulNumSectors, pIoman->pBlkDevice->pParam); #ifdef FF_BLKDEV_USES_SEM - FF_ReleaseSemaphore(pIoman->pBlkDevSemaphore); + if (!aSemLocked || pIoman->pSemaphore != pIoman->pBlkDevSemaphore) + FF_ReleaseSemaphore(pIoman->pBlkDevSemaphore); #endif - if(FF_GETERROR(slRetVal) == FF_ERR_DRIVER_BUSY) { - FF_Sleep(FF_DRIVER_BUSY_SLEEP); + if(!FF_isERR(slRetVal) && FF_GETERROR(slRetVal) != FF_ERR_DRIVER_BUSY) { + break; } - } while(FF_GETERROR(slRetVal) == FF_ERR_DRIVER_BUSY); + FF_Sleep(FF_DRIVER_BUSY_SLEEP); + } while (FF_TRUE); return slRetVal; } @@ -575,6 +598,7 @@ FF_PARTITION *pPart; FF_BUFFER *pBuffer; FF_T_UINT32 testLong; + FF_ERROR Error; if(pIoman) { pPart = pIoman->pPartition; @@ -586,22 +610,24 @@ pBuffer = FF_GetBuffer(pIoman, pIoman->pPartition->FatBeginLBA, FF_MODE_READ); { if(!pBuffer) { - return FF_ERR_DEVICE_DRIVER_FAILED; + return FF_ERR_DEVICE_DRIVER_FAILED | FF_DETERMINEFATTYPE; } testLong = (FF_T_UINT32) FF_getShort(pBuffer->pBuffer, 0x0000); } - FF_ReleaseBuffer(pIoman, pBuffer); + Error = FF_ReleaseBuffer(pIoman, pBuffer); + if(FF_isERR(Error)) { + return Error; + } if((testLong & 0x3FF) != 0x3F8) { - return FF_ERR_IOMAN_NOT_FAT_FORMATTED; + return FF_ERR_IOMAN_NOT_FAT_FORMATTED | FF_DETERMINEFATTYPE; } #else - return FF_ERR_IOMAN_NOT_FAT_FORMATTED; + return FF_ERR_IOMAN_NOT_FAT_FORMATTED | FF_DETERMINEFATTYPE; #endif #endif #ifdef FF_FAT12_SUPPORT return FF_ERR_NONE; #endif - } else if(pPart->NumClusters < 65525) { // FAT 16 pPart->Type = FF_T_FAT16; @@ -609,16 +635,18 @@ pBuffer = FF_GetBuffer(pIoman, pIoman->pPartition->FatBeginLBA, FF_MODE_READ); { if(!pBuffer) { - return FF_ERR_DEVICE_DRIVER_FAILED; + return FF_ERR_DEVICE_DRIVER_FAILED | FF_DETERMINEFATTYPE; } testLong = (FF_T_UINT32) FF_getShort(pBuffer->pBuffer, 0x0000); } - FF_ReleaseBuffer(pIoman, pBuffer); - if(testLong != 0xFFF8) { - return FF_ERR_IOMAN_NOT_FAT_FORMATTED; + Error = FF_ReleaseBuffer(pIoman, pBuffer); + if(FF_isERR(Error)) { + return Error; } + + if(testLong == 0xFFF8) + return FF_ERR_NONE; #endif - return FF_ERR_NONE; } else { // FAT 32! @@ -627,20 +655,28 @@ pBuffer = FF_GetBuffer(pIoman, pIoman->pPartition->FatBeginLBA, FF_MODE_READ); { if(!pBuffer) { - return FF_ERR_DEVICE_DRIVER_FAILED; + return FF_ERR_DEVICE_DRIVER_FAILED | FF_DETERMINEFATTYPE; } testLong = FF_getLong(pBuffer->pBuffer, 0x0000); } - FF_ReleaseBuffer(pIoman, pBuffer); + Error = FF_ReleaseBuffer(pIoman, pBuffer); + if(FF_isERR(Error)) { + return Error; + } + if((testLong & 0x0FFFFFF8) != 0x0FFFFFF8 && (testLong & 0x0FFFFFF8) != 0x0FFFFFF0) { - return FF_ERR_IOMAN_NOT_FAT_FORMATTED; + // HT: + // I had an SD-card which worked well in Linux/W32 + // but FullFAT returned me this error + // So for me I left out this check (just issue a warning for now) + return FF_ERR_NONE; // FF_ERR_IOMAN_NOT_FAT_FORMATTED; } #endif return FF_ERR_NONE; } } - return FF_ERR_IOMAN_NOT_FAT_FORMATTED; + return FF_ERR_IOMAN_NOT_FAT_FORMATTED | FF_DETERMINEFATTYPE; } static FF_T_SINT8 FF_PartitionCount (FF_T_UINT8 *pBuffer) @@ -689,28 +725,32 @@ 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; + FF_ERROR Error; + if(ulPartitionNumber >= 128) { - return FF_ERR_IOMAN_INVALID_PARTITION_NUM; + return FF_ERR_IOMAN_INVALID_PARTITION_NUM | FF_GETEFIPARTITIONENTRY; } pBuffer = FF_GetBuffer(pIoman, pPart->BeginLBA, FF_MODE_READ); { if(!pBuffer) { - return FF_ERR_DEVICE_DRIVER_FAILED; + return FF_ERR_DEVICE_DRIVER_FAILED | FF_GETEFIPARTITIONENTRY; } // Verify this is an EFI header if(memcmp(pBuffer->pBuffer, "EFI PART", 8) != 0) { - FF_ReleaseBuffer(pIoman, pBuffer); - return FF_ERR_IOMAN_INVALID_FORMAT; + Error = FF_ReleaseBuffer(pIoman, pBuffer); // Already returning an error, but this error would override the current one. + if(FF_isERR(Error)) { + return Error; + } + return FF_ERR_IOMAN_INVALID_FORMAT | FF_GETEFIPARTITIONENTRY; } 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); @@ -726,11 +766,14 @@ // Restore The CRC field FF_putLong(pBuffer->pBuffer, FF_GPT_HEAD_CRC, ulGPTHeadCRC); } - FF_ReleaseBuffer(pIoman, pBuffer); + Error = FF_ReleaseBuffer(pIoman, pBuffer); + if(FF_isERR(Error)) { + return Error; + } // Check CRC if(ulGPTHeadCRC != ulGPTCrcCheck) { - return FF_ERR_IOMAN_GPT_HEADER_CORRUPT; + return FF_ERR_IOMAN_GPT_HEADER_CORRUPT | FF_GETEFIPARTITIONENTRY; } // Calculate Sector Containing the Partition Entry we want to use. @@ -741,15 +784,18 @@ pBuffer = FF_GetBuffer(pIoman, ulEntrySector, FF_MODE_READ); { if(!pBuffer) { - return FF_ERR_DEVICE_DRIVER_FAILED; + return FF_ERR_DEVICE_DRIVER_FAILED | FF_GETEFIPARTITIONENTRY; } pPart->BeginLBA = FF_getLong(pBuffer->pBuffer, ulSectorOffset + FF_GPT_ENTRY_FIRST_SECTOR_LBA); } - FF_ReleaseBuffer(pIoman, pBuffer); + Error = FF_ReleaseBuffer(pIoman, pBuffer); + if(FF_isERR(Error)) { + return Error; + } if(!pPart->BeginLBA) { - return FF_ERR_IOMAN_INVALID_PARTITION_NUM; + return FF_ERR_IOMAN_INVALID_PARTITION_NUM | FF_GETEFIPARTITIONENTRY; } return FF_ERR_NONE; @@ -779,11 +825,13 @@ FF_ERROR Error; FF_T_UINT8 ucPartitionType; - +#ifdef FF_HASH_CACHE + FF_T_INT i; +#endif int partCount; if(!pIoman) { - return FF_ERR_NULL_POINTER; + return FF_ERR_NULL_POINTER | FF_MOUNTPARTITION; } /*if(PartitionNumber > 3) { @@ -795,12 +843,18 @@ memset (pIoman->pBuffers, '\0', sizeof(FF_BUFFER) * pIoman->CacheSize); memset (pIoman->pCacheMem, '\0', pIoman->BlkSize * pIoman->CacheSize); +#ifdef FF_HASH_CACHE + for(i = 0; i < FF_HASH_CACHE_DEPTH; i++) { + FF_ClearHashTable(pIoman->HashCache[i].pHashTable); + } +#endif + FF_IOMAN_InitBufferDescriptors(pIoman); pIoman->FirstFile = 0; pBuffer = FF_GetBuffer(pIoman, 0, FF_MODE_READ); if(!pBuffer) { - return FF_ERR_DEVICE_DRIVER_FAILED; + return FF_ERR_DEVICE_DRIVER_FAILED | FF_MOUNTPARTITION; } partCount = FF_PartitionCount (pBuffer->pBuffer); @@ -817,38 +871,45 @@ if(ucPartitionType != 0xEE) { if(PartitionNumber > 3) { - FF_ReleaseBuffer(pIoman, pBuffer); - return FF_ERR_IOMAN_INVALID_PARTITION_NUM; + Error = FF_ReleaseBuffer(pIoman, pBuffer); // Already returning an error, but an error from ReleaseBuf would override it. + if(FF_isERR(Error)) { + return Error; + } + return FF_ERR_IOMAN_INVALID_PARTITION_NUM | FF_MOUNTPARTITION; } // Primary Partitions to deal with! pPart->BeginLBA = FF_getLong(pBuffer->pBuffer, FF_FAT_PTBL + FF_FAT_PTBL_LBA + (16 * PartitionNumber)); } + Error = FF_ReleaseBuffer(pIoman, pBuffer); + if(FF_isERR(Error)) { + return Error; + } - 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) { + if(FF_isERR(Error)) { return Error; } } if(!pPart->BeginLBA) { - return FF_ERR_IOMAN_NO_MOUNTABLE_PARTITION; + return FF_ERR_IOMAN_NO_MOUNTABLE_PARTITION | FF_MOUNTPARTITION; } // Now we get the Partition sector. pBuffer = FF_GetBuffer(pIoman, pPart->BeginLBA, FF_MODE_READ); if(!pBuffer) { - return FF_ERR_DEVICE_DRIVER_FAILED; + return FF_ERR_DEVICE_DRIVER_FAILED | FF_MOUNTPARTITION; } pPart->BlkSize = FF_getShort(pBuffer->pBuffer, FF_FAT_BYTES_PER_SECTOR); if((pPart->BlkSize % 512) != 0 || pPart->BlkSize == 0) { - FF_ReleaseBuffer(pIoman, pBuffer); - return FF_ERR_IOMAN_INVALID_FORMAT; + Error = FF_ReleaseBuffer(pIoman, pBuffer); // An error here should override the current error, as its likely fatal. + if(FF_isERR(Error)) { + return Error; + } + return FF_ERR_IOMAN_INVALID_FORMAT | FF_MOUNTPARTITION; } } @@ -881,34 +942,46 @@ } memcpy (pPart->VolLabel, pBuffer->pBuffer + FF_FAT_16_VOL_LABEL, sizeof pPart->VolLabel); } +#ifdef FF_WRITE_FREE_COUNT + pPart->FSInfoLBA = pPart->BeginLBA + FF_getShort(pBuffer->pBuffer, 48); +#endif - FF_ReleaseBuffer(pIoman, pBuffer); // Release the buffer finally! + Error = FF_ReleaseBuffer(pIoman, pBuffer); // Release the buffer finally! + if(FF_isERR(Error)) { + return Error; + } if(!pPart->BlkSize) { - return FF_ERR_IOMAN_INVALID_FORMAT; + return FF_ERR_IOMAN_INVALID_FORMAT | FF_MOUNTPARTITION; } - + 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; + return FF_ERR_IOMAN_INVALID_FORMAT | FF_MOUNTPARTITION; } - pPart->NumClusters = pPart->DataSectors / pPart->SectorsPerCluster; + pPart->NumClusters = pPart->DataSectors / pPart->SectorsPerCluster; Error = FF_DetermineFatType(pIoman); - if(Error) { + if(FF_isERR(Error)) { return Error; } - + pPart->PartitionMounted = FF_TRUE; + pPart->LastFreeCluster = 0; #ifdef FF_MOUNT_FIND_FREE - pPart->LastFreeCluster = FF_FindFreeCluster(pIoman); - pPart->FreeClusterCount = FF_CountFreeClusters(pIoman); + pPart->LastFreeCluster = FF_FindFreeCluster(pIoman, &Error); + if(FF_isERR(Error)) { + return Error; + } + pPart->FreeClusterCount = FF_CountFreeClusters(pIoman, &Error); + if(FF_isERR(Error)) { + return Error; + } #else - pPart->LastFreeCluster = 0; pPart->FreeClusterCount = 0; #endif @@ -927,10 +1000,10 @@ **/ FF_ERROR FF_UnregisterBlkDevice(FF_IOMAN *pIoman) { - FF_T_SINT8 RetVal = FF_ERR_NONE; + FF_ERROR RetVal = FF_ERR_NONE; if(!pIoman) { - return FF_ERR_NULL_POINTER; + return FF_ERR_NULL_POINTER | FF_UNREGISTERBLKDEVICE; } FF_PendSemaphore(pIoman->pSemaphore); @@ -941,7 +1014,7 @@ pIoman->pBlkDevice->fnpWriteBlocks = NULL; pIoman->pBlkDevice->pParam = NULL; } else { - RetVal = FF_ERR_IOMAN_PARTITION_MOUNTED; + RetVal = FF_ERR_IOMAN_PARTITION_MOUNTED | FF_UNREGISTERBLKDEVICE; } } FF_ReleaseSemaphore(pIoman->pSemaphore); @@ -983,11 +1056,17 @@ * @return FF_ERR_NONE on success. **/ FF_ERROR FF_UnmountPartition(FF_IOMAN *pIoman) { - FF_T_SINT8 RetVal = FF_ERR_NONE; + FF_ERROR RetVal = FF_ERR_NONE; +#ifdef FF_MIRROR_FATS_UMOUNT + FF_T_UINT i, y; + FF_BUFFER *pBuffer; +#endif - if(!pIoman) { - return FF_ERR_NULL_POINTER; + if(!pIoman || !pIoman->pPartition) { + return FF_ERR_NULL_POINTER | FF_UNMOUNTPARTITION; } + if (!pIoman->pPartition->PartitionMounted) + return FF_ERR_NONE; FF_PendSemaphore(pIoman->pSemaphore); // Ensure that there are no File Handles { @@ -995,15 +1074,33 @@ if(pIoman->FirstFile == NULL) { // Release Semaphore to call this function! FF_ReleaseSemaphore(pIoman->pSemaphore); - FF_FlushCache(pIoman); // Flush any unwritten sectors to disk. + RetVal = FF_FlushCache(pIoman); // Flush any unwritten sectors to disk. + if(FF_isERR(RetVal)) { + return RetVal; + } // Reclaim Semaphore FF_PendSemaphore(pIoman->pSemaphore); pIoman->pPartition->PartitionMounted = FF_FALSE; + +#ifdef FF_MIRROR_FATS_UMOUNT + FF_ReleaseSemaphore(pIoman->pSemaphore); + for(i = 0; i < pIoman->pPartition->SectorsPerFAT; i++) { + pBuffer = FF_GetBuffer(pIoman, pIoman->pPartition->FatBeginLBA + i, FF_MODE_READ); + if(!pBuffer) { + RetVal = FF_ERR_DEVICE_DRIVER_FAILED | FF_UNMOUNTPARTITION; + break; + } + for(y = 0; y < pIoman->pPartition->NumFATS; y++) { + FF_BlockWrite(pIoman, pIoman->pPartition->FatBeginLBA + (y*pIoman->pPartition->SectorsPerFAT) + i, 1, pBuffer->pBuffer, FF_FALSE); + } + } + FF_PendSemaphore(pIoman->pSemaphore); +#endif } else { - RetVal = FF_ERR_IOMAN_ACTIVE_HANDLES; + RetVal = FF_ERR_IOMAN_ACTIVE_HANDLES | FF_UNMOUNTPARTITION; } } else { - RetVal = FF_ERR_IOMAN_ACTIVE_HANDLES; // Active handles found on the cache. + RetVal = FF_ERR_IOMAN_ACTIVE_HANDLES | FF_UNMOUNTPARTITION; // Active handles found on the cache. } } FF_ReleaseSemaphore(pIoman->pSemaphore); @@ -1015,39 +1112,83 @@ 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, &Error); - if(Error) { - return Error; - } - } else { - pIoman->pPartition->FreeClusterCount += Count; - } - //} - //FF_ReleaseSemaphore(pIoman->pSemaphore); +#ifdef FF_WRITE_FREE_COUNT + FF_BUFFER *pBuffer; +#endif + + if(!pIoman->pPartition->FreeClusterCount) { + pIoman->pPartition->FreeClusterCount = FF_CountFreeClusters(pIoman, &Error); + if(FF_isERR(Error)) { + return Error; + } + } else { + pIoman->pPartition->FreeClusterCount += Count; + } +#ifdef FF_WRITE_FREE_COUNT + // FAT32 update the FSINFO sector. + if(pIoman->pPartition->Type == FF_T_FAT32) { + // Find the FSINFO sector. + pBuffer = FF_GetBuffer(pIoman, pIoman->pPartition->FSInfoLBA, FF_MODE_WRITE); + { + if(!pBuffer) { + return FF_ERR_DEVICE_DRIVER_FAILED | FF_INCREASEFREECLUSTERS; + } + + if(FF_getLong(pBuffer->pBuffer, 0) == 0x41615252 && FF_getLong(pBuffer->pBuffer, 484) == 0x61417272) { + // FSINFO sector magic nums we're verified. Safe to write. + FF_putLong(pBuffer->pBuffer, 488, pIoman->pPartition->FreeClusterCount); + FF_putLong(pBuffer->pBuffer, 492, pIoman->pPartition->LastFreeCluster); + } + } + Error = FF_ReleaseBuffer(pIoman, pBuffer); + if(FF_isERR(Error)) { + return Error; + } + } +#endif + return FF_ERR_NONE; } FF_ERROR FF_DecreaseFreeClusters(FF_IOMAN *pIoman, FF_T_UINT32 Count) { FF_ERROR Error; +#ifdef FF_WRITE_FREE_COUNT + FF_BUFFER *pBuffer; +#endif - //FF_lockFAT(pIoman); - //{ - if(!pIoman->pPartition->FreeClusterCount) { - pIoman->pPartition->FreeClusterCount = FF_CountFreeClusters(pIoman, &Error); - if(Error) { - return Error; - } - } else { - pIoman->pPartition->FreeClusterCount -= Count; - } - //} - //FF_unlockFAT(pIoman); + if(!pIoman->pPartition->FreeClusterCount) { + pIoman->pPartition->FreeClusterCount = FF_CountFreeClusters(pIoman, &Error); + if(FF_isERR(Error)) { + return Error; + } + } else { + pIoman->pPartition->FreeClusterCount -= Count; + } +#ifdef FF_WRITE_FREE_COUNT + // FAT32 update the FSINFO sector. + if(pIoman->pPartition->Type == FF_T_FAT32) { + // Find the FSINFO sector. + pBuffer = FF_GetBuffer(pIoman, pIoman->pPartition->FSInfoLBA, FF_MODE_WRITE); + { + if(!pBuffer) { + return FF_ERR_DEVICE_DRIVER_FAILED | FF_DECREASEFREECLUSTERS; + } + + if(FF_getLong(pBuffer->pBuffer, 0) == 0x41615252 && FF_getLong(pBuffer->pBuffer, 484) == 0x61417272) { + // FSINFO sector magic nums we're verified. Safe to write. + FF_putLong(pBuffer->pBuffer, 488, pIoman->pPartition->FreeClusterCount); + FF_putLong(pBuffer->pBuffer, 492, pIoman->pPartition->LastFreeCluster); + } + } + Error = FF_ReleaseBuffer(pIoman, pBuffer); + if(FF_isERR(Error)) { + return Error; + } + } +#endif return FF_ERR_NONE; } @@ -1071,7 +1212,7 @@ return (FF_T_SINT32) pIoman->pPartition->BlkSize; } - return FF_ERR_NULL_POINTER; + return FF_ERR_NULL_POINTER | FF_GETPARTITIONBLOCKSIZE; } #ifdef FF_64_NUM_SUPPORT @@ -1085,16 +1226,18 @@ **/ FF_T_UINT64 FF_GetVolumeSize(FF_IOMAN *pIoman) { if(pIoman) { - FF_T_UINT32 TotalClusters = pIoman->pPartition->DataSectors / pIoman->pPartition->SectorsPerCluster; + FF_T_UINT32 TotalClusters = (pIoman->pPartition->DataSectors / pIoman->pPartition->SectorsPerCluster); return (FF_T_UINT64) ((FF_T_UINT64)TotalClusters * (FF_T_UINT64)((FF_T_UINT64)pIoman->pPartition->SectorsPerCluster * (FF_T_UINT64)pIoman->pPartition->BlkSize)); } return 0; } - #else FF_T_UINT32 FF_GetVolumeSize(FF_IOMAN *pIoman) { - FF_T_UINT32 TotalClusters = pIoman->pPartition->DataSectors / pIoman->pPartition->SectorsPerCluster; - return (FF_T_UINT32) (TotalClusters * (pIoman->pPartition->SectorsPerCluster * pIoman->pPartition->BlkSize)); + if(pIoman) { + FF_T_UINT32 TotalClusters = pIoman->pPartition->DataSectors / pIoman->pPartition->SectorsPerCluster; + return (FF_T_UINT32) (TotalClusters * (pIoman->pPartition->SectorsPerCluster * pIoman->pPartition->BlkSize)); + } + return 0; } #endif Index: ff_memory.c =================================================================== --- ff_memory.c (revision 58178) +++ ff_memory.c (working copy) @@ -1,7 +1,19 @@ /***************************************************************************** - * FullFAT - High Performance, Thread-Safe Embedded FAT File-System * - * Copyright (C) 2009 James Walmsley (james@worm.me.uk) * + * FullFAT - High Performance, Thread-Safe Embedded FAT File-System * * * + * Copyright(C) 2009 James Walmsley * + * Copyright(C) 2011 Hein Tibosch * + * * + * See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT. * + * * + * WARNING : COMMERCIAL PROJECTS MUST COMPLY WITH THE GNU GPL LICENSE. * + * * + * Projects that cannot comply with the GNU GPL terms are legally obliged * + * to seek alternative licensing. Contact James Walmsley for details. * + * * + ***************************************************************************** + * See http://www.fullfat-fs.co.uk/ for more information. * + ***************************************************************************** * 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 * @@ -15,18 +27,14 @@ * 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. * + * The Copyright of Hein Tibosch on this project recognises his efforts in * + * contributing to this project. The right to license the project under * + * any other terms (other than the GNU GPL license) remains with the * + * original copyright holder (James Walmsley) only. * * * - * 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. * + * Modification/Extensions/Bugfixes/Improvements to FullFAT must be sent to * + * James Walmsley for integration into the main development branch. * *****************************************************************************/ /** Index: ff_safety.c =================================================================== --- ff_safety.c (revision 58178) +++ ff_safety.c (working copy) @@ -1,7 +1,19 @@ /***************************************************************************** - * FullFAT - High Performance, Thread-Safe Embedded FAT File-System * - * Copyright (C) 2009 James Walmsley (james@worm.me.uk) * + * FullFAT - High Performance, Thread-Safe Embedded FAT File-System * * * + * Copyright(C) 2009 James Walmsley * + * Copyright(C) 2011 Hein Tibosch * + * * + * See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT. * + * * + * WARNING : COMMERCIAL PROJECTS MUST COMPLY WITH THE GNU GPL LICENSE. * + * * + * Projects that cannot comply with the GNU GPL terms are legally obliged * + * to seek alternative licensing. Contact James Walmsley for details. * + * * + ***************************************************************************** + * See http://www.fullfat-fs.co.uk/ for more information. * + ***************************************************************************** * 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 * @@ -15,20 +27,15 @@ * 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. * + * The Copyright of Hein Tibosch on this project recognises his efforts in * + * contributing to this project. The right to license the project under * + * any other terms (other than the GNU GPL license) remains with the * + * original copyright holder (James Walmsley) only. * * * - * 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. * + * Modification/Extensions/Bugfixes/Improvements to FullFAT must be sent to * + * James Walmsley for integration into the main development branch. * *****************************************************************************/ - /** * @file ff_safety.c * @author James Walmsley @@ -55,113 +62,50 @@ **/ #include "ff_safety.h" // Íncludes ff_types.h -#include -#define TAG_FULLFAT 'FLUF' - -// Call your OS's CreateSemaphore function -// void *FF_CreateSemaphore(void) { - PKSEMAPHORE ProcessSemaphore; + // Call your OS's CreateSemaphore function + // - /* Allocate some memory to store the semaphore */ - ProcessSemaphore = ExAllocatePoolWithTag(NonPagedPool, - sizeof(KSEMAPHORE), - TAG_FULLFAT); - if (ProcessSemaphore) - { - /* Initialize it */ - KeInitializeSemaphore(ProcessSemaphore, - 0, - MAXLONG); - } - - return ProcessSemaphore; + // return pointer to semaphore + return NULL; // Comment this out for your implementation. } -// Call your OS's PendSemaphore with the provided pSemaphore pointer. -// -// This should block indefinitely until the Semaphore -// becomes available. (No timeout!) -// If your OS doesn't do it for you, you should sleep -// this thread until the Semaphore is available. void FF_PendSemaphore(void *pSemaphore) { - NTSTATUS Status; - - /* Sanity check */ - if (pSemaphore) - { - /* Wait for the sempaphore to become signaled */ - Status = KeWaitForSingleObject(pSemaphore, - Executive, - KernelMode, - FALSE, - NULL); - if (NT_SUCCESS(Status)) - { - if (Status != STATUS_SUCCESS) - { - // log an error? - } - } - else - { - // log an error? - } - } + // Call your OS's PendSemaphore with the provided pSemaphore pointer. + // + // This should block indefinitely until the Semaphore + // becomes available. (No timeout!) + // If your OS doesn't do it for you, you should sleep + // this thread until the Semaphore is available. + pSemaphore = 0; } -// Call your OS's ReleaseSemaphore with the provided pSemaphore pointer. -// void FF_ReleaseSemaphore(void *pSemaphore) { + // Call your OS's ReleaseSemaphore with the provided pSemaphore pointer. + // - /* Sanity check */ - if (pSemaphore) - { - /* Increment the semaphore */ - KeReleaseSemaphore(pSemaphore, - 0, - 1, - FALSE); - } + // + pSemaphore = 0; } -// Call your OS's DestroySemaphore with the provided pSemaphore pointer. -// void FF_DestroySemaphore(void *pSemaphore) { + // Call your OS's DestroySemaphore with the provided pSemaphore pointer. + // - /* Sanity check */ - if (pSemaphore) - { - /* Free the semaphore memory */ - ExFreePoolWithTag(pSemaphore, - TAG_FULLFAT); - } + // + pSemaphore = 0; } -// FIXME: what do we do with this? void FF_Yield(void) { // Call your OS's thread Yield function. // If this doesn't work, then a deadlock will occur } -// Call your OS's thread sleep function, -// Sleep for TimeMs milliseconds void FF_Sleep(FF_T_UINT32 TimeMs) { - LARGE_INTEGER Interval; - NTSTATUS Status; - - /* Calculate the interval */ - Interval.QuadPart = -((LONGLONG)TimeMs * 10000); - - /* Do the wait */ - Status = KeDelayExecutionThread(KernelMode, - FALSE, - &Interval); - if (!NT_SUCCESS(Status)) - { - // log an error? - } + // Call your OS's thread sleep function, + // Sleep for TimeMs milliseconds + TimeMs = 0; } Index: ff_string.c =================================================================== --- ff_string.c (revision 58178) +++ ff_string.c (working copy) @@ -1,7 +1,19 @@ /***************************************************************************** - * FullFAT - High Performance, Thread-Safe Embedded FAT File-System * - * Copyright (C) 2009 James Walmsley (james@worm.me.uk) * + * FullFAT - High Performance, Thread-Safe Embedded FAT File-System * * * + * Copyright(C) 2009 James Walmsley * + * Copyright(C) 2011 Hein Tibosch * + * * + * See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT. * + * * + * WARNING : COMMERCIAL PROJECTS MUST COMPLY WITH THE GNU GPL LICENSE. * + * * + * Projects that cannot comply with the GNU GPL terms are legally obliged * + * to seek alternative licensing. Contact James Walmsley for details. * + * * + ***************************************************************************** + * See http://www.fullfat-fs.co.uk/ for more information. * + ***************************************************************************** * 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 * @@ -15,18 +27,14 @@ * 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. * + * The Copyright of Hein Tibosch on this project recognises his efforts in * + * contributing to this project. The right to license the project under * + * any other terms (other than the GNU GPL license) remains with the * + * original copyright holder (James Walmsley) only. * * * - * 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. * + * Modification/Extensions/Bugfixes/Improvements to FullFAT must be sent to * + * James Walmsley for integration into the main development branch. * *****************************************************************************/ /** @@ -403,13 +411,17 @@ pszWildCard = pszWc; pszString = pszStr++; } + + if(!*pszWildCard || !*pszString) { + break; + } } while ( *pszWildCard++ && *pszString++ ); while(*pszWildCard == '*') { pszWildCard++; } - if(!*(pszWildCard - 1)) { // WildCard is at the end. (Terminated) + if(!*pszWildCard) { // WildCard is at the end. (Terminated) return FF_TRUE; // Therefore this must be a match. } @@ -439,13 +451,17 @@ pszWildCard = pszWc; pszString = pszStr++; } - } while ( *pszWildCard++ && *pszString++ ); + if(!*pszWildCard || !*pszString) { + break; + } + } while ( *pszWildCard++ && *pszString++ ); + while(*pszWildCard == '*') { pszWildCard++; } - if(!*(pszWildCard - 1)) { // WildCard is at the end. (Terminated) + if(!*pszWildCard) { // WildCard is at the end. (Terminated) return FF_TRUE; // Therefore this must be a match. } Index: ff_time.c =================================================================== --- ff_time.c (revision 58178) +++ ff_time.c (working copy) @@ -1,7 +1,19 @@ /***************************************************************************** - * FullFAT - High Performance, Thread-Safe Embedded FAT File-System * - * Copyright (C) 2009 James Walmsley (james@worm.me.uk) * + * FullFAT - High Performance, Thread-Safe Embedded FAT File-System * * * + * Copyright(C) 2009 James Walmsley * + * Copyright(C) 2011 Hein Tibosch * + * * + * See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT. * + * * + * WARNING : COMMERCIAL PROJECTS MUST COMPLY WITH THE GNU GPL LICENSE. * + * * + * Projects that cannot comply with the GNU GPL terms are legally obliged * + * to seek alternative licensing. Contact James Walmsley for details. * + * * + ***************************************************************************** + * See http://www.fullfat-fs.co.uk/ for more information. * + ***************************************************************************** * 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 * @@ -15,18 +27,14 @@ * 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. * + * The Copyright of Hein Tibosch on this project recognises his efforts in * + * contributing to this project. The right to license the project under * + * any other terms (other than the GNU GPL license) remains with the * + * original copyright holder (James Walmsley) only. * * * - * 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. * + * Modification/Extensions/Bugfixes/Improvements to FullFAT must be sent to * + * James Walmsley for integration into the main development branch. * *****************************************************************************/ Index: ff_unaligned.c =================================================================== --- ff_unaligned.c (revision 0) +++ ff_unaligned.c (working copy) @@ -0,0 +1,59 @@ +/***************************************************************************** + * FullFAT - High Performance, Thread-Safe Embedded FAT File-System * + * * + * Copyright(C) 2009 James Walmsley * + * Copyright(C) 2011 Hein Tibosch * + * * + * See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT. * + * * + * WARNING : COMMERCIAL PROJECTS MUST COMPLY WITH THE GNU GPL LICENSE. * + * * + * Projects that cannot comply with the GNU GPL terms are legally obliged * + * to seek alternative licensing. Contact James Walmsley for details. * + * * + ***************************************************************************** + * See http://www.fullfat-fs.co.uk/ for more information. * + ***************************************************************************** + * 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 . * + * * + * The Copyright of Hein Tibosch on this project recognises his efforts in * + * contributing to this project. The right to license the project under * + * any other terms (other than the GNU GPL license) remains with the * + * original copyright holder (James Walmsley) only. * + * * + ***************************************************************************** + * Modification/Extensions/Bugfixes/Improvements to FullFAT must be sent to * + * James Walmsley for integration into the main development branch. * + *****************************************************************************/ +/* + New versions of FF_Read() and FF_Write() that are optimised for unaligned accesses. +*/ +#include "fullfat.h" + + +FF_T_SINT32 FF_Write2(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, FF_T_UINT8 *pBuffer) { + FF_ERROR Error; + + if(!pFile) { + return FF_ERR_NULL_POINTER | FF_WRITE; + } + + Error = FF_CheckValid(pFile); + if(Error) { + return Error; + } + + +} + Index: ff_unicode.c =================================================================== --- ff_unicode.c (revision 58178) +++ ff_unicode.c (working copy) @@ -1,7 +1,19 @@ /***************************************************************************** - * FullFAT - High Performance, Thread-Safe Embedded FAT File-System * - * Copyright (C) 2009 James Walmsley (james@worm.me.uk) * + * FullFAT - High Performance, Thread-Safe Embedded FAT File-System * * * + * Copyright(C) 2009 James Walmsley * + * Copyright(C) 2011 Hein Tibosch * + * * + * See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT. * + * * + * WARNING : COMMERCIAL PROJECTS MUST COMPLY WITH THE GNU GPL LICENSE. * + * * + * Projects that cannot comply with the GNU GPL terms are legally obliged * + * to seek alternative licensing. Contact James Walmsley for details. * + * * + ***************************************************************************** + * See http://www.fullfat-fs.co.uk/ for more information. * + ***************************************************************************** * 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 * @@ -15,18 +27,14 @@ * 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. * + * The Copyright of Hein Tibosch on this project recognises his efforts in * + * contributing to this project. The right to license the project under * + * any other terms (other than the GNU GPL license) remains with the * + * original copyright holder (James Walmsley) only. * * * - * 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. * + * Modification/Extensions/Bugfixes/Improvements to FullFAT must be sent to * + * James Walmsley for integration into the main development branch. * *****************************************************************************/ /** @@ -90,7 +98,7 @@ } if(!ulSize) { - return FF_ERR_UNICODE_DEST_TOO_SMALL; + return FF_ERR_UNICODE_DEST_TOO_SMALL | FF_UTF8CTOUTF16C; } switch(uiSequenceNumber) { @@ -115,7 +123,7 @@ case 4: // Convert to UTF-32 and then into UTF-16 if(ulSize < 2) { - return FF_ERR_UNICODE_DEST_TOO_SMALL; + return FF_ERR_UNICODE_DEST_TOO_SMALL | FF_UTF8CTOUTF16C; } ulUtf32char = (FF_T_UINT16) ((*utf8Source & 0x0F) << 18) | ((*(utf8Source + 1) & 0x3F) << 12) | ((*(utf8Source + 2) & 0x3F) << 6) | ((*(utf8Source + 3) & 0x3F)); @@ -144,7 +152,7 @@ FF_T_UINT16 ulUtf16char; if(!ulSize) { - return FF_ERR_UNICODE_DEST_TOO_SMALL; + return FF_ERR_UNICODE_DEST_TOO_SMALL | FF_UTF16CTOUTF8C; } memcpy(&ulUtf16char, utf16Source, sizeof(FF_T_UINT16)); @@ -154,7 +162,7 @@ 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. + return FF_ERR_UNICODE_INVALID_SEQUENCE | FF_UTF16CTOUTF8C; // Invalid UTF-16 sequence. } ulUtf32char |= ((FF_T_UINT32) (/*bobtntfullfat *(utf16Source + 1)*/ulUtf16char & 0x003FF)); @@ -170,7 +178,7 @@ if(ulUtf32char < 0x00000800) { // Double byte UTF-8 sequence. if(ulSize < 2) { - return FF_ERR_UNICODE_DEST_TOO_SMALL; + return FF_ERR_UNICODE_DEST_TOO_SMALL | FF_UTF16CTOUTF8C; } *(utf8Dest + 0) = (FF_T_UINT8) (0xC0 | ((ulUtf32char >> 6) & 0x1F)); *(utf8Dest + 1) = (FF_T_UINT8) (0x80 | ((ulUtf32char >> 0) & 0x3F)); @@ -179,7 +187,7 @@ if(ulUtf32char < 0x00010000) { // Triple byte UTF-8 sequence. if(ulSize < 3) { - return FF_ERR_UNICODE_DEST_TOO_SMALL; + return FF_ERR_UNICODE_DEST_TOO_SMALL | FF_UTF16CTOUTF8C; } *(utf8Dest + 0) = (FF_T_UINT8) (0xE0 | ((ulUtf32char >> 12) & 0x0F)); *(utf8Dest + 1) = (FF_T_UINT8) (0x80 | ((ulUtf32char >> 6 ) & 0x3F)); @@ -189,7 +197,7 @@ if(ulUtf32char < 0x00200000) { // Quadruple byte UTF-8 sequence. if(ulSize < 4) { - return FF_ERR_UNICODE_DEST_TOO_SMALL; + return FF_ERR_UNICODE_DEST_TOO_SMALL | FF_UTF16CTOUTF8C; } *(utf8Dest + 0) = (FF_T_UINT8) (0xF0 | ((ulUtf32char >> 18) & 0x07)); *(utf8Dest + 1) = (FF_T_UINT8) (0x80 | ((ulUtf32char >> 12) & 0x3F)); @@ -198,7 +206,7 @@ return 4; } - return FF_ERR_UNICODE_INVALID_CODE; // Invalid Charachter + return FF_ERR_UNICODE_INVALID_CODE | FF_UTF16CTOUTF8C; // Invalid Charachter } @@ -210,7 +218,7 @@ // 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. + return FF_ERR_UNICODE_INVALID_CODE | FF_UTF32CTOUTF16C; // Invalid charachter. } if(utf32char < 0x10000) { @@ -219,7 +227,7 @@ } if(ulSize < 2) { - return FF_ERR_UNICODE_DEST_TOO_SMALL; // Not enough UTF-16 units to record this charachter. + return FF_ERR_UNICODE_DEST_TOO_SMALL | FF_UTF32CTOUTF16C; // Not enough UTF-16 units to record this charachter. } if(utf32char < 0x00200000) { @@ -232,7 +240,7 @@ return 2; // Surrogate pair encoded value. } - return FF_ERR_UNICODE_INVALID_CODE; // Invalid Charachter + return FF_ERR_UNICODE_INVALID_CODE | FF_UTF32CTOUTF16C; // Invalid Charachter } // Converts a UTF-16 sequence into its equivalent UTF-32 code point. @@ -246,7 +254,7 @@ *utf32Dest = ((FF_T_UINT32) (*(utf16Source + 0) & 0x003FF) << 10) + 0x10000; if((*(utf16Source + 1) & 0xFC00) != 0xDC00) { - return FF_ERR_UNICODE_INVALID_SEQUENCE; // Invalid UTF-16 sequence. + return FF_ERR_UNICODE_INVALID_SEQUENCE | FF_UTF16CTOUTF32C; // Invalid UTF-16 sequence. } *utf32Dest |= ((FF_T_UINT32) (*(utf16Source + 1) & 0x003FF)); return 2; // 2 utf-16 units make up the Unicode code-point.