Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenff_dir.c
Go to the documentation of this file.
00001 /***************************************************************************** 00002 * FullFAT - High Performance, Thread-Safe Embedded FAT File-System * 00003 * Copyright (C) 2009 James Walmsley (james@worm.me.uk) * 00004 * * 00005 * This program is free software: you can redistribute it and/or modify * 00006 * it under the terms of the GNU General Public License as published by * 00007 * the Free Software Foundation, either version 3 of the License, or * 00008 * (at your option) any later version. * 00009 * * 00010 * This program is distributed in the hope that it will be useful, * 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00013 * GNU General Public License for more details. * 00014 * * 00015 * You should have received a copy of the GNU General Public License * 00016 * along with this program. If not, see <http://www.gnu.org/licenses/>. * 00017 * * 00018 * IMPORTANT NOTICE: * 00019 * ================= * 00020 * Alternative Licensing is available directly from the Copyright holder, * 00021 * (James Walmsley). For more information consult LICENSING.TXT to obtain * 00022 * a Commercial license. * 00023 * * 00024 * See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT. * 00025 * * 00026 * Removing the above notice is illegal and will invalidate this license. * 00027 ***************************************************************************** 00028 * See http://worm.me.uk/fullfat for more information. * 00029 * Or http://fullfat.googlecode.com/ for latest releases and the wiki. * 00030 *****************************************************************************/ 00031 00043 #include "ff_dir.h" 00044 #include "ff_string.h" 00045 #include "ff_unicode.h" 00046 #include <stdio.h> 00047 00048 00049 #ifdef FF_UNICODE_SUPPORT 00050 #include <wchar.h> 00051 #endif 00052 00053 #ifdef WIN32 00054 #else 00055 #include <ctype.h> // tolower() 00056 int strcasecmp(const char *s1, const char *s2) 00057 { 00058 unsigned char c1,c2; 00059 do { 00060 c1 = *s1++; 00061 c2 = *s2++; 00062 c1 = (unsigned char) tolower( (unsigned char) c1); 00063 c2 = (unsigned char) tolower( (unsigned char) c2); 00064 } 00065 while((c1 == c2) && (c1 != '\0')); 00066 return (int) c1-c2; 00067 } 00068 #endif 00069 00070 00071 #ifdef FF_UNICODE_SUPPORT 00072 static void FF_ProcessShortName(FF_T_WCHAR *name); 00073 #else 00074 static void FF_ProcessShortName(FF_T_INT8 *name); 00075 #endif 00076 00077 void FF_lockDIR(FF_IOMAN *pIoman) { 00078 FF_PendSemaphore(pIoman->pSemaphore); // Use Semaphore to protect DIR modifications. 00079 { 00080 while((pIoman->Locks & FF_DIR_LOCK)) { 00081 FF_ReleaseSemaphore(pIoman->pSemaphore); 00082 FF_Yield(); // Keep Releasing and Yielding until we have the DIR protector. 00083 FF_PendSemaphore(pIoman->pSemaphore); 00084 } 00085 pIoman->Locks |= FF_DIR_LOCK; 00086 } 00087 FF_ReleaseSemaphore(pIoman->pSemaphore); 00088 } 00089 00090 void FF_unlockDIR(FF_IOMAN *pIoman) { 00091 FF_PendSemaphore(pIoman->pSemaphore); 00092 { 00093 pIoman->Locks &= ~FF_DIR_LOCK; 00094 } 00095 FF_ReleaseSemaphore(pIoman->pSemaphore); 00096 } 00097 00098 static FF_T_UINT8 FF_CreateChkSum(const FF_T_UINT8 *pa_pShortName) { 00099 FF_T_UINT8 cNameLen; 00100 FF_T_UINT8 ChkSum = 0; 00101 00102 for(cNameLen = 11; cNameLen != 0; cNameLen--) { 00103 ChkSum = ((ChkSum & 1) ? 0x80 : 0) + (ChkSum >> 1) + *pa_pShortName++; 00104 } 00105 return ChkSum; 00106 } 00107 00108 00109 FF_ERROR FF_FindNextInDir(FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_FETCH_CONTEXT *pFetchContext) { 00110 00111 FF_T_UINT8 numLFNs; 00112 FF_T_UINT8 EntryBuffer[32]; 00113 FF_ERROR Error; 00114 00115 if(!pIoman) { 00116 return FF_ERR_NULL_POINTER; 00117 } 00118 00119 for(; pDirent->CurrentItem < 0xFFFF; pDirent->CurrentItem += 1) { 00120 00121 Error = FF_FetchEntryWithContext(pIoman, pDirent->CurrentItem, pFetchContext, EntryBuffer); 00122 00123 if(Error) { 00124 return Error; 00125 } 00126 00127 if(EntryBuffer[0] != 0xE5) { 00128 if(FF_isEndOfDir(EntryBuffer)){ 00129 return FF_ERR_DIR_END_OF_DIR; 00130 } 00131 pDirent->Attrib = FF_getChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB)); 00132 if((pDirent->Attrib & FF_FAT_ATTR_LFN) == FF_FAT_ATTR_LFN) { 00133 // LFN Processing 00134 numLFNs = (FF_T_UINT8)(EntryBuffer[0] & ~0x40); 00135 //pDirent->NumLFNs = numLFNs; 00136 #ifdef FF_LFN_SUPPORT 00137 Error = FF_PopulateLongDirent(pIoman, pDirent, pDirent->CurrentItem, pFetchContext); 00138 if(Error) { 00139 return Error; 00140 } 00141 return FF_ERR_NONE; 00142 #else 00143 pDirent->CurrentItem += (numLFNs - 1); 00144 #endif 00145 } else if((pDirent->Attrib & FF_FAT_ATTR_VOLID) == FF_FAT_ATTR_VOLID) { 00146 // Do Nothing 00147 00148 } else { 00149 FF_PopulateShortDirent(pIoman, pDirent, EntryBuffer); 00150 pDirent->CurrentItem += 1; 00151 return FF_ERR_NONE; 00152 } 00153 } 00154 } 00155 00156 return FF_ERR_DIR_END_OF_DIR; 00157 } 00158 00159 #ifdef FF_UNICODE_SUPPORT 00160 static FF_T_BOOL FF_ShortNameExists(FF_IOMAN *pIoman, FF_T_UINT32 ulDirCluster, FF_T_WCHAR *szShortName, FF_ERROR *pError) { 00161 #else 00162 static FF_T_BOOL FF_ShortNameExists(FF_IOMAN *pIoman, FF_T_UINT32 ulDirCluster, FF_T_INT8 *szShortName, FF_ERROR *pError) { 00163 #endif 00164 00165 FF_T_UINT16 i; 00166 FF_T_UINT8 EntryBuffer[32]; 00167 FF_T_UINT8 Attrib; 00168 FF_FETCH_CONTEXT FetchContext; 00169 00170 #ifdef FF_UNICODE_SUPPORT 00171 FF_T_WCHAR UTF16EntryBuffer[32]; 00172 #endif 00173 00174 #ifdef FF_HASH_CACHE 00175 FF_T_UINT32 ulHash; 00176 #endif 00177 00178 *pError = FF_ERR_NONE; 00179 00180 00181 #ifdef FF_HASH_CACHE 00182 if(!FF_DirHashed(pIoman, ulDirCluster)) { 00183 // Hash the directory 00184 FF_HashDir(pIoman, ulDirCluster); 00185 } 00186 00187 #if FF_HASH_FUNCTION == CRC16 00188 ulHash = (FF_T_UINT32) FF_GetCRC16((FF_T_UINT8 *) szShortName, strlen(szShortName)); 00189 #elif FF_HASH_FUNCTION == CRC8 00190 ulHash = (FF_T_UINT32) FF_GetCRC8((FF_T_UINT8 *) szShortName, strlen(szShortName)); 00191 #endif 00192 00193 if(!FF_CheckDirentHash(pIoman, ulDirCluster, ulHash)) { 00194 return FF_FALSE; 00195 } 00196 00197 #endif 00198 00199 *pError = FF_InitEntryFetch(pIoman, ulDirCluster, &FetchContext); 00200 if(*pError) { 00201 return FF_FALSE; 00202 } 00203 00204 for(i = 0; i < 0xFFFF; i++) { 00205 *pError = FF_FetchEntryWithContext(pIoman, i, &FetchContext, EntryBuffer); 00206 if(*pError) { 00207 FF_CleanupEntryFetch(pIoman, &FetchContext); 00208 return FF_FALSE; 00209 } 00210 Attrib = FF_getChar(EntryBuffer, FF_FAT_DIRENT_ATTRIB); 00211 if(FF_getChar(EntryBuffer, 0x00) != 0xE5) { 00212 if(Attrib != FF_FAT_ATTR_LFN) { 00213 #ifdef FF_UNICODE_SUPPORT 00214 // Convert Entry Buffer into UTF16 00215 FF_cstrntowcs(UTF16EntryBuffer, (FF_T_INT8 *) EntryBuffer, 32); 00216 FF_ProcessShortName(UTF16EntryBuffer); 00217 #else 00218 FF_ProcessShortName((FF_T_INT8 *)EntryBuffer); 00219 #endif 00220 if(FF_isEndOfDir(EntryBuffer)) { 00221 FF_CleanupEntryFetch(pIoman, &FetchContext); 00222 return FF_FALSE; 00223 } 00224 #ifdef FF_UNICODE_SUPPORT 00225 if(wcscmp(szShortName, UTF16EntryBuffer) == 0) { 00226 #else 00227 if(strcmp(szShortName, (FF_T_INT8 *)EntryBuffer) == 0) { 00228 #endif 00229 FF_CleanupEntryFetch(pIoman, &FetchContext); 00230 return FF_TRUE; 00231 } 00232 } 00233 } 00234 } 00235 00236 FF_CleanupEntryFetch(pIoman, &FetchContext); 00237 return FF_FALSE; 00238 } 00239 00240 00241 #ifdef FF_UNICODE_SUPPORT 00242 FF_T_UINT32 FF_FindEntryInDir(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, const FF_T_WCHAR *name, FF_T_UINT8 pa_Attrib, FF_DIRENT *pDirent, FF_ERROR *pError) { 00243 #else 00244 FF_T_UINT32 FF_FindEntryInDir(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, const FF_T_INT8 *name, FF_T_UINT8 pa_Attrib, FF_DIRENT *pDirent, FF_ERROR *pError) { 00245 #endif 00246 00247 FF_FETCH_CONTEXT FetchContext; 00248 FF_T_UINT8 *src; // Pointer to read from pBuffer 00249 FF_T_UINT8 *lastSrc; 00250 #ifdef FF_UNICODE_UTF8_SUPPORT 00251 FF_T_SINT32 utf8Error; 00252 FF_T_UINT8 bSurrogate = FF_FALSE; 00253 #endif 00254 #ifdef FF_UNICODE_SUPPORT 00255 FF_T_WCHAR *ptr; // Pointer to store a LFN 00256 #else 00257 FF_T_INT8 *ptr; // Pointer to store a LFN 00258 #endif 00259 #ifdef FF_UNICODE_SUPPORT 00260 FF_T_WCHAR *lastPtr = pDirent->FileName + sizeof(pDirent->FileName); 00261 #else 00262 FF_T_INT8 *lastPtr = pDirent->FileName + sizeof(pDirent->FileName); 00263 #endif 00264 FF_T_UINT8 CheckSum = 0; 00265 FF_T_UINT8 lastAttrib; 00266 FF_T_INT8 totalLFNs = 0; 00267 FF_T_INT8 numLFNs = 0; 00268 FF_T_INT32 i; 00269 FF_T_UINT16 lfnItem = 0; 00270 00271 pError = NULL; 00272 00273 pDirent->CurrentItem = 0; 00274 pDirent->Attrib = 0; 00275 00276 FF_InitEntryFetch(pIoman, DirCluster, &FetchContext); 00277 00278 while(pDirent->CurrentItem < 0xFFFF) { 00279 if (FF_FetchEntryWithContext(pIoman, pDirent->CurrentItem, &FetchContext, NULL)) { 00280 break; 00281 } 00282 lastSrc = FetchContext.pBuffer->pBuffer + pIoman->BlkSize; 00283 for (src = FetchContext.pBuffer->pBuffer; src < lastSrc; src += 32, pDirent->CurrentItem++) { 00284 if (FF_isEndOfDir(src)) { // 0x00: end-of-dir 00285 FF_CleanupEntryFetch(pIoman, &FetchContext); 00286 return 0; 00287 } 00288 if (src[0] == 0xE5) { // Entry not used 00289 pDirent->Attrib = 0; 00290 continue; 00291 } 00292 lastAttrib = pDirent->Attrib; 00293 pDirent->Attrib = FF_getChar(src, FF_FAT_DIRENT_ATTRIB); 00294 if((pDirent->Attrib & FF_FAT_ATTR_LFN) == FF_FAT_ATTR_LFN) { 00295 // LFN Processing 00296 #ifdef FF_LFN_SUPPORT 00297 if (numLFNs == 0 || (lastAttrib & FF_FAT_ATTR_LFN) != FF_FAT_ATTR_LFN) { 00298 totalLFNs = numLFNs = (FF_T_UINT8)(src[0] & ~0x40); 00299 lfnItem = pDirent->CurrentItem; 00300 CheckSum = FF_getChar(src, FF_FAT_LFN_CHECKSUM); 00301 lastPtr[-1] = '\0'; 00302 } 00303 if (numLFNs) { 00304 numLFNs--; 00305 ptr = pDirent->FileName + (numLFNs * 13); 00306 00307 /* 00308 This section needs to extract the name and do the comparison 00309 dependent on UNICODE settings in the ff_config.h file. 00310 */ 00311 #ifdef FF_UNICODE_SUPPORT 00312 // Add UTF-16 Routine here 00313 memcpy(ptr, &src[FF_FAT_LFN_NAME_1], 10); // Copy first 5 UTF-16 chars (10 bytes). 00314 ptr += 5; // Increment Filename pointer 5 utf16 chars. 00315 00316 memcpy(ptr, &src[FF_FAT_LFN_NAME_2], 12); //Copy next 6 chars (12 bytes). 00317 ptr += 6; 00318 00319 memcpy(ptr, &src[FF_FAT_LFN_NAME_3], 4); // You're getting the idea by now! 00320 ptr += 2; 00321 00322 #endif 00323 #ifdef FF_UNICODE_UTF8_SUPPORT 00324 // UTF-8 Routine here 00325 for(i = 0; i < 5 && ptr < lastPtr; i++) { 00326 // Was there a surrogate sequence? -- Add handling here. 00327 utf8Error = FF_Utf16ctoUtf8c((FF_T_UINT8 *) ptr, (FF_T_UINT16 *) &src[FF_FAT_LFN_NAME_1 + (2*i)], lastPtr - ptr); 00328 if(utf8Error > 0) { 00329 ptr += utf8Error; 00330 00331 } else { 00332 if(utf8Error == FF_ERR_UNICODE_INVALID_SEQUENCE) { 00333 // Handle potential surrogate sequence across entries. 00334 00335 } 00336 } 00337 } 00338 00339 for(i = 0; i < 6 && ptr < lastPtr; i++) { 00340 // Was there a surrogate sequence? -- To add handling here. 00341 utf8Error = FF_Utf16ctoUtf8c((FF_T_UINT8 *) ptr, (FF_T_UINT16 *) &src[FF_FAT_LFN_NAME_2 + (2*i)], lastPtr - ptr); 00342 if(utf8Error > 0) { 00343 ptr += utf8Error; 00344 } else { 00345 if(utf8Error == FF_ERR_UNICODE_INVALID_SEQUENCE) { 00346 // Handle potential surrogate sequence across entries. 00347 } 00348 } 00349 } 00350 00351 for(i = 0; i < 2 && ptr < lastPtr; i++) { 00352 // Was there a surrogate sequence? -- To add handling here. 00353 utf8Error = FF_Utf16ctoUtf8c((FF_T_UINT8 *) ptr, (FF_T_UINT16 *) &src[FF_FAT_LFN_NAME_3 + (2*i)], lastPtr - ptr); 00354 if(utf8Error > 0) { 00355 ptr += utf8Error; 00356 } else { 00357 if(utf8Error == FF_ERR_UNICODE_INVALID_SEQUENCE) { 00358 // Handle potential surrogate sequence across entries. 00359 } 00360 } 00361 } 00362 00363 #endif 00364 #ifndef FF_UNICODE_SUPPORT 00365 #ifndef FF_UNICODE_UTF8_SUPPORT 00366 for(i = 0; i < 10 && ptr < lastPtr; i += 2) 00367 *(ptr++) = src[FF_FAT_LFN_NAME_1 + i]; 00368 00369 for(i = 0; i < 12 && ptr < lastPtr; i += 2) 00370 *(ptr++) = src[FF_FAT_LFN_NAME_2 + i]; 00371 00372 for(i = 0; i < 4 && ptr < lastPtr; i += 2) 00373 *(ptr++) = src[FF_FAT_LFN_NAME_3 + i]; 00374 00375 if (numLFNs == totalLFNs-1 && ptr < lastPtr) 00376 *ptr = '\0'; // Important when name len is multiple of 13 00377 #endif 00378 #endif 00379 if (numLFNs == totalLFNs-1 && ptr < lastPtr) 00380 *ptr = '\0'; // Important when name len is multiple of 13 00381 00382 } 00383 #endif 00384 continue; 00385 } 00386 if ((pDirent->Attrib & FF_FAT_ATTR_VOLID) == FF_FAT_ATTR_VOLID) { 00387 totalLFNs = 0; 00388 continue; 00389 } 00390 #ifdef FF_LFN_SUPPORT 00391 if(!totalLFNs || CheckSum != FF_CreateChkSum(src)) 00392 #endif 00393 { 00394 #ifdef FF_UNICODE_SUPPORT 00395 for(i = 0; i < 11; i++) { 00396 pDirent->FileName[i] = (FF_T_WCHAR) src[i]; 00397 } 00398 FF_ProcessShortName(pDirent->FileName); 00399 #else 00400 memcpy(pDirent->FileName, src, 11); 00401 FF_ProcessShortName(pDirent->FileName); 00402 #endif 00403 totalLFNs = 0; 00404 } 00405 00406 if((pDirent->Attrib & pa_Attrib) == pa_Attrib){ 00407 #ifdef FF_UNICODE_SUPPORT 00408 if(!wcsicmp(name, pDirent->FileName)) { 00409 #else 00410 if (!FF_stricmp(name, pDirent->FileName)) { 00411 #endif 00412 // Finally get the complete information 00413 #ifdef FF_LFN_SUPPORT 00414 if (totalLFNs) { 00415 FF_PopulateLongDirent(pIoman, pDirent, lfnItem, &FetchContext); 00416 } else 00417 #endif 00418 { 00419 FF_PopulateShortDirent(pIoman, pDirent, src); 00420 } 00421 // Object found! 00422 FF_CleanupEntryFetch(pIoman, &FetchContext); 00423 return pDirent->ObjectCluster; // Return the cluster number 00424 } 00425 } 00426 totalLFNs = 0; 00427 } 00428 } // for (src = FetchContext.pBuffer->pBuffer; src < lastSrc; src += 32, pDirent->CurrentItem++) 00429 00430 FF_CleanupEntryFetch(pIoman, &FetchContext); 00431 00432 return 0; 00433 } 00434 00435 00436 00440 #ifdef FF_UNICODE_SUPPORT 00441 FF_T_UINT32 FF_FindDir(FF_IOMAN *pIoman, const FF_T_WCHAR *path, FF_T_UINT16 pathLen, FF_ERROR *pError) { 00442 #else 00443 FF_T_UINT32 FF_FindDir(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT16 pathLen, FF_ERROR *pError) { 00444 #endif 00445 FF_T_UINT32 dirCluster = pIoman->pPartition->RootDirCluster; 00446 #ifdef FF_UNICODE_SUPPORT 00447 FF_T_WCHAR mytoken[FF_MAX_FILENAME]; 00448 FF_T_WCHAR *token; 00449 #else 00450 FF_T_INT8 mytoken[FF_MAX_FILENAME]; 00451 FF_T_INT8 *token; 00452 #endif 00453 00454 FF_T_UINT16 it = 0; // Re-entrancy Variables for FF_strtok() 00455 FF_T_BOOL last = FF_FALSE; 00456 FF_DIRENT MyDir; 00457 #ifdef FF_PATH_CACHE 00458 FF_T_UINT32 i; 00459 #endif 00460 00461 *pError = FF_ERR_NONE; 00462 00463 if(pathLen <= 1) { // Must be the root dir! (/ or \) 00464 return pIoman->pPartition->RootDirCluster; 00465 } 00466 00467 if(path[pathLen-1] == '\\' || path[pathLen-1] == '/') { 00468 pathLen--; 00469 } 00470 00471 #ifdef FF_PATH_CACHE // Is the requested path in the PATH CACHE? 00472 FF_PendSemaphore(pIoman->pSemaphore); // Thread safety on shared object! 00473 { 00474 for(i = 0; i < FF_PATH_CACHE_DEPTH; i++) { 00475 #ifdef FF_UNICODE_SUPPORT 00476 if(wcslen(pIoman->pPartition->PathCache[i].Path) == pathLen) { 00477 if(FF_strmatch(pIoman->pPartition->PathCache[i].Path, path, pathLen)) { 00478 #else 00479 if(strlen(pIoman->pPartition->PathCache[i].Path) == pathLen) { 00480 if(FF_strmatch(pIoman->pPartition->PathCache[i].Path, path, pathLen)) { 00481 #endif 00482 00483 FF_ReleaseSemaphore(pIoman->pSemaphore); 00484 return pIoman->pPartition->PathCache[i].DirCluster; 00485 } 00486 } 00487 } 00488 } 00489 FF_ReleaseSemaphore(pIoman->pSemaphore); 00490 #endif 00491 00492 token = FF_strtok(path, mytoken, &it, &last, pathLen); 00493 00494 do{ 00495 MyDir.CurrentItem = 0; 00496 dirCluster = FF_FindEntryInDir(pIoman, dirCluster, token, FF_FAT_ATTR_DIR, &MyDir, pError); 00497 00498 if(*pError) { 00499 return 0; 00500 } 00501 00502 /*if(dirCluster == 0 && MyDir.CurrentItem == 2 && MyDir.FileName[0] == '.') { // .. Dir Entry pointing to root dir. 00503 dirCluster = pIoman->pPartition->RootDirCluster; 00504 }*/ 00505 token = FF_strtok(path, mytoken, &it, &last, pathLen); 00506 }while(token != NULL); 00507 00508 #ifdef FF_PATH_CACHE // Update the PATH CACHE with a new PATH 00509 if(dirCluster) { // Only cache if the dir was actually found! 00510 FF_PendSemaphore(pIoman->pSemaphore); 00511 { 00512 if(pathLen < FF_MAX_PATH) { // Ensure the PATH won't cause a buffer overrun. 00513 #ifdef FF_UNICODE_SUPPORT 00514 memcpy(pIoman->pPartition->PathCache[pIoman->pPartition->PCIndex].Path, path, pathLen * sizeof(FF_T_WCHAR)); 00515 #else 00516 memcpy(pIoman->pPartition->PathCache[pIoman->pPartition->PCIndex].Path, path, pathLen); 00517 #endif 00518 pIoman->pPartition->PathCache[pIoman->pPartition->PCIndex].Path[pathLen] = '\0'; 00519 pIoman->pPartition->PathCache[pIoman->pPartition->PCIndex].DirCluster = dirCluster; 00520 #ifdef FF_HASH_TABLE_SUPPORT 00521 FF_ClearHashTable(pIoman->pPartition->PathCache[pIoman->pPartition->PCIndex].pHashTable); 00522 #endif 00523 pIoman->pPartition->PCIndex += 1; 00524 if(pIoman->pPartition->PCIndex >= FF_PATH_CACHE_DEPTH) { 00525 pIoman->pPartition->PCIndex = 0; 00526 } 00527 } 00528 } 00529 FF_ReleaseSemaphore(pIoman->pSemaphore); 00530 } 00531 #endif 00532 00533 return dirCluster; 00534 } 00535 00536 00537 #if defined(FF_SHORTNAME_CASE) 00538 00543 #ifdef FF_UNICODE_SUPPORT 00544 static void FF_CaseShortName(FF_T_WCHAR *name, FF_T_UINT8 attrib) { 00545 #else 00546 static void FF_CaseShortName(FF_T_INT8 *name, FF_T_UINT8 attrib) { 00547 #endif 00548 FF_T_UINT8 testAttrib = FF_FAT_CASE_ATTR_BASE; 00549 for (; *name; name++) { 00550 if (*name == '.') { 00551 testAttrib = FF_FAT_CASE_ATTR_EXT; 00552 } else if ((attrib & testAttrib)) { 00553 if (*name >= 'A' && *name <= 'Z') 00554 *name += 0x20; 00555 } else if (*name >= 'a' && *name <= 'z') { 00556 *name -= 0x20; 00557 } 00558 } 00559 } 00560 #endif 00561 00566 #ifdef FF_UNICODE_SUPPORT 00567 static void FF_ProcessShortName(FF_T_WCHAR *name) { 00568 FF_T_WCHAR shortName[13]; 00569 FF_T_WCHAR *ptr = name; 00570 #else 00571 static void FF_ProcessShortName(FF_T_INT8 *name) { 00572 FF_T_INT8 shortName[13]; 00573 FF_T_INT8 *ptr = name; 00574 #endif 00575 FF_T_UINT8 i; 00576 #ifdef FF_UNICODE_SUPPORT 00577 memcpy(shortName, name, 11 * sizeof(FF_T_WCHAR)); 00578 #else 00579 memcpy(shortName, name, 11); 00580 #endif 00581 00582 for(i = 0; i < 11; i++) { 00583 if(shortName[i] == 0x20) { 00584 if (i >= 8) 00585 break; 00586 i = 7; 00587 } else { 00588 if (i == 8) 00589 *(ptr++) = '.'; 00590 *(ptr++) = shortName[i]; 00591 } 00592 } 00593 *ptr = '\0'; 00594 } 00595 00596 /* 00597 #ifdef FF_UNICODE_SUPPORT 00598 static void FF_ProcessShortName(FF_T_WCHAR *name) { 00599 FF_T_WCHAR shortName[13]; 00600 #else 00601 static void FF_ProcessShortName(FF_T_INT8 *name) { 00602 FF_T_INT8 shortName[13]; 00603 #endif 00604 00605 FF_T_UINT8 i; 00606 #ifdef FF_UNICODE_SUPPORT 00607 memcpy(shortName, name, 11 * sizeof(FF_T_WCHAR)); 00608 #else 00609 memcpy(shortName, name, 11); 00610 #endif 00611 00612 for(i = 0; i < 8; i++) { 00613 if(shortName[i] == 0x20) { 00614 name[i] = '\0'; 00615 break; 00616 } 00617 name[i] = shortName[i]; 00618 } 00619 00620 if(shortName[8] != 0x20){ 00621 name[i] = '.'; 00622 name[i+1] = shortName[8]; 00623 name[i+2] = shortName[9]; 00624 name[i+3] = shortName[10]; 00625 name[i+4] = '\0'; 00626 for(i = 0; i < 11; i++) { 00627 if(name[i] == 0x20) { 00628 name[i] = '\0'; 00629 break; 00630 } 00631 } 00632 } else { 00633 name[i] = '\0'; 00634 } 00635 00636 }*/ 00637 00638 #ifdef FF_TIME_SUPPORT 00639 static void FF_PlaceTime(FF_T_UINT8 *EntryBuffer, FF_T_UINT32 Offset) { 00640 FF_T_UINT16 myShort; 00641 FF_SYSTEMTIME str_t; 00642 00643 FF_GetSystemTime(&str_t); 00644 00645 myShort = 0; 00646 myShort |= ((str_t.Hour << 11) & 0xF800); 00647 myShort |= ((str_t.Minute << 5) & 0x07E0); 00648 myShort |= ((str_t.Second / 2) & 0x001F); 00649 FF_putShort(EntryBuffer, (FF_T_UINT16) Offset, myShort); 00650 } 00651 00652 static void FF_PlaceDate(FF_T_UINT8 *EntryBuffer, FF_T_UINT32 Offset) { 00653 FF_T_UINT16 myShort; 00654 FF_SYSTEMTIME str_t; 00655 00656 FF_GetSystemTime(&str_t); 00657 00658 myShort = 0; 00659 myShort |= (((str_t.Year- 1980) << 9) & 0xFE00) ; 00660 myShort |= ((str_t.Month << 5) & 0x01E0); 00661 myShort |= (str_t.Day & 0x001F); 00662 FF_putShort(EntryBuffer, (FF_T_UINT16) Offset, myShort); 00663 } 00664 00665 00666 static void FF_GetTime(FF_SYSTEMTIME *pTime, FF_T_UINT8 *EntryBuffer, FF_T_UINT32 Offset) { 00667 FF_T_UINT16 myShort; 00668 myShort = FF_getShort(EntryBuffer, (FF_T_UINT16) Offset); 00669 pTime->Hour = (((myShort & 0xF800) >> 11) & 0x001F); 00670 pTime->Minute = (((myShort & 0x07E0) >> 5) & 0x003F); 00671 pTime->Second = 2 * (myShort & 0x01F); 00672 } 00673 00674 static void FF_GetDate(FF_SYSTEMTIME *pTime, FF_T_UINT8 *EntryBuffer, FF_T_UINT32 Offset) { 00675 FF_T_UINT16 myShort; 00676 myShort = FF_getShort(EntryBuffer, (FF_T_UINT16) Offset); 00677 pTime->Year = 1980 + (((myShort & 0xFE00) >> 9) & 0x07F); 00678 pTime->Month = (((myShort & 0x01E0) >> 5) & 0x000F); 00679 pTime->Day = myShort & 0x01F; 00680 } 00681 #endif 00682 00683 void FF_PopulateShortDirent(FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_T_UINT8 *EntryBuffer) { 00684 FF_T_UINT16 myShort; 00685 #ifdef FF_UNICODE_SUPPORT 00686 FF_T_WCHAR UTF16EntryBuffer[12]; 00687 FF_cstrntowcs(UTF16EntryBuffer, (FF_T_INT8 *) EntryBuffer, 11); 00688 memcpy(pDirent->FileName, UTF16EntryBuffer, 11 * sizeof(FF_T_WCHAR)); 00689 #else 00690 memcpy(pDirent->FileName, EntryBuffer, 11); // Copy the filename into the Dirent object. 00691 #endif 00692 #if defined(FF_LFN_SUPPORT) && defined(FF_INCLUDE_SHORT_NAME) 00693 memcpy(pDirent->ShortName, EntryBuffer, 11); 00694 pDirent->ShortName[11] = '\0'; 00695 FF_ProcessShortName(pDirent->ShortName); // Format the shortname, for pleasant viewing. 00696 00697 #endif 00698 FF_ProcessShortName(pDirent->FileName); // Format the shortname, for pleasant viewing. 00699 00700 #ifdef FF_HASH_TABLE_SUPPORT 00701 /*#if FF_HASH_FUNCTION == CRC16 00702 FF_AddDirentHash(pIoman, pDirent->DirCluster, (FF_T_UINT32)FF_GetCRC16((FF_T_UINT8 *) pDirent->FileName, strlen(pDirent->FileName))); 00703 #elif FF_HASH_FUNCTION == CRC8 00704 FF_AddDirentHash(pIoman, pDirent->DirCluster, (FF_T_UINT32)FF_GetCRC8((FF_T_UINT8 *) pDirent->FileName, strlen(pDirent->FileName))); 00705 #endif*/ 00706 #else 00707 pIoman = NULL; // Silence a compiler warning, about not referencing pIoman. 00708 #endif 00709 00710 #ifdef FF_UNICODE_SUPPORT 00711 FF_tolower(pDirent->FileName, (FF_T_UINT32)wcslen(pDirent->FileName)); 00712 #else 00713 FF_tolower(pDirent->FileName, (FF_T_UINT32)strlen(pDirent->FileName)); 00714 #endif 00715 00716 // Get the item's Cluster address. 00717 myShort = FF_getShort(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_HIGH)); 00718 pDirent->ObjectCluster = (FF_T_UINT32) (myShort << 16); 00719 myShort = FF_getShort(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_LOW)); 00720 pDirent->ObjectCluster |= myShort; 00721 #ifdef FF_TIME_SUPPORT 00722 // Get the creation Time & Date 00723 FF_GetTime(&pDirent->CreateTime, EntryBuffer, FF_FAT_DIRENT_CREATE_TIME); 00724 FF_GetDate(&pDirent->CreateTime, EntryBuffer, FF_FAT_DIRENT_CREATE_DATE); 00725 // Get the modified Time & Date 00726 FF_GetTime(&pDirent->CreateTime, EntryBuffer, FF_FAT_DIRENT_LASTMOD_TIME); 00727 FF_GetDate(&pDirent->CreateTime, EntryBuffer, FF_FAT_DIRENT_LASTMOD_DATE); 00728 // Get the last accessed Date. 00729 FF_GetDate(&pDirent->AccessedTime, EntryBuffer, FF_FAT_DIRENT_LASTACC_DATE); 00730 pDirent->AccessedTime.Hour = 0; 00731 pDirent->AccessedTime.Minute = 0; 00732 pDirent->AccessedTime.Second = 0; 00733 #endif 00734 // Get the filesize. 00735 pDirent->Filesize = FF_getLong(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_FILESIZE)); 00736 // Get the attribute. 00737 pDirent->Attrib = FF_getChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB)); 00738 } 00739 00740 /* 00741 Initialises a context object for FF_FetchEntryWithContext() 00742 */ 00743 FF_ERROR FF_InitEntryFetch(FF_IOMAN *pIoman, FF_T_UINT32 ulDirCluster, FF_FETCH_CONTEXT *pContext) { 00744 00745 FF_ERROR Error; 00746 00747 memset(pContext, 0, sizeof(FF_FETCH_CONTEXT)); 00748 00749 pContext->ulChainLength = FF_GetChainLength(pIoman, ulDirCluster, NULL, &Error); // Get the total length of the chain. 00750 if(Error) { 00751 return Error; 00752 } 00753 pContext->ulDirCluster = ulDirCluster; 00754 pContext->ulCurrentClusterLCN = ulDirCluster; 00755 pContext->ulCurrentClusterNum = 0; 00756 pContext->ulCurrentEntry = 0; 00757 00758 if(pIoman->pPartition->Type != FF_T_FAT32) { 00759 // Handle Root Dirs that don't have cluster chains! 00760 if(pContext->ulDirCluster == pIoman->pPartition->RootDirCluster) { 00761 // This is a RootDIR, special consideration needs to be made, because it doesn't have a Cluster chain! 00762 pContext->ulChainLength = pIoman->pPartition->RootDirSectors / pIoman->pPartition->SectorsPerCluster; 00763 if(!pContext->ulChainLength) { // Some media has RootDirSectors < SectorsPerCluster. This is wrong, as it should be atleast 1 cluster! 00764 pContext->ulChainLength = 1; 00765 } 00766 } 00767 } 00768 00769 return FF_ERR_NONE; 00770 } 00771 00772 void FF_CleanupEntryFetch(FF_IOMAN *pIoman, FF_FETCH_CONTEXT *pContext) { 00773 if(pContext->pBuffer) { 00774 FF_ReleaseBuffer(pIoman, pContext->pBuffer); 00775 pContext->pBuffer = NULL; 00776 } 00777 } 00778 00779 FF_ERROR FF_FetchEntryWithContext(FF_IOMAN *pIoman, FF_T_UINT32 ulEntry, FF_FETCH_CONTEXT *pContext, FF_T_UINT8 *pEntryBuffer) { 00780 00781 FF_T_UINT32 ulItemLBA; 00782 FF_T_UINT32 ulRelItem; 00783 FF_T_UINT32 ulClusterNum; 00784 FF_ERROR Error; 00785 00786 ulClusterNum = FF_getClusterChainNumber(pIoman, ulEntry, (FF_T_UINT16)32); 00787 ulRelItem = FF_getMinorBlockEntry (pIoman, ulEntry, (FF_T_UINT16)32); 00788 00789 if(ulClusterNum != pContext->ulCurrentClusterNum) { 00790 // Traverse the fat gently! 00791 if(ulClusterNum > pContext->ulCurrentClusterNum) { 00792 pContext->ulCurrentClusterLCN = FF_TraverseFAT(pIoman, pContext->ulCurrentClusterLCN, (ulClusterNum - pContext->ulCurrentClusterNum), &Error); 00793 if(Error) { 00794 return Error; 00795 } 00796 } else { 00797 pContext->ulCurrentClusterLCN = FF_TraverseFAT(pIoman, pContext->ulDirCluster, ulClusterNum, &Error); 00798 if(Error) { 00799 return Error; 00800 } 00801 } 00802 pContext->ulCurrentClusterNum = ulClusterNum; 00803 } 00804 00805 if(pIoman->pPartition->Type != FF_T_FAT32) { 00806 // Handle Root Dirs that don't have cluster chains! 00807 if(pContext->ulDirCluster == pIoman->pPartition->RootDirCluster) { 00808 // This is a RootDIR, special consideration needs to be made, because it doesn't have a Cluster chain! 00809 pContext->ulCurrentClusterLCN = pContext->ulDirCluster; 00810 ulClusterNum = 0; 00811 if(ulEntry > ((pIoman->pPartition->RootDirSectors * pIoman->pPartition->BlkSize) / 32)) { 00812 return FF_ERR_DIR_END_OF_DIR; 00813 } 00814 } 00815 } 00816 00817 if((ulClusterNum + 1) > pContext->ulChainLength) { 00818 return FF_ERR_DIR_END_OF_DIR; // End of Dir was reached! 00819 } 00820 00821 ulItemLBA = FF_Cluster2LBA (pIoman, pContext->ulCurrentClusterLCN) + FF_getMajorBlockNumber(pIoman, ulEntry, (FF_T_UINT16)32); 00822 ulItemLBA = FF_getRealLBA (pIoman, ulItemLBA) + FF_getMinorBlockNumber(pIoman, ulRelItem, (FF_T_UINT16)32); 00823 00824 if(!pContext->pBuffer || (pContext->pBuffer->Sector != ulItemLBA)) { 00825 if(pContext->pBuffer) { 00826 FF_ReleaseBuffer(pIoman, pContext->pBuffer); 00827 } 00828 pContext->pBuffer = FF_GetBuffer(pIoman, ulItemLBA, FF_MODE_READ); 00829 if(!pContext->pBuffer) { 00830 return FF_ERR_DEVICE_DRIVER_FAILED; 00831 } 00832 } 00833 00834 if (pEntryBuffer) { // HT Because it might be called with NULL 00835 memcpy(pEntryBuffer, (pContext->pBuffer->pBuffer + (ulRelItem*32)), 32); 00836 } 00837 00838 return FF_ERR_NONE; 00839 } 00840 00841 00842 FF_ERROR FF_PushEntryWithContext(FF_IOMAN *pIoman, FF_T_UINT32 ulEntry, FF_FETCH_CONTEXT *pContext, FF_T_UINT8 *pEntryBuffer) { 00843 FF_T_UINT32 ulItemLBA; 00844 FF_T_UINT32 ulRelItem; 00845 FF_T_UINT32 ulClusterNum; 00846 FF_ERROR Error; 00847 00848 ulClusterNum = FF_getClusterChainNumber(pIoman, ulEntry, (FF_T_UINT16)32); 00849 ulRelItem = FF_getMinorBlockEntry (pIoman, ulEntry, (FF_T_UINT16)32); 00850 00851 if(ulClusterNum != pContext->ulCurrentClusterNum) { 00852 // Traverse the fat gently! 00853 if(ulClusterNum > pContext->ulCurrentClusterNum) { 00854 pContext->ulCurrentClusterLCN = FF_TraverseFAT(pIoman, pContext->ulCurrentClusterLCN, (ulClusterNum - pContext->ulCurrentClusterNum), &Error); 00855 if(Error) { 00856 return Error; 00857 } 00858 } else { 00859 pContext->ulCurrentClusterLCN = FF_TraverseFAT(pIoman, pContext->ulDirCluster, ulClusterNum, &Error); 00860 if(Error) { 00861 return Error; 00862 } 00863 } 00864 pContext->ulCurrentClusterNum = ulClusterNum; 00865 } 00866 00867 if(pIoman->pPartition->Type != FF_T_FAT32) { 00868 // Handle Root Dirs that don't have cluster chains! 00869 if(pContext->ulDirCluster == pIoman->pPartition->RootDirCluster) { 00870 // This is a RootDIR, special consideration needs to be made, because it doesn't have a Cluster chain! 00871 pContext->ulCurrentClusterLCN = pContext->ulDirCluster; 00872 ulClusterNum = 0; 00873 if(ulEntry > ((pIoman->pPartition->RootDirSectors * pIoman->pPartition->BlkSize) / 32)) { 00874 return FF_ERR_DIR_END_OF_DIR; 00875 } 00876 } 00877 } 00878 00879 if((ulClusterNum + 1) > pContext->ulChainLength) { 00880 return FF_ERR_DIR_END_OF_DIR; // End of Dir was reached! 00881 } 00882 00883 ulItemLBA = FF_Cluster2LBA (pIoman, pContext->ulCurrentClusterLCN) + FF_getMajorBlockNumber(pIoman, ulEntry, (FF_T_UINT16)32); 00884 ulItemLBA = FF_getRealLBA (pIoman, ulItemLBA) + FF_getMinorBlockNumber(pIoman, ulRelItem, (FF_T_UINT16)32); 00885 00886 if(!pContext->pBuffer || (pContext->pBuffer->Sector != ulItemLBA)) { 00887 if(pContext->pBuffer) { 00888 FF_ReleaseBuffer(pIoman, pContext->pBuffer); 00889 } 00890 pContext->pBuffer = FF_GetBuffer(pIoman, ulItemLBA, FF_MODE_READ); 00891 if(!pContext->pBuffer) { 00892 return FF_ERR_DEVICE_DRIVER_FAILED; 00893 } 00894 } 00895 00896 memcpy((pContext->pBuffer->pBuffer + (ulRelItem*32)), pEntryBuffer, 32); 00897 pContext->pBuffer->Mode = FF_MODE_WRITE; 00898 pContext->pBuffer->Modified = FF_TRUE; 00899 00900 return FF_ERR_NONE; 00901 } 00902 00903 00907 FF_ERROR FF_GetEntry(FF_IOMAN *pIoman, FF_T_UINT16 nEntry, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent) { 00908 FF_T_UINT8 EntryBuffer[32]; 00909 FF_T_UINT8 numLFNs; 00910 FF_FETCH_CONTEXT FetchContext; 00911 FF_ERROR Error; 00912 00913 Error = FF_InitEntryFetch(pIoman, DirCluster, &FetchContext); 00914 if(Error) { 00915 return Error; 00916 } 00917 00918 Error = FF_FetchEntryWithContext(pIoman, nEntry, &FetchContext, EntryBuffer); 00919 if(Error) { 00920 FF_CleanupEntryFetch(pIoman, &FetchContext); 00921 return Error; 00922 } 00923 if(EntryBuffer[0] != 0xE5) { 00924 if(FF_isEndOfDir(EntryBuffer)){ 00925 FF_CleanupEntryFetch(pIoman, &FetchContext); 00926 return FF_ERR_DIR_END_OF_DIR; 00927 } 00928 00929 pDirent->Attrib = FF_getChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB)); 00930 00931 if((pDirent->Attrib & FF_FAT_ATTR_LFN) == FF_FAT_ATTR_LFN) { 00932 // LFN Processing 00933 numLFNs = (FF_T_UINT8)(EntryBuffer[0] & ~0x40); 00934 #ifdef FF_LFN_SUPPORT 00935 Error = FF_PopulateLongDirent(pIoman, pDirent, nEntry, &FetchContext); 00936 FF_CleanupEntryFetch(pIoman, &FetchContext); 00937 if(Error) { 00938 return Error; 00939 } 00940 return FF_ERR_NONE; 00941 #else 00942 pDirent->CurrentItem += (numLFNs - 1); 00943 #endif 00944 } else if((pDirent->Attrib & FF_FAT_ATTR_VOLID) == FF_FAT_ATTR_VOLID) { 00945 // Do Nothing 00946 00947 } else { 00948 FF_PopulateShortDirent(pIoman, pDirent, EntryBuffer); 00949 pDirent->CurrentItem += 1; 00950 FF_CleanupEntryFetch(pIoman, &FetchContext); 00951 return 0; 00952 } 00953 } 00954 00955 FF_CleanupEntryFetch(pIoman, &FetchContext); 00956 return FF_ERR_NONE; 00957 } 00958 00959 FF_T_BOOL FF_isEndOfDir(FF_T_UINT8 *EntryBuffer) { 00960 if(EntryBuffer[0] == 0x00) { 00961 return FF_TRUE; 00962 } 00963 return FF_FALSE; 00964 } 00965 00966 #ifdef FF_HASH_CACHE 00967 FF_ERROR FF_AddDirentHash(FF_IOMAN *pIoman, FF_T_UINT32 ulDirCluster, FF_T_UINT32 ulHash) { 00968 FF_T_UINT32 i; 00969 FF_HASH_TABLE pHash = NULL; 00970 for(i = 0; i < FF_HASH_CACHE_DEPTH; i++) { 00971 if(pIoman->HashCache[i].ulDirCluster == ulDirCluster) { 00972 pHash = pIoman->HashCache[i].pHashTable; 00973 break; 00974 } 00975 } 00976 00977 if(pHash) { 00978 FF_SetHash(pHash, ulHash); 00979 } 00980 00981 return FF_ERR_NONE; 00982 } 00983 00984 FF_T_BOOL FF_CheckDirentHash(FF_IOMAN *pIoman, FF_T_UINT32 ulDirCluster, FF_T_UINT32 ulHash) { 00985 FF_T_UINT32 i; 00986 FF_HASH_TABLE pHash = NULL; 00987 for(i = 0; i < FF_HASH_CACHE_DEPTH; i++) { 00988 if(pIoman->HashCache[i].ulDirCluster == ulDirCluster) { 00989 pHash = pIoman->HashCache[i].pHashTable; 00990 break; 00991 } 00992 } 00993 00994 if(pHash) { 00995 return FF_isHashSet(pHash, ulHash); 00996 } 00997 00998 return FF_FALSE; 00999 } 01000 01001 FF_T_BOOL FF_DirHashed(FF_IOMAN *pIoman, FF_T_UINT32 ulDirCluster) { 01002 FF_T_UINT32 i; 01003 for(i = 0; i < FF_HASH_CACHE_DEPTH; i++) { 01004 if(pIoman->HashCache[i].ulDirCluster == ulDirCluster) { 01005 return FF_TRUE; 01006 } 01007 } 01008 01009 return FF_FALSE; 01010 } 01011 01012 FF_ERROR FF_HashDir(FF_IOMAN *pIoman, FF_T_UINT32 ulDirCluster) { 01013 // Find most suitable Hash Table to replace! 01014 FF_T_UINT32 i; 01015 FF_HASHCACHE *pHashCache = NULL; 01016 FF_FETCH_CONTEXT FetchContext; 01017 FF_T_UINT8 EntryBuffer[32], ucAttrib; 01018 FF_T_UINT32 ulHash; 01019 01020 if(FF_DirHashed(pIoman, ulDirCluster)) { 01021 return FF_ERR_NONE; // Don't wastefully re-hash a dir! 01022 } 01023 01024 //printf("----- Hashing Directory\n"); 01025 01026 for(i = 0; i < FF_HASH_CACHE_DEPTH; i++) { 01027 if(!pIoman->HashCache[i].ulNumHandles) { 01028 if(!pHashCache) { 01029 pHashCache = &pIoman->HashCache[i]; 01030 } else { 01031 if((pIoman->HashCache[i].ulMisses > pHashCache->ulMisses)) { 01032 pHashCache = &pIoman->HashCache[i]; 01033 } 01034 } 01035 } 01036 } 01037 01038 if(pHashCache) { 01039 // Clear the hash table! 01040 FF_ClearHashTable(pHashCache->pHashTable); 01041 pHashCache->ulDirCluster = ulDirCluster; 01042 pHashCache->ulMisses = 0; 01043 01044 // Hash the directory! 01045 01046 FF_InitEntryFetch(pIoman, ulDirCluster, &FetchContext); 01047 01048 for(i = 0; i < 0xFFFF; i++) { 01049 if(FF_FetchEntryWithContext(pIoman, i, &FetchContext, EntryBuffer)) { 01050 break; // HT addition 01051 } 01052 ucAttrib = FF_getChar(EntryBuffer, FF_FAT_DIRENT_ATTRIB); 01053 if(FF_getChar(EntryBuffer, 0x00) != 0xE5) { 01054 if(ucAttrib != FF_FAT_ATTR_LFN) { 01055 FF_ProcessShortName((FF_T_INT8 *)EntryBuffer); 01056 if(FF_isEndOfDir(EntryBuffer)) { 01057 // HT uncommented 01058 FF_CleanupEntryFetch(pIoman, &FetchContext); 01059 return FF_ERR_NONE; 01060 } 01061 01062 // Generate the Hash 01063 #if FF_HASH_FUNCTION == CRC16 01064 ulHash = FF_GetCRC16(EntryBuffer, strlen((const FF_T_INT8 *) EntryBuffer)); 01065 #elif FF_HASH_FUNCTION == CRC8 01066 ulHash = FF_GetCRC8(EntryBuffer, strlen((const FF_T_INT8 *) EntryBuffer)); 01067 #endif 01068 FF_SetHash(pHashCache->pHashTable, ulHash); 01069 01070 } 01071 } 01072 } 01073 01074 FF_CleanupEntryFetch(pIoman, &FetchContext); 01075 01076 return FF_ERR_NONE; 01077 } 01078 01079 return -1; 01080 } 01081 01082 /*void FF_SetDirHashed(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster) { 01083 int i; 01084 for(i = 0; i < FF_PATH_CACHE_DEPTH; i++) { 01085 if(pIoman->pPartition->PathCache[i].DirCluster == DirCluster) { 01086 pIoman->pPartition->PathCache[i].bHashed = FF_TRUE; 01087 return; 01088 } 01089 } 01090 }*/ 01091 #endif 01092 01093 FF_ERROR FF_PopulateLongDirent(FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_T_UINT16 nEntry, FF_FETCH_CONTEXT *pFetchContext) { 01094 // First get the entire name as UTF-16 from the LFN's. 01095 // Then transform into the API's native string format. 01096 01097 FF_ERROR Error; 01098 FF_T_UINT uiNumLFNs; 01099 FF_T_UINT uiLfnLength = 0; 01100 #ifdef FF_UNICODE_UTF8_SUPPORT 01101 FF_T_UINT i,y; 01102 // FF_T_SINT32 slRetVal; 01103 FF_T_UINT16 nLfnBegin; 01104 FF_T_UINT16 usUtf8Len = 0; 01105 #endif 01106 FF_T_UINT16 myShort; 01107 FF_T_UINT8 ucCheckSum; 01108 01109 FF_T_UINT8 EntryBuffer[32]; 01110 //FF_T_UINT16 UTF16Name[FF_MAX_FILENAME]; 01111 01112 #ifdef FF_UNICODE_SUPPORT 01113 FF_T_WCHAR WCEntryBuffer[32]; 01114 FF_T_WCHAR ShortName[13]; 01115 #else 01116 FF_T_INT8 ShortName[13]; 01117 #endif 01118 01119 Error = FF_FetchEntryWithContext(pIoman, nEntry++, pFetchContext, EntryBuffer); 01120 if(Error) { 01121 return Error; 01122 } 01123 01124 uiNumLFNs = (FF_T_UINT)(EntryBuffer[0] & ~0x40); 01125 ucCheckSum = FF_getChar(EntryBuffer, FF_FAT_LFN_CHECKSUM); 01126 01127 #ifdef FF_UNICODE_SUPPORT // UTF-16 Can simply get segments of the UTF-16 sequence going forward 01128 // in the dirents. (I.e. reversed order). 01129 01130 while(uiNumLFNs) { // Avoid stack intensive use of a UTF-16 buffer. Stream direct to FileName dirent field in correct format. 01131 01132 // memcopy direct!-UTF-16 support 01133 memcpy(pDirent->FileName + ((uiNumLFNs - 1) * 13) + 0, &EntryBuffer[FF_FAT_LFN_NAME_1], 10); 01134 memcpy(pDirent->FileName + ((uiNumLFNs - 1) * 13) + 5, &EntryBuffer[FF_FAT_LFN_NAME_2], 12); 01135 memcpy(pDirent->FileName + ((uiNumLFNs - 1) * 13) + 11, &EntryBuffer[FF_FAT_LFN_NAME_3], 4); 01136 01137 01138 uiLfnLength += 13; 01139 01140 Error = FF_FetchEntryWithContext(pIoman, nEntry++, pFetchContext, EntryBuffer); 01141 if(Error) { 01142 return Error; 01143 } 01144 uiNumLFNs--; 01145 } 01146 01147 pDirent->FileName[uiLfnLength] = '\0'; 01148 #endif 01149 01150 #ifdef FF_UNICODE_UTF8_SUPPORT 01151 // UTF-8 Sequence, we can only convert this from the beginning, must receive entries in reverse. 01152 nLfnBegin = nEntry - 1; 01153 01154 for(i = 0; i < uiNumLFNs; i++) { 01155 Error = FF_FetchEntryWithContext(pIoman, (nLfnBegin + (uiNumLFNs - 1) - i), pFetchContext, EntryBuffer); 01156 if(Error) { 01157 return Error; 01158 } 01159 01160 // Now have the first part of the UTF-16 sequence. Stream into a UTF-8 sequence. 01161 for(y = 0; y < 5; y++) { 01162 Error = FF_Utf16ctoUtf8c((FF_T_UINT8 *) &pDirent->FileName[usUtf8Len], (FF_T_UINT16 *) &EntryBuffer[FF_FAT_LFN_NAME_1 + (y*2)], sizeof(pDirent->FileName) - usUtf8Len); 01163 if(Error > 0) { 01164 usUtf8Len += (FF_T_UINT16) Error; 01165 } 01166 } 01167 01168 for(y = 0; y < 6; y++) { 01169 Error = FF_Utf16ctoUtf8c((FF_T_UINT8 *) &pDirent->FileName[usUtf8Len], (FF_T_UINT16 *) &EntryBuffer[FF_FAT_LFN_NAME_2 + (y*2)], sizeof(pDirent->FileName) - usUtf8Len); 01170 if(Error > 0) { 01171 usUtf8Len += (FF_T_UINT16) Error; 01172 } 01173 } 01174 01175 for(y = 0; y < 2; y++) { 01176 Error = FF_Utf16ctoUtf8c((FF_T_UINT8 *) &pDirent->FileName[usUtf8Len], (FF_T_UINT16 *) &EntryBuffer[FF_FAT_LFN_NAME_3 + (y*2)], sizeof(pDirent->FileName) - usUtf8Len); 01177 if(Error > 0) { 01178 usUtf8Len += (FF_T_UINT16) Error; 01179 } 01180 } 01181 nEntry++; 01182 } 01183 01184 pDirent->FileName[usUtf8Len] = '\0'; 01185 01186 // Put Entry context to correct position. 01187 Error = FF_FetchEntryWithContext(pIoman, nEntry-1, pFetchContext, EntryBuffer); 01188 if(Error) { 01189 return Error; 01190 } 01191 01192 #endif 01193 01194 #ifndef FF_UNICODE_SUPPORT 01195 #ifndef FF_UNICODE_UTF8_SUPPORT // No Unicode, simple ASCII. 01196 while(uiNumLFNs) { // Avoid stack intensive use of a UTF-16 buffer. Stream direct to FileName dirent field in correct format. 01197 01198 for(i = 0; i < 5; i++) { 01199 pDirent->FileName[((uiNumLFNs - 1) * 13) + i] = EntryBuffer[FF_FAT_LFN_NAME_1 + (i*2)]; 01200 } 01201 01202 for(i = 0; i < 6; i++) { 01203 pDirent->FileName[((uiNumLFNs - 1) * 13) + i + 5] = EntryBuffer[FF_FAT_LFN_NAME_2 + (i*2)]; 01204 } 01205 01206 for(i = 0; i < 2; i++) { 01207 pDirent->FileName[((uiNumLFNs - 1) * 13) + i + 11] = EntryBuffer[FF_FAT_LFN_NAME_3 + (i*2)]; 01208 } 01209 01210 uiLfnLength += 13; 01211 01212 Error = FF_FetchEntryWithContext(pIoman, nEntry++, pFetchContext, EntryBuffer); 01213 if(Error) { 01214 return Error; 01215 } 01216 uiNumLFNs--; 01217 } 01218 01219 pDirent->FileName[uiLfnLength] = '\0'; 01220 01221 01222 #endif 01223 #endif 01224 // Process the Shortname. -- LFN Transformation is now complete. 01225 // Process the ShortName Entry 01226 01227 // if SHORTNAMES must be included, simple byte copy into shortname buffer. 01228 #if defined(FF_LFN_SUPPORT) && defined(FF_INCLUDE_SHORT_NAME) 01229 memcpy(pDirent->ShortName, EntryBuffer, 11); 01230 pDirent->ShortName[11] = '\0'; 01231 FF_ProcessShortName(pDirent->ShortName); 01232 #endif 01233 01234 #ifdef FF_UNICODE_SUPPORT 01235 FF_cstrntowcs(WCEntryBuffer, (FF_T_INT8 *) EntryBuffer, 32); 01236 memcpy(ShortName, WCEntryBuffer, 11 * sizeof(FF_T_WCHAR)); 01237 #else 01238 memcpy(ShortName, EntryBuffer, 11); 01239 #endif 01240 FF_ProcessShortName(ShortName); 01241 if(ucCheckSum != FF_CreateChkSum(EntryBuffer)) { 01242 #ifdef FF_UNICODE_SUPPORT 01243 wcscpy(pDirent->FileName, ShortName); 01244 #else 01245 strcpy(pDirent->FileName, ShortName); 01246 #endif 01247 } 01248 01249 // Finally fill in the other details 01250 myShort = FF_getShort(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_HIGH)); 01251 pDirent->ObjectCluster = (FF_T_UINT32) (myShort << 16); 01252 myShort = FF_getShort(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_LOW)); 01253 pDirent->ObjectCluster |= myShort; 01254 01255 #ifdef FF_TIME_SUPPORT 01256 // Get the creation Time & Date 01257 FF_GetTime(&pDirent->CreateTime, EntryBuffer, FF_FAT_DIRENT_CREATE_TIME); 01258 FF_GetDate(&pDirent->CreateTime, EntryBuffer, FF_FAT_DIRENT_CREATE_DATE); 01259 // Get the modified Time & Date 01260 FF_GetTime(&pDirent->CreateTime, EntryBuffer, FF_FAT_DIRENT_LASTMOD_TIME); 01261 FF_GetDate(&pDirent->CreateTime, EntryBuffer, FF_FAT_DIRENT_LASTMOD_DATE); 01262 // Get the last accessed Date. 01263 FF_GetDate(&pDirent->AccessedTime, EntryBuffer, FF_FAT_DIRENT_LASTACC_DATE); 01264 pDirent->AccessedTime.Hour = 0; 01265 pDirent->AccessedTime.Minute = 0; 01266 pDirent->AccessedTime.Second = 0; 01267 #endif 01268 01269 // Get the filesize. 01270 pDirent->Filesize = FF_getLong(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_FILESIZE)); 01271 // Get the attribute. 01272 pDirent->Attrib = FF_getChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB)); 01273 01274 pDirent->CurrentItem = nEntry; 01275 //return x; 01276 return FF_ERR_NONE; 01277 } 01278 01279 /* 01280 FF_ERROR FF_PopulateLongDirent(FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_T_UINT16 nEntry, FF_FETCH_CONTEXT *pFetchContext) { 01281 FF_T_UINT8 EntryBuffer[32]; 01282 #ifdef FF_UNICODE_SUPPORT 01283 FF_T_WCHAR UTF16EntryBuffer[32]; 01284 FF_T_WCHAR ShortName[13]; 01285 #if WCHAR_MAX > 0xFFFF 01286 FF_T_UINT16 i,y; 01287 #endif 01288 #else 01289 FF_T_INT8 ShortName[13]; 01290 #ifdef FF_UNICODE_UTF8_SUPPORT 01291 FF_T_SINT32 i, y; 01292 #else 01293 FF_T_UINT16 i, y; 01294 #endif 01295 #endif 01296 01297 #ifdef FF_UNICODE_UTF8_SUPPORT 01298 FF_T_UINT16 UTF16Name[FF_MAX_FILENAME]; // Read in the entire UTF-16 name into this buffer. 01299 FF_T_UINT16 *UTF16cptr; 01300 #endif 01301 FF_T_UINT8 numLFNs; 01302 FF_T_UINT8 x; 01303 FF_T_UINT8 CheckSum = 0; 01304 01305 FF_T_UINT16 lenlfn = 0; 01306 FF_T_UINT16 myShort; 01307 FF_ERROR Error; 01308 01309 Error = FF_FetchEntryWithContext(pIoman, nEntry++, pFetchContext, EntryBuffer); 01310 if(Error) { 01311 return Error; 01312 } 01313 01314 numLFNs = (FF_T_UINT8)(EntryBuffer[0] & ~0x40); 01315 // Handle the name 01316 CheckSum = FF_getChar(EntryBuffer, FF_FAT_LFN_CHECKSUM); 01317 01318 x = numLFNs; 01319 while(numLFNs) { 01320 if(numLFNs > 1) { 01321 numLFNs = numLFNs; 01322 } 01323 01324 #ifdef FF_UNICODE_SUPPORT 01325 // Simply fill the FileName buffer with UTF-16 Filename! 01326 #if WCHAR_MAX <= 0xFFFF // System works in UTF-16 so we can trust it if we just copy the UTF-16 strings directly. 01327 memcpy(pDirent->FileName + ((numLFNs - 1) * 13) + 0, &EntryBuffer[FF_FAT_LFN_NAME_1], (5 * 2)); 01328 memcpy(pDirent->FileName + ((numLFNs - 1) * 13) + 5, &EntryBuffer[FF_FAT_LFN_NAME_2], (6 * 2)); 01329 memcpy(pDirent->FileName + ((numLFNs - 1) * 13) + 11, &EntryBuffer[FF_FAT_LFN_NAME_3], (2 * 2)); 01330 lenlfn += 13; 01331 #else 01332 for(i = 0, y = 0; i < 5; i++, y += 2) { 01333 FF_Utf16ctoUtf32c((FF_T_UINT32 *)&pDirent->FileName[i + ((numLFNs - 1) * 13)], (FF_T_UINT16 *) &EntryBuffer[FF_FAT_LFN_NAME_1 + y]); 01334 //pDirent->FileName[i + ((numLFNs - 1) * 13)] = (FF_T_WCHAR) ((FF_T_WCHAR) EntryBuffer[FF_FAT_LFN_NAME_1 + y] | ((FF_T_WCHAR) EntryBuffer[FF_FAT_LFN_NAME_1 + y + 1] >> 8)); 01335 lenlfn++; 01336 } 01337 for(i = 0, y = 0; i < 6; i++, y += 2) { 01338 FF_Utf16ctoUtf32c((FF_T_UINT32 *)&pDirent->FileName[i + ((numLFNs - 1) * 13) + 5], (FF_T_UINT16 *) &EntryBuffer[FF_FAT_LFN_NAME_2 + y]); 01339 //pDirent->FileName[i + ((numLFNs - 1) * 13) + 5] = (FF_T_WCHAR) ((FF_T_WCHAR) EntryBuffer[FF_FAT_LFN_NAME_2 + y] | ((FF_T_WCHAR) EntryBuffer[FF_FAT_LFN_NAME_2 + y + 1] >> 8)); 01340 lenlfn++; 01341 } 01342 for(i = 0, y = 0; i < 2; i++, y += 2) { 01343 FF_Utf16ctoUtf32c((FF_T_UINT32 *)&pDirent->FileName[i + ((numLFNs - 1) * 13) + 11], (FF_T_UINT16 *) &EntryBuffer[FF_FAT_LFN_NAME_3 + y]); 01344 //pDirent->FileName[i + ((numLFNs - 1) * 13) + 11] = (FF_T_WCHAR) ((FF_T_WCHAR) EntryBuffer[FF_FAT_LFN_NAME_3 + y] | ((FF_T_WCHAR)EntryBuffer[FF_FAT_LFN_NAME_3 + y + 1] >> 8)); 01345 lenlfn++; 01346 } 01347 #endif 01348 // Copy each part of the LFNS 01349 #else 01350 #ifdef FF_UNICODE_UTF8_SUPPORT 01351 memcpy(UTF16Name + ((numLFNs - 1) * 13) + 0, &EntryBuffer[FF_FAT_LFN_NAME_1], (5 * 2)); 01352 memcpy(UTF16Name + ((numLFNs - 1) * 13) + 5, &EntryBuffer[FF_FAT_LFN_NAME_2], (6 * 2)); 01353 memcpy(UTF16Name + ((numLFNs - 1) * 13) + 11, &EntryBuffer[FF_FAT_LFN_NAME_3], (2 * 2)); 01354 lenlfn += 13; 01355 #else 01356 // Attempts to pull ASCII from UTF-8 encoding. 01357 for(i = 0, y = 0; i < 5; i++, y += 2) { 01358 pDirent->FileName[i + ((numLFNs - 1) * 13)] = EntryBuffer[FF_FAT_LFN_NAME_1 + y]; 01359 lenlfn++; 01360 } 01361 01362 for(i = 0, y = 0; i < 6; i++, y += 2) { 01363 pDirent->FileName[i + ((numLFNs - 1) * 13) + 5] = EntryBuffer[FF_FAT_LFN_NAME_2 + y]; 01364 lenlfn++; 01365 } 01366 01367 for(i = 0, y = 0; i < 2; i++, y += 2) { 01368 pDirent->FileName[i + ((numLFNs - 1) * 13) + 11] = EntryBuffer[FF_FAT_LFN_NAME_3 + y]; 01369 lenlfn++; 01370 } 01371 #endif 01372 #endif 01373 01374 Error = FF_FetchEntryWithContext(pIoman, nEntry++, pFetchContext, EntryBuffer); 01375 if(Error) { 01376 return Error; 01377 } 01378 numLFNs--; 01379 } 01380 01381 #ifdef FF_UNICODE_UTF8_SUPPORT 01382 UTF16cptr = UTF16Name; 01383 UTF16Name[lenlfn] = '\0'; 01384 i = 0; // Keep tabs of the current char position in the UTF-8 sequence. 01385 while(*UTF16cptr) { 01386 y = FF_Utf16ctoUtf8c((FF_T_UINT8 *)&pDirent->FileName[i], UTF16cptr, (FF_MAX_FILENAME - i)); 01387 i += y; 01388 if(FF_GetUtf16SequenceLen(*UTF16cptr++) == 2) { // IF this is a surrogate, then bump the UTF16 Pointer. 01389 UTF16cptr++; 01390 } 01391 } 01392 pDirent->FileName[i] = '\0'; 01393 #else 01394 pDirent->FileName[lenlfn] = '\0'; 01395 #endif 01396 01397 // Process the ShortName Entry 01398 #ifdef FF_UNICODE_SUPPORT 01399 FF_cstrntowcs(UTF16EntryBuffer, (FF_T_INT8 *) EntryBuffer, 32); 01400 memcpy(ShortName, UTF16EntryBuffer, 11 * sizeof(FF_T_WCHAR)); 01401 #else 01402 memcpy(ShortName, EntryBuffer, 11); 01403 #endif 01404 if(CheckSum != FF_CreateChkSum(EntryBuffer)) { 01405 FF_ProcessShortName(ShortName); 01406 #ifdef FF_UNICODE_SUPPORT 01407 wcscpy(pDirent->FileName, ShortName); 01408 #else 01409 strcpy(pDirent->FileName, ShortName); 01410 #endif 01411 } else { 01412 FF_ProcessShortName(ShortName); 01413 } 01414 01415 #ifdef FF_HASH_TABLE_SUPPORT*/ 01416 /*#if FF_HASH_FUNCTION == CRC16 01417 FF_AddDirentHash(pIoman, pFetchContext->ulDirCluster, (FF_T_UINT32)FF_GetCRC16((FF_T_UINT8 *) ShortName, strlen(ShortName))); 01418 #elif FF_HASH_FUNCTION == CRC8 01419 FF_AddDirentHash(pIoman, DirCluster, (FF_T_UINT32)FF_GetCRC8((FF_T_UINT8 *) ShortName, strlen(ShortName))); 01420 #endif*//* 01421 #endif 01422 01423 myShort = FF_getShort(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_HIGH)); 01424 pDirent->ObjectCluster = (FF_T_UINT32) (myShort << 16); 01425 myShort = FF_getShort(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_LOW)); 01426 pDirent->ObjectCluster |= myShort; 01427 01428 #ifdef FF_TIME_SUPPORT 01429 // Get the creation Time & Date 01430 FF_GetTime(&pDirent->CreateTime, EntryBuffer, FF_FAT_DIRENT_CREATE_TIME); 01431 FF_GetDate(&pDirent->CreateTime, EntryBuffer, FF_FAT_DIRENT_CREATE_DATE); 01432 // Get the modified Time & Date 01433 FF_GetTime(&pDirent->CreateTime, EntryBuffer, FF_FAT_DIRENT_LASTMOD_TIME); 01434 FF_GetDate(&pDirent->CreateTime, EntryBuffer, FF_FAT_DIRENT_LASTMOD_DATE); 01435 // Get the last accessed Date. 01436 FF_GetDate(&pDirent->AccessedTime, EntryBuffer, FF_FAT_DIRENT_LASTACC_DATE); 01437 pDirent->AccessedTime.Hour = 0; 01438 pDirent->AccessedTime.Minute = 0; 01439 pDirent->AccessedTime.Second = 0; 01440 #endif 01441 01442 // Get the filesize. 01443 pDirent->Filesize = FF_getLong(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_FILESIZE)); 01444 // Get the attribute. 01445 pDirent->Attrib = FF_getChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB)); 01446 01447 pDirent->CurrentItem = nEntry; 01448 //return x; 01449 return FF_ERR_NONE; 01450 } 01451 */ 01484 #ifdef FF_UNICODE_SUPPORT 01485 FF_ERROR FF_FindFirst(FF_IOMAN *pIoman, FF_DIRENT *pDirent, const FF_T_WCHAR *path) { 01486 #else 01487 FF_ERROR FF_FindFirst(FF_IOMAN *pIoman, FF_DIRENT *pDirent, const FF_T_INT8 *path) { 01488 #endif 01489 #ifdef FF_UNICODE_SUPPORT 01490 FF_T_UINT16 PathLen = (FF_T_UINT16) wcslen(path); 01491 #else 01492 FF_T_UINT16 PathLen = (FF_T_UINT16) strlen(path); 01493 #endif 01494 FF_ERROR Error; 01495 01496 #ifdef FF_FINDAPI_ALLOW_WILDCARDS 01497 FF_T_UINT16 i = 0; 01498 #ifdef FF_UNICODE_SUPPORT 01499 const FF_T_WCHAR *szWildCard; // Check for a Wild-card. 01500 #else 01501 const FF_T_INT8 *szWildCard; // Check for a Wild-card. 01502 #endif 01503 #endif 01504 01505 if(!pIoman) { 01506 return FF_ERR_NULL_POINTER; 01507 } 01508 01509 // Detect a Wild-Card on the End, or Filename, as apposed to a complete path. 01510 #ifndef FF_FINDAPI_ALLOW_WILDCARDS 01511 pDirent->DirCluster = FF_FindDir(pIoman, path, PathLen); // Get the directory cluster, if it exists. 01512 #endif 01513 01514 #ifdef FF_FINDAPI_ALLOW_WILDCARDS 01515 pDirent->szWildCard[0] = '\0'; // WildCard blank if its not a wildCard. 01516 01517 szWildCard = &path[PathLen - 1]; 01518 01519 if(PathLen) { 01520 while(*szWildCard != '\\' && *szWildCard != '/') { // Open the dir of the last token. 01521 i++; 01522 szWildCard--; 01523 if(!(PathLen - i)) { 01524 break; 01525 } 01526 } 01527 } 01528 01529 pDirent->DirCluster = FF_FindDir(pIoman, path, PathLen - i, &Error); 01530 if(Error) { 01531 return Error; 01532 } 01533 if(pDirent->DirCluster) { 01534 // Valid Dir found, copy the wildCard to filename! 01535 #ifdef FF_UNICODE_SUPPORT 01536 wcsncpy(pDirent->szWildCard, ++szWildCard, FF_MAX_FILENAME); 01537 #else 01538 strncpy(pDirent->szWildCard, ++szWildCard, FF_MAX_FILENAME); 01539 #endif 01540 } 01541 #endif 01542 01543 if(pDirent->DirCluster == 0) { 01544 return FF_ERR_DIR_INVALID_PATH; 01545 } 01546 01547 // Initialise the Fetch Context 01548 Error = FF_InitEntryFetch(pIoman, pDirent->DirCluster, &pDirent->FetchContext); 01549 if(Error) { 01550 return Error; 01551 } 01552 01553 pDirent->CurrentItem = 0; 01554 01555 return FF_FindNext(pIoman, pDirent); 01556 } 01557 01571 FF_ERROR FF_FindNext(FF_IOMAN *pIoman, FF_DIRENT *pDirent) { 01572 01573 FF_ERROR Error; 01574 FF_T_UINT8 numLFNs; 01575 FF_T_UINT8 EntryBuffer[32]; 01576 01577 if(!pIoman) { 01578 return FF_ERR_NULL_POINTER; 01579 } 01580 01581 for(; pDirent->CurrentItem < 0xFFFF; pDirent->CurrentItem += 1) { 01582 Error = FF_FetchEntryWithContext(pIoman, pDirent->CurrentItem, &pDirent->FetchContext, EntryBuffer); 01583 if(Error) { 01584 FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); 01585 return Error; 01586 } 01587 if(EntryBuffer[0] != FF_FAT_DELETED) { 01588 if(FF_isEndOfDir(EntryBuffer)){ 01589 FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); 01590 return FF_ERR_DIR_END_OF_DIR; 01591 } 01592 pDirent->Attrib = FF_getChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB)); 01593 if((pDirent->Attrib & FF_FAT_ATTR_LFN) == FF_FAT_ATTR_LFN) { 01594 // LFN Processing 01595 numLFNs = (FF_T_UINT8)(EntryBuffer[0] & ~0x40); 01596 // Get the shortname and check if it is marked deleted. 01597 #ifdef FF_LFN_SUPPORT 01598 // Fetch the shortname, and get it's checksum, or for a deleted item with 01599 // orphaned LFN entries. 01600 Error = FF_FetchEntryWithContext(pIoman, (pDirent->CurrentItem + numLFNs), &pDirent->FetchContext, EntryBuffer); 01601 if(Error) { 01602 FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); 01603 return Error; 01604 } 01605 01606 if(EntryBuffer[0] != FF_FAT_DELETED) { 01607 Error = FF_PopulateLongDirent(pIoman, pDirent, pDirent->CurrentItem, &pDirent->FetchContext); 01608 if(Error) { 01609 FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); 01610 return Error; 01611 } 01612 #ifdef FF_INCLUDE_SHORT_NAME 01613 pDirent->Attrib |= FF_FAT_ATTR_IS_LFN; 01614 #endif 01615 01616 #ifdef FF_FINDAPI_ALLOW_WILDCARDS 01617 #ifdef FF_UNICODE_SUPPORT 01618 if(wcscmp(pDirent->szWildCard, L"")) { 01619 #else 01620 if(strcmp(pDirent->szWildCard, "")) { 01621 #endif 01622 if(FF_wildcompare(pDirent->szWildCard, pDirent->FileName)) { 01623 FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); 01624 return FF_ERR_NONE; 01625 } 01626 pDirent->CurrentItem -= 1; 01627 } else { 01628 FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); 01629 return FF_ERR_NONE; 01630 } 01631 #else 01632 FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); 01633 return FF_ERR_NONE; 01634 #endif 01635 } 01636 #else 01637 pDirent->CurrentItem += (numLFNs - 1); 01638 #endif 01639 } else if((pDirent->Attrib & FF_FAT_ATTR_VOLID) == FF_FAT_ATTR_VOLID) { 01640 // Do Nothing 01641 01642 } else { 01643 FF_PopulateShortDirent(pIoman, pDirent, EntryBuffer); 01644 #if defined(FF_SHORTNAME_CASE) 01645 // Apply NT/XP+ bits to get correct case 01646 FF_CaseShortName(pDirent->FileName, FF_getChar(EntryBuffer, FF_FAT_CASE_OFFS)); 01647 #endif 01648 #ifdef FF_FINDAPI_ALLOW_WILDCARDS 01649 #ifdef FF_UNICODE_SUPPORT 01650 if(wcscmp(pDirent->szWildCard, L"")) { 01651 #else 01652 if(strcmp(pDirent->szWildCard, "")) { 01653 #endif 01654 if(FF_wildcompare(pDirent->szWildCard, pDirent->FileName)) { 01655 FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); 01656 pDirent->CurrentItem += 1; 01657 return FF_ERR_NONE; 01658 } 01659 } else { 01660 FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); 01661 pDirent->CurrentItem += 1; 01662 return FF_ERR_NONE; 01663 } 01664 #else 01665 01666 FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); 01667 pDirent->CurrentItem += 1; 01668 return FF_ERR_NONE; 01669 #endif 01670 } 01671 } 01672 } 01673 01674 FF_CleanupEntryFetch(pIoman, &pDirent->FetchContext); 01675 01676 return FF_ERR_DIR_END_OF_DIR; 01677 } 01678 01679 01680 FF_T_SINT8 FF_RewindFind(FF_IOMAN *pIoman, FF_DIRENT *pDirent) { 01681 if(!pIoman) { 01682 return FF_ERR_NULL_POINTER; 01683 } 01684 pDirent->CurrentItem = 0; 01685 return 0; 01686 } 01687 01688 /* 01689 Returns >= 0 for a free dirent entry. 01690 Returns < 0 with and Error code if anything goes wrong. 01691 */ 01692 static FF_T_SINT32 FF_FindFreeDirent(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT16 Sequential) { 01693 01694 FF_T_UINT8 EntryBuffer[32]; 01695 FF_T_UINT16 i = 0; 01696 FF_T_UINT16 nEntry; 01697 FF_ERROR Error; 01698 FF_T_UINT32 DirLength; 01699 FF_FETCH_CONTEXT FetchContext; 01700 01701 Error = FF_InitEntryFetch(pIoman, DirCluster, &FetchContext); 01702 if(Error) { 01703 return Error; 01704 } 01705 01706 for(nEntry = 0; nEntry < 0xFFFF; nEntry++) { 01707 Error = FF_FetchEntryWithContext(pIoman, nEntry, &FetchContext, EntryBuffer); 01708 if(Error == FF_ERR_DIR_END_OF_DIR) { 01709 01710 Error = FF_ExtendDirectory(pIoman, DirCluster); 01711 FF_CleanupEntryFetch(pIoman, &FetchContext); 01712 01713 if(Error) { 01714 return Error; 01715 } 01716 01717 return nEntry; 01718 } else { 01719 if(Error) { 01720 FF_CleanupEntryFetch(pIoman, &FetchContext); 01721 return Error; 01722 } 01723 } 01724 if(FF_isEndOfDir(EntryBuffer)) { // If its the end of the Dir, then FreeDirents from here. 01725 // Check Dir is long enough! 01726 DirLength = FetchContext.ulChainLength;//FF_GetChainLength(pIoman, DirCluster, &iEndOfChain); 01727 if((nEntry + Sequential) > (FF_T_UINT16)(((pIoman->pPartition->SectorsPerCluster * pIoman->pPartition->BlkSize) * DirLength) / 32)) { 01728 Error = FF_ExtendDirectory(pIoman, DirCluster); 01729 } 01730 01731 FF_CleanupEntryFetch(pIoman, &FetchContext); 01732 01733 if(Error) { 01734 return Error; 01735 } 01736 01737 return nEntry; 01738 } 01739 if(EntryBuffer[0] == 0xE5) { 01740 i++; 01741 } else { 01742 i = 0; 01743 } 01744 01745 if(i == Sequential) { 01746 FF_CleanupEntryFetch(pIoman, &FetchContext); 01747 return (nEntry - (Sequential - 1));// Return the beginning entry in the sequential sequence. 01748 } 01749 } 01750 01751 FF_CleanupEntryFetch(pIoman, &FetchContext); 01752 01753 return FF_ERR_DIR_DIRECTORY_FULL; 01754 } 01755 01756 01757 01758 01759 FF_ERROR FF_PutEntry(FF_IOMAN *pIoman, FF_T_UINT16 Entry, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent) { 01760 FF_BUFFER *pBuffer; 01761 FF_ERROR Error; 01762 FF_T_UINT32 itemLBA; 01763 FF_T_UINT32 clusterNum = FF_getClusterChainNumber (pIoman, Entry, (FF_T_UINT16)32); 01764 FF_T_UINT32 relItem = FF_getMinorBlockEntry (pIoman, Entry, (FF_T_UINT16)32); 01765 FF_T_UINT32 clusterAddress = FF_TraverseFAT(pIoman, DirCluster, clusterNum, &Error); 01766 01767 if(Error) { 01768 return Error; 01769 } 01770 01771 itemLBA = FF_Cluster2LBA(pIoman, clusterAddress) + FF_getMajorBlockNumber(pIoman, Entry, (FF_T_UINT16)32); 01772 itemLBA = FF_getRealLBA (pIoman, itemLBA) + FF_getMinorBlockNumber(pIoman, relItem, (FF_T_UINT16)32); 01773 01774 pBuffer = FF_GetBuffer(pIoman, itemLBA, FF_MODE_WRITE); 01775 { 01776 if(!pBuffer) { 01777 return FF_ERR_DEVICE_DRIVER_FAILED; 01778 } 01779 // Modify the Entry! 01780 //memcpy((pBuffer->pBuffer + (32*relItem)), pDirent->FileName, 11); 01781 relItem *= 32; 01782 FF_putChar(pBuffer->pBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB + relItem), pDirent->Attrib); 01783 FF_putShort(pBuffer->pBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_HIGH + relItem), (FF_T_UINT16)(pDirent->ObjectCluster >> 16)); 01784 FF_putShort(pBuffer->pBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_LOW + relItem), (FF_T_UINT16)(pDirent->ObjectCluster)); 01785 FF_putLong(pBuffer->pBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_FILESIZE + relItem), pDirent->Filesize); 01786 #ifdef FF_TIME_SUPPORT 01787 FF_PlaceDate((pBuffer->pBuffer + relItem), FF_FAT_DIRENT_LASTACC_DATE); // Last accessed date. 01788 #endif 01789 } 01790 FF_ReleaseBuffer(pIoman, pBuffer); 01791 01792 return 0; 01793 } 01794 01795 FF_T_BOOL FF_ValidShortChar (FF_T_INT8 Chr) 01796 { 01797 return (Chr >= 'A' && Chr <= 'Z') || 01798 #if defined(FF_SHORTNAME_CASE) 01799 (Chr >= 'a' && Chr <= 'z') || // lower-case can be stored using NT/XP attribute 01800 #endif 01801 (Chr >= '0' && Chr <= '9') || 01802 strchr ("$%-_@~`!(){}^#&", Chr) != NULL; 01803 } 01804 01805 FF_T_BOOL FF_ValidLongChar (FF_T_INT8 Chr) 01806 { 01807 return Chr >= 0x20 && strchr ("/\\:*?\"<>|", Chr) == NULL; 01808 } 01809 01810 #ifdef FF_UNICODE_SUPPORT 01811 FF_T_SINT8 FF_CreateShortName(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_WCHAR *ShortName, FF_T_WCHAR *LongName) { 01812 #else 01813 FF_T_SINT8 FF_CreateShortName(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *ShortName, FF_T_INT8 *LongName) { 01814 #endif 01815 FF_T_UINT8 caseAttrib = 0; 01816 #if defined(FF_SHORTNAME_CASE) 01817 FF_T_UINT8 testAttrib = FF_FAT_CASE_ATTR_BASE; 01818 #endif 01819 01820 FF_T_UINT16 i,x,y,last_dot; 01821 FF_T_UINT16 first_tilde = 6; 01822 #ifdef FF_UNICODE_SUPPORT 01823 FF_T_WCHAR MyShortName[13]; 01824 #else 01825 FF_T_INT8 MyShortName[13]; 01826 #endif 01827 FF_T_UINT16 NameLen; 01828 FF_T_BOOL FitsShort = FF_TRUE; 01829 FF_DIRENT MyDir; 01830 FF_T_BOOL found; 01831 //FF_T_SINT8 RetVal = 0; 01832 FF_T_INT8 NumberBuf[6]; 01833 FF_ERROR Error; 01834 01835 #ifdef FF_UNICODE_SUPPORT 01836 NameLen = (FF_T_UINT16) wcslen(LongName); 01837 #else 01838 NameLen = (FF_T_UINT16) strlen(LongName); 01839 #endif 01840 01841 // Does LongName fit a shortname? 01842 01843 for(i = 0, x = 0, last_dot = NameLen; i < NameLen; i++) { 01844 if(LongName[i] != '.') { 01845 x++; 01846 } else { 01847 last_dot = i; 01848 } 01849 } 01850 01851 if (NameLen > 12 || NameLen-x > 1 || NameLen-last_dot > 4 || last_dot > 8) { 01852 FitsShort = FF_FALSE; 01853 } 01854 01855 for(i = 0, x = 0; i < 11; x++) { 01856 FF_T_INT8 ch = (FF_T_INT8) LongName[x]; 01857 if (!ch) 01858 break; 01859 if (x == last_dot) { 01860 while (i < 8) 01861 ShortName[i++] = 0x20; 01862 #if defined(FF_SHORTNAME_CASE) 01863 testAttrib = FF_FAT_CASE_ATTR_EXT; 01864 #endif 01865 } else { 01866 if (i == 8) { 01867 x = last_dot; 01868 ch = (FF_T_INT8) LongName[x]; 01869 if (ch) 01870 ch = (FF_T_INT8) LongName[++x]; 01871 #if defined(FF_SHORTNAME_CASE) 01872 testAttrib = FF_FAT_CASE_ATTR_EXT; 01873 #endif 01874 } 01875 if (!FF_ValidShortChar (ch)) { 01876 FitsShort = FF_FALSE; 01877 continue; 01878 } 01879 if (ch >= 'a' && ch <= 'z') { 01880 ch -= 0x20; 01881 #if defined(FF_SHORTNAME_CASE) 01882 if (testAttrib) 01883 caseAttrib |= testAttrib; 01884 else 01885 FitsShort = FF_FALSE; // We had capital: does not fit 01886 } else if (ch >= 'A' && ch <= 'Z') { 01887 if (caseAttrib & testAttrib) 01888 FitsShort = FF_FALSE; // We had lower-case: does not fit 01889 testAttrib = 0; 01890 #endif 01891 } 01892 ShortName[i++] = ch; 01893 } 01894 } 01895 while (i < 11) 01896 ShortName[i++] = 0x20; 01897 if (last_dot < first_tilde) 01898 first_tilde = last_dot; 01899 if (NameLen < first_tilde) // Names like "Abc" will become "~Abc" 01900 first_tilde = NameLen; 01901 01902 // Tail : 01903 memcpy(MyShortName, ShortName, 11); 01904 FF_ProcessShortName(MyShortName); 01905 found = (FF_T_BOOL) FF_FindEntryInDir(pIoman, DirCluster, MyShortName, 0x00, &MyDir, &Error); 01906 #ifdef Hein_Tibosch 01907 if (verboseLevel >= 1) logPrintf ("Long Name: %-14.14s Short '%s' (%s) Fit '%d' Found %d\n", LongName, ShortName, MyShortName, FitsShort, found); 01908 #endif 01909 if(FitsShort && !found) { 01910 return caseAttrib | 0x01; 01911 } 01912 if(FitsShort) { 01913 return FF_ERR_DIR_OBJECT_EXISTS; 01914 } 01915 for(i = 1; i < 0x0000FFFF; i++) { // Max Number of Entries in a DIR! 01916 sprintf(NumberBuf, "%d", i); 01917 NameLen = (FF_T_UINT16) strlen(NumberBuf); 01918 x = 7 - NameLen; 01919 if (x > first_tilde) 01920 x = first_tilde; 01921 ShortName[x++] = '~'; 01922 for(y = 0; y < NameLen; y++) { 01923 ShortName[x+y] = NumberBuf[y]; 01924 } 01925 memcpy(MyShortName, ShortName, 11); 01926 FF_ProcessShortName(MyShortName); 01927 found = FF_ShortNameExists(pIoman, DirCluster, MyShortName, &Error); 01928 #ifdef Hein_Tibosch 01929 if (verboseLevel >= 1) logPrintf ("Long Name: %-14.14s Short '%s' (%s) Fit '%d' Found %d\n", LongName, ShortName, MyShortName, FitsShort, found); 01930 #endif 01931 if(!found) { 01932 #ifdef FF_HASH_CACHE 01933 #if FF_HASH_FUNCTION == CRC16 01934 FF_AddDirentHash(pIoman, DirCluster, (FF_T_UINT32) FF_GetCRC16((FF_T_UINT8*)MyShortName, strlen(MyShortName))); 01935 #elif FF_HASH_FUNCTION == CRC8 01936 FF_AddDirentHash(pIoman, DirCluster, (FF_T_UINT32) FF_GetCRC8((FF_T_UINT8*)MyShortName, strlen(MyShortName))); 01937 #endif 01938 #endif 01939 return 0; 01940 } 01941 } 01942 // Add a tail and special number until we're happy :D 01943 01944 return FF_ERR_DIR_DIRECTORY_FULL; 01945 } 01946 01947 01948 #ifdef FF_LFN_SUPPORT 01949 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) { 01950 01951 FF_T_UINT i, x; 01952 01953 memset(EntryBuffer, 0, 32); 01954 01955 FF_putChar(EntryBuffer, FF_FAT_LFN_ORD, (FF_T_UINT8) ((uiLFN & ~0x40))); 01956 FF_putChar(EntryBuffer, FF_FAT_DIRENT_ATTRIB, (FF_T_UINT8) FF_FAT_ATTR_LFN); 01957 FF_putChar(EntryBuffer, FF_FAT_LFN_CHECKSUM, (FF_T_UINT8) CheckSum); 01958 01959 // Name_1 01960 for(i = 0, x = 0; i < 5; i++, x += 2) { 01961 if(i < uiNameLen) 01962 { 01963 memcpy(&EntryBuffer[FF_FAT_LFN_NAME_1 + x], &Name[i], sizeof(FF_T_UINT16)); 01964 //bobtntfullfat *((FF_T_UINT16 *) &EntryBuffer[FF_FAT_LFN_NAME_1 + x]) = Name[i]; 01965 } 01966 else 01967 if (i == uiNameLen) 01968 { 01969 EntryBuffer[FF_FAT_LFN_NAME_1 + x] = '\0'; 01970 EntryBuffer[FF_FAT_LFN_NAME_1 + x + 1] = '\0'; 01971 } 01972 else 01973 { 01974 EntryBuffer[FF_FAT_LFN_NAME_1 + x] = 0xFF; 01975 EntryBuffer[FF_FAT_LFN_NAME_1 + x + 1] = 0xFF; 01976 } 01977 } 01978 01979 // Name_2 01980 for(i = 0, x = 0; i < 6; i++, x += 2) { 01981 if((i + 5) < uiNameLen) 01982 { 01983 memcpy(&EntryBuffer[FF_FAT_LFN_NAME_2 + x], &Name[i+5], sizeof(FF_T_UINT16)); 01984 //EntryBuffer[FF_FAT_LFN_NAME_2 + x] = Name[i+5]; 01985 //bobtntfullfat *((FF_T_UINT16 *) &EntryBuffer[FF_FAT_LFN_NAME_2 + x]) = Name[i+5]; 01986 } else if ((i + 5) == uiNameLen) { 01987 EntryBuffer[FF_FAT_LFN_NAME_2 + x] = '\0'; 01988 EntryBuffer[FF_FAT_LFN_NAME_2 + x + 1] = '\0'; 01989 }else { 01990 EntryBuffer[FF_FAT_LFN_NAME_2 + x] = 0xFF; 01991 EntryBuffer[FF_FAT_LFN_NAME_2 + x + 1] = 0xFF; 01992 } 01993 } 01994 01995 // Name_3 01996 for(i = 0, x = 0; i < 2; i++, x += 2) { 01997 if((i + 11) < uiNameLen) 01998 { 01999 memcpy(&EntryBuffer[FF_FAT_LFN_NAME_3 + x], &Name[i+11], sizeof(FF_T_UINT16)); 02000 //EntryBuffer[FF_FAT_LFN_NAME_3 + x] = Name[i+11]; 02001 //bobtntfullfat *((FF_T_UINT16 *) &EntryBuffer[FF_FAT_LFN_NAME_3 + x]) = Name[i+11]; 02002 } else if ((i + 11) == uiNameLen) { 02003 EntryBuffer[FF_FAT_LFN_NAME_3 + x] = '\0'; 02004 EntryBuffer[FF_FAT_LFN_NAME_3 + x + 1] = '\0'; 02005 }else { 02006 EntryBuffer[FF_FAT_LFN_NAME_3 + x] = 0xFF; 02007 EntryBuffer[FF_FAT_LFN_NAME_3 + x + 1] = 0xFF; 02008 } 02009 } 02010 02011 return FF_ERR_NONE; 02012 } 02013 #endif 02014 02015 /* 02016 #ifdef FF_UNICODE_SUPPORT 02017 static FF_ERROR FF_CreateLFNs(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_WCHAR *Name, FF_T_UINT8 CheckSum, FF_T_UINT16 nEntry) { 02018 #else 02019 static FF_ERROR FF_CreateLFNs(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *Name, FF_T_UINT8 CheckSum, FF_T_UINT16 nEntry) { 02020 #endif 02021 FF_T_UINT8 EntryBuffer[32]; 02022 #ifdef FF_UNICODE_SUPPORT 02023 FF_T_UINT16 NameLen = (FF_T_UINT16) wcslen(Name); 02024 #else 02025 FF_T_UINT16 NameLen = (FF_T_UINT16) strlen(Name); 02026 #endif 02027 FF_T_UINT8 NumLFNs = (FF_T_UINT8) (NameLen / 13); 02028 FF_T_UINT8 i; 02029 FF_T_UINT8 EndPos = (NameLen % 13); 02030 FF_ERROR Error; 02031 02032 FF_FETCH_CONTEXT FetchContext; 02033 02034 if(EndPos) { 02035 NumLFNs ++; 02036 } else { 02037 EndPos = 13; 02038 } 02039 02040 Error = FF_InitEntryFetch(pIoman, DirCluster, &FetchContext); 02041 if(Error) { 02042 return Error; 02043 } 02044 02045 for(i = NumLFNs; i > 0; i--) { 02046 if(i == NumLFNs) { 02047 FF_CreateLFNEntry(EntryBuffer, (Name + (13 * (i - 1))), EndPos, i, CheckSum); 02048 EntryBuffer[0] |= 0x40; 02049 } else { 02050 FF_CreateLFNEntry(EntryBuffer, (Name + (13 * (i - 1))), 13, i, CheckSum); 02051 } 02052 02053 Error = FF_PushEntryWithContext(pIoman, nEntry + (NumLFNs - i), &FetchContext, EntryBuffer); 02054 if(Error) { 02055 FF_CleanupEntryFetch(pIoman, &FetchContext); 02056 return Error; 02057 } 02058 } 02059 02060 FF_CleanupEntryFetch(pIoman, &FetchContext); 02061 02062 return FF_ERR_NONE; 02063 } 02064 #endif 02065 */ 02066 02067 02068 #ifdef FF_UNICODE_SUPPORT 02069 static FF_ERROR FF_CreateLFNs(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_WCHAR *Name, FF_T_UINT8 CheckSum, FF_T_UINT16 nEntry) { 02070 #else 02071 static FF_ERROR FF_CreateLFNs(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *Name, FF_T_UINT8 CheckSum, FF_T_UINT16 nEntry) { 02072 #endif 02073 FF_ERROR Error; 02074 FF_T_UINT uiNumLFNs; 02075 FF_T_UINT uiEndPos; 02076 FF_T_UINT i,y; 02077 02078 #ifdef FF_UNICODE_UTF8_SUPPORT 02079 FF_T_SINT32 slRetVal; 02080 #endif 02081 02082 #ifndef FF_UNICODE_SUPPORT 02083 #ifndef FF_UNICODE_UTF8_SUPPORT 02084 FF_T_UINT16 *pUtf16; 02085 #endif 02086 #endif 02087 02088 FF_FETCH_CONTEXT FetchContext; 02089 02090 FF_T_UINT8 EntryBuffer[32]; 02091 FF_T_UINT16 usUtf16Name[FF_MAX_FILENAME + 1]; 02092 02093 02094 #ifdef FF_UNICODE_SUPPORT 02095 #if WCHAR_MAX <= 0xFFFF 02096 y = wcslen(Name); 02097 if(y > FF_MAX_FILENAME) { 02098 return FF_ERR_DIR_NAME_TOO_LONG; 02099 } 02100 wcsncpy(usUtf16Name, Name, FF_MAX_FILENAME); 02101 #else 02102 i = 0; 02103 y = 0; 02104 while(Name[i]) { 02105 FF_Utf32ctoUtf16c(&usUtf16Name[y], (FF_T_UINT32) Name[i], FF_MAX_FILENAME - i); 02106 y += FF_GetUtf16SequenceLen(usUtf16Name[y]); 02107 i++; 02108 if(y > FF_MAX_FILENAME) { 02109 return FF_ERR_DIR_NAME_TOO_LONG; 02110 } 02111 } 02112 #endif 02113 #endif 02114 02115 // Convert the name into UTF-16 format. 02116 #ifdef FF_UNICODE_UTF8_SUPPORT 02117 // Simply convert the UTF8 to UTF16 and be done with it. 02118 i = 0; 02119 y = 0; 02120 while(Name[i]) { 02121 slRetVal = FF_Utf8ctoUtf16c(&usUtf16Name[y], (FF_T_UINT8 *)&Name[i], FF_MAX_FILENAME - i); 02122 if(slRetVal > 0) { 02123 i += slRetVal; 02124 } else { 02125 break; // No more space in the UTF-16 buffer, simply truncate for safety. 02126 } 02127 y += FF_GetUtf16SequenceLen(usUtf16Name[y]); 02128 if(y > FF_MAX_FILENAME) { 02129 return FF_ERR_DIR_NAME_TOO_LONG; 02130 } 02131 } 02132 #else 02133 #ifndef FF_UNICODE_SUPPORT 02134 i = 0; 02135 y = strlen(Name); 02136 if(y > FF_MAX_FILENAME) { 02137 return FF_ERR_DIR_NAME_TOO_LONG; 02138 } 02139 pUtf16 = usUtf16Name; 02140 while(Name[i]) { 02141 usUtf16Name[i] = (FF_T_UINT16) Name[i]; 02142 i++; 02143 } 02144 #endif 02145 #endif 02146 02147 // Whole name is now in a valid UTF-16 format. Lets go make thos LFN's. 02148 // i should at this point be the length of the name. 02149 02150 uiNumLFNs = y / 13; // Number of LFNs is the total number of UTF-16 units, divided by 13 (13 units per LFN). 02151 uiEndPos = y % 13; // The ending position in an LFN, of the last LFN UTF-16 charachter. 02152 02153 if(uiEndPos) { 02154 uiNumLFNs++; 02155 } else { 02156 uiEndPos = 13; 02157 } 02158 02159 Error = FF_InitEntryFetch(pIoman, DirCluster, &FetchContext); 02160 if(Error) { 02161 return Error; 02162 } 02163 02164 // After this point, i is no longer the length of the Filename in UTF-16 units. 02165 for(i = uiNumLFNs; i > 0; i--) { 02166 if(i == uiNumLFNs) { 02167 FF_CreateLFNEntry(EntryBuffer, (usUtf16Name + (13 * (i - 1))), uiEndPos, i, CheckSum); 02168 EntryBuffer[0] |= 0x40; 02169 } else { 02170 FF_CreateLFNEntry(EntryBuffer, (usUtf16Name + (13 * (i - 1))), 13, i, CheckSum); 02171 } 02172 02173 Error = FF_PushEntryWithContext(pIoman, nEntry + (uiNumLFNs - i), &FetchContext, EntryBuffer); 02174 if(Error) { 02175 FF_CleanupEntryFetch(pIoman, &FetchContext); 02176 return Error; 02177 } 02178 } 02179 02180 FF_CleanupEntryFetch(pIoman, &FetchContext); 02181 02182 return FF_ERR_NONE; 02183 } 02184 02185 FF_ERROR FF_ExtendDirectory(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster) { 02186 FF_T_UINT32 CurrentCluster; 02187 FF_T_UINT32 NextCluster; 02188 FF_ERROR Error; 02189 02190 if(pIoman->pPartition->Type != FF_T_FAT32) { 02191 if(DirCluster == pIoman->pPartition->RootDirCluster) { 02192 return FF_ERR_DIR_CANT_EXTEND_ROOT_DIR; 02193 } 02194 } 02195 02196 if(!pIoman->pPartition->FreeClusterCount) { 02197 pIoman->pPartition->FreeClusterCount = FF_CountFreeClusters(pIoman, &Error); 02198 if(Error) { 02199 return Error; 02200 } 02201 if(pIoman->pPartition->FreeClusterCount == 0) { 02202 return FF_ERR_FAT_NO_FREE_CLUSTERS; 02203 } 02204 } 02205 02206 FF_lockFAT(pIoman); 02207 { 02208 CurrentCluster = FF_FindEndOfChain(pIoman, DirCluster, &Error); 02209 if(Error) { 02210 FF_unlockFAT(pIoman); 02211 return Error; 02212 } 02213 02214 NextCluster = FF_FindFreeCluster(pIoman, &Error); 02215 if(Error) { 02216 FF_unlockFAT(pIoman); 02217 return Error; 02218 } 02219 02220 Error = FF_putFatEntry(pIoman, CurrentCluster, NextCluster); 02221 if(Error) { 02222 FF_unlockFAT(pIoman); 02223 return Error; 02224 } 02225 02226 Error = FF_putFatEntry(pIoman, NextCluster, 0xFFFFFFFF); 02227 if(Error) { 02228 FF_unlockFAT(pIoman); 02229 return Error; 02230 } 02231 } 02232 FF_unlockFAT(pIoman); 02233 02234 Error = FF_ClearCluster(pIoman, NextCluster); 02235 if(Error) { 02236 FF_unlockFAT(pIoman); 02237 return Error; 02238 } 02239 02240 Error = FF_DecreaseFreeClusters(pIoman, 1); 02241 if(Error) { 02242 FF_unlockFAT(pIoman); 02243 return Error; 02244 } 02245 02246 return FF_ERR_NONE; 02247 } 02248 02249 #ifdef FF_UNICODE_SUPPORT 02250 static void FF_MakeNameCompliant(FF_T_WCHAR *Name) { 02251 #else 02252 static void FF_MakeNameCompliant(FF_T_UINT8 *Name) { 02253 #endif 02254 02255 if((FF_T_UINT8) Name[0] == 0xE5) { // Support Japanese KANJI symbol. 02256 Name[0] = 0x05; 02257 } 02258 02259 while(*Name) { 02260 if(*Name < 0x20 || *Name == 0x7F || *Name == 0x22 || *Name == 0x7C) { // Leave all extended chars as they are. 02261 *Name = '_'; 02262 } 02263 if(*Name >= 0x2A && *Name <= 0x2F && *Name != 0x2B && *Name != 0x2E && *Name != 0x2D) { 02264 *Name = '_'; 02265 } 02266 if(*Name >= 0x3A && *Name <= 0x3F) { 02267 *Name = '_'; 02268 } 02269 if(*Name >= 0x5B && *Name <= 0x5C) { 02270 *Name = '_'; 02271 } 02272 Name++; 02273 } 02274 } 02275 02276 FF_ERROR FF_CreateDirent(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent) { 02277 02278 FF_T_UINT8 EntryBuffer[32]; 02279 #ifdef FF_UNICODE_SUPPORT 02280 FF_T_UINT16 NameLen = (FF_T_UINT16) wcslen(pDirent->FileName); 02281 #else 02282 FF_T_UINT16 NameLen = (FF_T_UINT16) strlen(pDirent->FileName); 02283 #endif 02284 FF_T_UINT8 numLFNs = (FF_T_UINT8) (NameLen / 13); 02285 FF_T_SINT32 FreeEntry; 02286 FF_ERROR RetVal = FF_ERR_NONE; 02287 FF_T_UINT8 Entries; 02288 02289 FF_FETCH_CONTEXT FetchContext; 02290 02291 #ifdef FF_LFN_SUPPORT 02292 FF_T_UINT8 CheckSum; 02293 #endif 02294 02295 #ifdef FF_UNICODE_SUPPORT 02296 FF_T_WCHAR UTF16EntryBuffer[32]; 02297 #if WCHAR_MAX > 0xFFFF 02298 // Check that the filename won't exceed the max LFN length if converted to UTF-16. 02299 /*if(FF_Utf32GetUtf16Len((FF_T_UINT32 *) pDirent->FileName) > FF_MAX_FILENAME) { 02300 return FF_ERR_UNICODE_CONVERSION_EXCEEDED; 02301 }*/ 02302 #endif 02303 02304 #endif 02305 02306 #ifdef FF_UNICODE_SUPPORT 02307 FF_MakeNameCompliant(pDirent->FileName); // Ensure we don't break the Dir tables. 02308 #else 02309 FF_MakeNameCompliant((FF_T_UINT8 *)pDirent->FileName); // Ensure we don't break the Dir tables. 02310 #endif 02311 memset(EntryBuffer, 0, 32); 02312 02313 if(NameLen % 13) { 02314 numLFNs ++; 02315 } 02316 02317 #ifdef FF_LFN_SUPPORT 02318 // Create and push the LFN's 02319 Entries = numLFNs + 1; // Find enough places for the LFNs and the ShortName 02320 #else 02321 Entries = 1; 02322 #endif 02323 02324 // Create the ShortName 02325 FF_lockDIR(pIoman); 02326 { 02327 if((FreeEntry = FF_FindFreeDirent(pIoman, DirCluster, Entries)) >= 0) { 02328 #ifdef FF_UNICODE_SUPPORT 02329 //FF_cstrntowcs(UTF16EntryBuffer, (FF_T_INT8 *) EntryBuffer, 32); 02330 RetVal = FF_CreateShortName(pIoman, DirCluster, UTF16EntryBuffer, pDirent->FileName); 02331 #else 02332 RetVal = FF_CreateShortName(pIoman, DirCluster, (FF_T_INT8 *) EntryBuffer, pDirent->FileName); 02333 #endif 02334 02335 //if(!RetVal) { 02336 #ifdef FF_LFN_SUPPORT 02337 #ifdef FF_UNICODE_SUPPORT 02338 FF_wcsntocstr((FF_T_INT8 *) EntryBuffer, UTF16EntryBuffer, 11); 02339 #endif 02340 CheckSum = FF_CreateChkSum(EntryBuffer); 02341 FF_CreateLFNs(pIoman, DirCluster, pDirent->FileName, CheckSum, (FF_T_UINT16) FreeEntry); 02342 #else 02343 numLFNs = 0; 02344 #endif 02345 02346 #ifdef FF_TIME_SUPPORT 02347 FF_PlaceTime(EntryBuffer, FF_FAT_DIRENT_CREATE_TIME); 02348 FF_PlaceDate(EntryBuffer, FF_FAT_DIRENT_CREATE_DATE); 02349 FF_PlaceTime(EntryBuffer, FF_FAT_DIRENT_LASTMOD_TIME); 02350 FF_PlaceDate(EntryBuffer, FF_FAT_DIRENT_LASTMOD_DATE); 02351 #endif 02352 02353 FF_putChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB), pDirent->Attrib); 02354 FF_putShort(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_HIGH), (FF_T_UINT16)(pDirent->ObjectCluster >> 16)); 02355 FF_putShort(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_LOW), (FF_T_UINT16)(pDirent->ObjectCluster)); 02356 FF_putLong(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_FILESIZE), pDirent->Filesize); 02357 02358 RetVal = FF_InitEntryFetch(pIoman, DirCluster, &FetchContext); 02359 if(RetVal) { 02360 FF_unlockDIR(pIoman); 02361 return RetVal; 02362 } 02363 RetVal = FF_PushEntryWithContext(pIoman, (FF_T_UINT16) (FreeEntry + numLFNs), &FetchContext, EntryBuffer); 02364 FF_CleanupEntryFetch(pIoman, &FetchContext); 02365 if(RetVal) { 02366 FF_unlockDIR(pIoman); 02367 return RetVal; 02368 } 02369 /*} else { 02370 FF_unlockDIR(pIoman); 02371 return RetVal; 02372 }*/ 02373 }else { 02374 FF_unlockDIR(pIoman); 02375 return FreeEntry; 02376 } 02377 } 02378 FF_unlockDIR(pIoman); 02379 02380 if(RetVal) { 02381 return RetVal; 02382 } 02383 02384 if(pDirent) { 02385 pDirent->CurrentItem = (FF_T_UINT16) (FreeEntry + numLFNs); 02386 } 02387 02388 return FF_ERR_NONE; 02389 } 02390 02391 02392 #ifdef FF_UNICODE_SUPPORT 02393 FF_T_UINT32 FF_CreateFile(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_WCHAR *FileName, FF_DIRENT *pDirent, FF_ERROR *pError) { 02394 #else 02395 FF_T_UINT32 FF_CreateFile(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *FileName, FF_DIRENT *pDirent, FF_ERROR *pError) { 02396 #endif 02397 FF_DIRENT MyFile; 02398 *pError = FF_ERR_NONE; 02399 #ifdef FF_UNICODE_SUPPORT 02400 wcsncpy(MyFile.FileName, FileName, FF_MAX_FILENAME); 02401 #else 02402 strncpy(MyFile.FileName, FileName, FF_MAX_FILENAME); 02403 #endif 02404 02405 MyFile.Attrib = 0x00; 02406 MyFile.Filesize = 0; 02407 MyFile.ObjectCluster = FF_CreateClusterChain(pIoman, pError); 02408 if(*pError) { 02409 FF_UnlinkClusterChain(pIoman, MyFile.ObjectCluster, 0); 02410 FF_FlushCache(pIoman); 02411 return 0; 02412 } 02413 MyFile.CurrentItem = 0; 02414 02415 *pError = FF_CreateDirent(pIoman, DirCluster, &MyFile); 02416 02417 if(*pError) { 02418 FF_UnlinkClusterChain(pIoman, MyFile.ObjectCluster, 0); 02419 FF_FlushCache(pIoman); 02420 return 0; 02421 } 02422 02423 FF_FlushCache(pIoman); 02424 02425 if(pDirent) { 02426 memcpy(pDirent, &MyFile, sizeof(FF_DIRENT)); 02427 } 02428 02429 return MyFile.ObjectCluster; 02430 } 02431 02432 02444 #ifdef FF_UNICODE_SUPPORT 02445 FF_ERROR FF_MkDir(FF_IOMAN *pIoman, const FF_T_WCHAR *Path) { 02446 #else 02447 FF_ERROR FF_MkDir(FF_IOMAN *pIoman, const FF_T_INT8 *Path) { 02448 #endif 02449 FF_DIRENT MyDir; 02450 FF_T_UINT32 DirCluster; 02451 #ifdef FF_UNICODE_SUPPORT 02452 FF_T_WCHAR DirName[FF_MAX_FILENAME]; 02453 #else 02454 FF_T_INT8 DirName[FF_MAX_FILENAME]; 02455 #endif 02456 FF_T_UINT8 EntryBuffer[32]; 02457 FF_T_UINT32 DotDotCluster; 02458 FF_T_UINT16 i; 02459 FF_ERROR Error = FF_ERR_NONE; 02460 02461 FF_FETCH_CONTEXT FetchContext; 02462 02463 if(!pIoman) { 02464 return FF_ERR_NULL_POINTER; 02465 } 02466 02467 #ifdef FF_UNICODE_SUPPORT 02468 i = (FF_T_UINT16) wcslen(Path); 02469 #else 02470 i = (FF_T_UINT16) strlen(Path); 02471 #endif 02472 02473 while(i != 0) { 02474 if(Path[i] == '\\' || Path[i] == '/') { 02475 break; 02476 } 02477 i--; 02478 } 02479 02480 #ifdef FF_UNICODE_SUPPORT 02481 wcsncpy(DirName, (Path + i + 1), FF_MAX_FILENAME); 02482 #else 02483 strncpy(DirName, (Path + i + 1), FF_MAX_FILENAME); 02484 #endif 02485 02486 if(i == 0) { 02487 i = 1; 02488 } 02489 02490 DirCluster = FF_FindDir(pIoman, Path, i, &Error); 02491 02492 if(Error) { 02493 return Error; 02494 } 02495 02496 if(DirCluster) { 02497 if(FF_FindEntryInDir(pIoman, DirCluster, DirName, 0x00, &MyDir, &Error)) { 02498 return FF_ERR_DIR_OBJECT_EXISTS; 02499 } 02500 02501 if(Error && Error != FF_ERR_DIR_END_OF_DIR) { 02502 return Error; 02503 } 02504 02505 #ifdef FF_UNICODE_SUPPORT 02506 wcsncpy(MyDir.FileName, DirName, FF_MAX_FILENAME); 02507 #else 02508 strncpy(MyDir.FileName, DirName, FF_MAX_FILENAME); 02509 #endif 02510 MyDir.Filesize = 0; 02511 MyDir.Attrib = FF_FAT_ATTR_DIR; 02512 MyDir.ObjectCluster = FF_CreateClusterChain(pIoman, &Error); 02513 if(Error) { 02514 return Error; 02515 } 02516 if(MyDir.ObjectCluster) { 02517 Error = FF_ClearCluster(pIoman, MyDir.ObjectCluster); 02518 if(Error) { 02519 FF_UnlinkClusterChain(pIoman, MyDir.ObjectCluster, 0); 02520 FF_FlushCache(pIoman); 02521 return Error; 02522 } 02523 } else { 02524 // Couldn't allocate any space for the dir! 02525 return FF_ERR_DIR_EXTEND_FAILED; 02526 } 02527 02528 Error = FF_CreateDirent(pIoman, DirCluster, &MyDir); 02529 02530 if(Error) { 02531 FF_UnlinkClusterChain(pIoman, MyDir.ObjectCluster, 0); 02532 FF_FlushCache(pIoman); 02533 return Error; 02534 } 02535 02536 memset(EntryBuffer, 0, 32); 02537 EntryBuffer[0] = '.'; 02538 for(i = 1; i < 11; i++) { 02539 EntryBuffer[i] = 0x20; 02540 } 02541 FF_putChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB), FF_FAT_ATTR_DIR); 02542 FF_putShort(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_HIGH), (FF_T_UINT16)(MyDir.ObjectCluster >> 16)); 02543 FF_putShort(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_LOW), (FF_T_UINT16) MyDir.ObjectCluster); 02544 FF_putLong(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_FILESIZE), 0); 02545 02546 Error = FF_InitEntryFetch(pIoman, MyDir.ObjectCluster, &FetchContext); 02547 if(Error) { 02548 FF_UnlinkClusterChain(pIoman, MyDir.ObjectCluster, 0); 02549 FF_FlushCache(pIoman); 02550 return Error; 02551 } 02552 02553 Error = FF_PushEntryWithContext(pIoman, 0, &FetchContext, EntryBuffer); 02554 if(Error) { 02555 FF_UnlinkClusterChain(pIoman, MyDir.ObjectCluster, 0); 02556 FF_FlushCache(pIoman); 02557 FF_CleanupEntryFetch(pIoman, &FetchContext); 02558 return Error; 02559 } 02560 02561 memset(EntryBuffer, 0, 32); 02562 EntryBuffer[0] = '.'; 02563 EntryBuffer[1] = '.'; 02564 for(i = 2; i < 11; i++) { 02565 EntryBuffer[i] = 0x20; 02566 } 02567 02568 if(DirCluster == pIoman->pPartition->RootDirCluster) { 02569 DotDotCluster = 0; 02570 } else { 02571 DotDotCluster = DirCluster; 02572 } 02573 02574 FF_putChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB), FF_FAT_ATTR_DIR); 02575 FF_putShort(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_HIGH), (FF_T_UINT16)(DotDotCluster >> 16)); 02576 FF_putShort(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_LOW), (FF_T_UINT16) DotDotCluster); 02577 FF_putLong(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_FILESIZE), 0); 02578 02579 //FF_PushEntry(pIoman, MyDir.ObjectCluster, 1, EntryBuffer); 02580 Error = FF_PushEntryWithContext(pIoman, 1, &FetchContext, EntryBuffer); 02581 if(Error) { 02582 FF_UnlinkClusterChain(pIoman, MyDir.ObjectCluster, 0); 02583 FF_FlushCache(pIoman); 02584 FF_CleanupEntryFetch(pIoman, &FetchContext); 02585 return Error; 02586 } 02587 FF_CleanupEntryFetch(pIoman, &FetchContext); 02588 02589 FF_FlushCache(pIoman); // Ensure dir was flushed to the disk! 02590 02591 return FF_ERR_NONE; 02592 } 02593 02594 return FF_ERR_DIR_INVALID_PATH; 02595 } 02596 02597 02598 02599 FF_ERROR FF_RmLFNs(FF_IOMAN *pIoman, FF_T_UINT16 usDirEntry, FF_FETCH_CONTEXT *pContext) { 02600 02601 FF_ERROR Error; 02602 FF_T_UINT8 EntryBuffer[32]; 02603 02604 usDirEntry--; 02605 02606 do { 02607 Error = FF_FetchEntryWithContext(pIoman, usDirEntry, pContext, EntryBuffer); 02608 if(Error) { 02609 return Error; 02610 } 02611 02612 if(FF_getChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB)) == FF_FAT_ATTR_LFN) { 02613 FF_putChar(EntryBuffer, (FF_T_UINT16) 0, (FF_T_UINT8) 0xE5); 02614 Error = FF_PushEntryWithContext(pIoman, usDirEntry, pContext, EntryBuffer); 02615 if(Error) { 02616 return Error; 02617 } 02618 } 02619 02620 if(usDirEntry == 0) { 02621 break; 02622 } 02623 usDirEntry--; 02624 }while(FF_getChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB)) == FF_FAT_ATTR_LFN); 02625 02626 return FF_ERR_NONE; 02627 } Generated on Sun May 27 2012 04:34:05 for ReactOS by
1.7.6.1
|