Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenff_file.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_file.h" 00044 #include "ff_string.h" 00045 #include "ff_config.h" 00046 00047 #ifdef FF_UNICODE_SUPPORT 00048 #include <wchar.h> 00049 #endif 00050 00059 FF_T_UINT8 FF_GetModeBits(FF_T_INT8 *Mode) { 00060 FF_T_UINT8 ModeBits = 0x00; 00061 while(*Mode) { 00062 switch(*Mode) { 00063 case 'r': // Allow Read 00064 case 'R': 00065 ModeBits |= FF_MODE_READ; 00066 break; 00067 00068 case 'w': // Allow Write 00069 case 'W': 00070 ModeBits |= FF_MODE_WRITE; 00071 ModeBits |= FF_MODE_CREATE; // Create if not exist. 00072 ModeBits |= FF_MODE_TRUNCATE; 00073 break; 00074 00075 case 'a': // Append new writes to the end of the file. 00076 case 'A': 00077 ModeBits |= FF_MODE_WRITE; 00078 ModeBits |= FF_MODE_APPEND; 00079 ModeBits |= FF_MODE_CREATE; // Create if not exist. 00080 break; 00081 00082 case '+': // Update the file, don't Append! 00083 ModeBits |= FF_MODE_READ; // RW Mode 00084 ModeBits |= FF_MODE_WRITE; // RW Mode 00085 break; 00086 00087 /*case 'D': // Internal use only! 00088 ModeBits |= FF_MODE_DIR; 00089 break;*/ 00090 00091 default: // b|B flags not supported (Binary mode is native anyway). 00092 break; 00093 } 00094 Mode++; 00095 } 00096 00097 return ModeBits; 00098 } 00099 00151 #ifdef FF_UNICODE_SUPPORT 00152 FF_FILE *FF_Open(FF_IOMAN *pIoman, const FF_T_WCHAR *path, FF_T_UINT8 Mode, FF_ERROR *pError) { 00153 #else 00154 FF_FILE *FF_Open(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT8 Mode, FF_ERROR *pError) { 00155 #endif 00156 FF_FILE *pFile; 00157 FF_FILE *pFileChain; 00158 FF_DIRENT Object; 00159 FF_T_UINT32 DirCluster, FileCluster; 00160 FF_T_UINT32 nBytesPerCluster; 00161 #ifdef FF_UNICODE_SUPPORT 00162 FF_T_WCHAR filename[FF_MAX_FILENAME]; 00163 #else 00164 FF_T_INT8 filename[FF_MAX_FILENAME]; 00165 #endif 00166 FF_ERROR Error; 00167 00168 FF_T_UINT16 i; 00169 00170 if(pError) { 00171 *pError = 0; 00172 } 00173 00174 if(!pIoman) { 00175 if(pError) { 00176 *pError = FF_ERR_NULL_POINTER; 00177 } 00178 return (FF_FILE *)NULL; 00179 } 00180 pFile = FF_MALLOC(sizeof(FF_FILE)); 00181 if(!pFile) { 00182 if(pError) { 00183 *pError = FF_ERR_NOT_ENOUGH_MEMORY; 00184 } 00185 return (FF_FILE *)NULL; 00186 } 00187 00188 // Get the Mode Bits. 00189 pFile->Mode = Mode; 00190 00191 #ifdef FF_UNICODE_SUPPORT 00192 i = (FF_T_UINT16) wcslen(path); 00193 #else 00194 i = (FF_T_UINT16) strlen(path); 00195 #endif 00196 00197 while(i != 0) { 00198 if(path[i] == '\\' || path[i] == '/') { 00199 break; 00200 } 00201 i--; 00202 } 00203 #ifdef FF_UNICODE_SUPPORT 00204 wcsncpy(filename, (path + i + 1), FF_MAX_FILENAME); 00205 #else 00206 strncpy(filename, (path + i + 1), FF_MAX_FILENAME); 00207 #endif 00208 00209 if(i == 0) { 00210 i = 1; 00211 } 00212 00213 00214 DirCluster = FF_FindDir(pIoman, path, i, &Error); 00215 if(Error) { 00216 if(pError) { 00217 *pError = Error; 00218 } 00219 FF_FREE(pFile); 00220 return (FF_FILE *) NULL; 00221 } 00222 00223 if(DirCluster) { 00224 00225 FileCluster = FF_FindEntryInDir(pIoman, DirCluster, filename, 0x00, &Object, &Error); 00226 if(Error) { 00227 if(pError) { 00228 *pError = Error; 00229 } 00230 FF_FREE(pFile); 00231 return (FF_FILE *) NULL; 00232 } 00233 00234 if(!FileCluster) { // If 0 was returned, it might be because the file has no allocated cluster 00235 #ifdef FF_UNICODE_SUPPORT 00236 if(wcslen(filename) == wcslen(Object.FileName)) { 00237 if(Object.Filesize == 0 && FF_strmatch(filename, Object.FileName, (FF_T_UINT16) wcslen(filename)) == FF_TRUE) { 00238 #else 00239 if(strlen(filename) == strlen(Object.FileName)) { 00240 if(Object.Filesize == 0 && FF_strmatch(filename, Object.FileName, (FF_T_UINT16) strlen(filename)) == FF_TRUE) { 00241 #endif 00242 // The file really was found! 00243 FileCluster = 1; 00244 } 00245 } 00246 } 00247 00248 if(!FileCluster) { 00249 if((pFile->Mode & FF_MODE_CREATE)) { 00250 FileCluster = FF_CreateFile(pIoman, DirCluster, filename, &Object, &Error); 00251 if(Error) { 00252 if(pError) { 00253 *pError = Error; 00254 } 00255 FF_FREE(pFile); 00256 return (FF_FILE *) NULL; 00257 } 00258 Object.CurrentItem += 1; 00259 } 00260 } 00261 00262 if(FileCluster) { 00263 if(Object.Attrib == FF_FAT_ATTR_DIR) { 00264 if(!(pFile->Mode & FF_MODE_DIR)) { 00265 // Not the object, File Not Found! 00266 FF_FREE(pFile); 00267 if(pError) { 00268 *pError = FF_ERR_FILE_OBJECT_IS_A_DIR; 00269 } 00270 return (FF_FILE *) NULL; 00271 } 00272 } 00273 00274 //---------- Ensure Read-Only files don't get opened for Writing. 00275 if((pFile->Mode & FF_MODE_WRITE) || (pFile->Mode & FF_MODE_APPEND)) { 00276 if((Object.Attrib & FF_FAT_ATTR_READONLY)) { 00277 FF_FREE(pFile); 00278 if(pError) { 00279 *pError = FF_ERR_FILE_IS_READ_ONLY; 00280 } 00281 return (FF_FILE *) NULL; 00282 } 00283 } 00284 pFile->pIoman = pIoman; 00285 pFile->FilePointer = 0; 00286 pFile->ObjectCluster = Object.ObjectCluster; 00287 pFile->Filesize = Object.Filesize; 00288 pFile->CurrentCluster = 0; 00289 pFile->AddrCurrentCluster = pFile->ObjectCluster; 00290 //pFile->Mode = Mode; 00291 pFile->Next = NULL; 00292 pFile->DirCluster = DirCluster; 00293 pFile->DirEntry = Object.CurrentItem - 1; 00294 nBytesPerCluster = pFile->pIoman->pPartition->SectorsPerCluster / pIoman->BlkSize; 00295 pFile->iChainLength = 0; 00296 pFile->iEndOfChain = 0; 00297 pFile->FileDeleted = FF_FALSE; 00298 00299 // File Permission Processing 00300 // Only "w" and "w+" mode strings can erase a file's contents. 00301 // Any other combinations will not cause an erase. 00302 if((pFile->Mode & FF_MODE_TRUNCATE)) { 00303 pFile->Filesize = 0; 00304 pFile->FilePointer = 0; 00305 } 00306 00307 /* 00308 Add pFile onto the end of our linked list of FF_FILE objects. 00309 */ 00310 FF_PendSemaphore(pIoman->pSemaphore); 00311 { 00312 if(!pIoman->FirstFile) { 00313 pIoman->FirstFile = pFile; 00314 } else { 00315 pFileChain = (FF_FILE *) pIoman->FirstFile; 00316 do { 00317 if(pFileChain->ObjectCluster == pFile->ObjectCluster) { 00318 // File is already open! DON'T ALLOW IT! 00319 FF_ReleaseSemaphore(pIoman->pSemaphore); 00320 FF_FREE(pFile); 00321 if(pError) { 00322 *pError = FF_ERR_FILE_ALREADY_OPEN; 00323 } 00324 return (FF_FILE *) NULL; 00325 } 00326 if(!pFileChain->Next) { 00327 pFileChain->Next = pFile; 00328 break; 00329 } 00330 pFileChain = (FF_FILE *) pFileChain->Next; 00331 }while(pFileChain != NULL); 00332 } 00333 } 00334 FF_ReleaseSemaphore(pIoman->pSemaphore); 00335 00336 return pFile; 00337 }else { 00338 FF_FREE(pFile); 00339 if(pError) { 00340 *pError = FF_ERR_FILE_NOT_FOUND; 00341 } 00342 return (FF_FILE *) NULL; 00343 } 00344 } 00345 if(pError) { 00346 *pError = FF_ERR_FILE_INVALID_PATH; 00347 } 00348 00349 FF_FREE(pFile); 00350 00351 return (FF_FILE *)NULL; 00352 } 00353 00354 00362 #ifdef FF_UNICODE_SUPPORT 00363 FF_T_BOOL FF_isDirEmpty(FF_IOMAN *pIoman, const FF_T_WCHAR *Path) { 00364 #else 00365 FF_T_BOOL FF_isDirEmpty(FF_IOMAN *pIoman, const FF_T_INT8 *Path) { 00366 #endif 00367 00368 FF_DIRENT MyDir; 00369 FF_ERROR RetVal = FF_ERR_NONE; 00370 FF_T_UINT8 i = 0; 00371 00372 if(!pIoman) { 00373 return FF_FALSE; 00374 } 00375 00376 RetVal = FF_FindFirst(pIoman, &MyDir, Path); 00377 while(RetVal == 0) { 00378 i++; 00379 RetVal = FF_FindNext(pIoman, &MyDir); 00380 if(i > 2) { 00381 return FF_FALSE; 00382 } 00383 } 00384 00385 return FF_TRUE; 00386 } 00387 00388 #ifdef FF_UNICODE_SUPPORT 00389 FF_ERROR FF_RmDir(FF_IOMAN *pIoman, const FF_T_WCHAR *path) { 00390 #else 00391 FF_ERROR FF_RmDir(FF_IOMAN *pIoman, const FF_T_INT8 *path) { 00392 #endif 00393 FF_FILE *pFile; 00394 FF_ERROR Error = FF_ERR_NONE; 00395 FF_T_UINT8 EntryBuffer[32]; 00396 FF_FETCH_CONTEXT FetchContext; 00397 FF_T_SINT8 RetVal = FF_ERR_NONE; 00398 #ifdef FF_PATH_CACHE 00399 FF_T_UINT32 i; 00400 #endif 00401 00402 if(!pIoman) { 00403 return FF_ERR_NULL_POINTER; 00404 } 00405 00406 pFile = FF_Open(pIoman, path, FF_MODE_DIR, &Error); 00407 00408 if(!pFile) { 00409 return Error; // File in use or File not found! 00410 } 00411 00412 pFile->FileDeleted = FF_TRUE; 00413 00414 FF_lockDIR(pIoman); 00415 { 00416 if(FF_isDirEmpty(pIoman, path)) { 00417 FF_lockFAT(pIoman); 00418 { 00419 Error = FF_UnlinkClusterChain(pIoman, pFile->ObjectCluster, 0); // 0 to delete the entire chain! 00420 } 00421 FF_unlockFAT(pIoman); 00422 00423 if(Error) { 00424 FF_unlockDIR(pIoman); 00425 FF_Close(pFile); 00426 return Error; 00427 } 00428 00429 // Initialise the dirent Fetch Context object for faster removal of dirents. 00430 00431 Error = FF_InitEntryFetch(pIoman, pFile->DirCluster, &FetchContext); 00432 if(Error) { 00433 FF_unlockDIR(pIoman); 00434 FF_Close(pFile); 00435 return Error; 00436 } 00437 00438 // Edit the Directory Entry! (So it appears as deleted); 00439 Error = FF_RmLFNs(pIoman, pFile->DirEntry, &FetchContext); 00440 if(Error) { 00441 FF_CleanupEntryFetch(pIoman, &FetchContext); 00442 FF_unlockDIR(pIoman); 00443 FF_Close(pFile); 00444 return Error; 00445 } 00446 Error = FF_FetchEntryWithContext(pIoman, pFile->DirEntry, &FetchContext, EntryBuffer); 00447 if(Error) { 00448 FF_CleanupEntryFetch(pIoman, &FetchContext); 00449 FF_unlockDIR(pIoman); 00450 FF_Close(pFile); 00451 return Error; 00452 } 00453 EntryBuffer[0] = 0xE5; 00454 Error = FF_PushEntryWithContext(pIoman, pFile->DirEntry, &FetchContext, EntryBuffer); 00455 if(Error) { 00456 FF_CleanupEntryFetch(pIoman, &FetchContext); 00457 FF_unlockDIR(pIoman); 00458 FF_Close(pFile); 00459 return Error; 00460 } 00461 #ifdef FF_PATH_CACHE 00462 FF_PendSemaphore(pIoman->pSemaphore); // Thread safety on shared object! 00463 { 00464 for(i = 0; i < FF_PATH_CACHE_DEPTH; i++) { 00465 #ifdef FF_UNICODE_SUPPORT 00466 if(FF_strmatch(pIoman->pPartition->PathCache[i].Path, path, (FF_T_UINT16)wcslen(path))) { 00467 #else 00468 if(FF_strmatch(pIoman->pPartition->PathCache[i].Path, path, (FF_T_UINT16)strlen(path))) { 00469 #endif 00470 pIoman->pPartition->PathCache[i].Path[0] = '\0'; 00471 pIoman->pPartition->PathCache[i].DirCluster = 0; 00472 FF_ReleaseSemaphore(pIoman->pSemaphore); 00473 } 00474 } 00475 } 00476 FF_ReleaseSemaphore(pIoman->pSemaphore); 00477 #endif 00478 00479 Error = FF_IncreaseFreeClusters(pIoman, pFile->iChainLength); 00480 if(Error) { 00481 FF_CleanupEntryFetch(pIoman, &FetchContext); 00482 FF_unlockDIR(pIoman); 00483 FF_Close(pFile); 00484 return Error; 00485 } 00486 00487 FF_CleanupEntryFetch(pIoman, &FetchContext); 00488 00489 Error = FF_FlushCache(pIoman); 00490 if(Error) { 00491 FF_unlockDIR(pIoman); 00492 FF_Close(pFile); 00493 return Error; 00494 } 00495 } else { 00496 RetVal = FF_ERR_DIR_NOT_EMPTY; 00497 } 00498 } 00499 FF_unlockDIR(pIoman); 00500 Error = FF_Close(pFile); // Free the file pointer resources 00501 00502 if(Error) { 00503 return Error; 00504 } 00505 00506 // File is now lost! 00507 return RetVal; 00508 } 00509 00510 #ifdef FF_UNICODE_SUPPORT 00511 FF_ERROR FF_RmFile(FF_IOMAN *pIoman, const FF_T_WCHAR *path) { 00512 #else 00513 FF_ERROR FF_RmFile(FF_IOMAN *pIoman, const FF_T_INT8 *path) { 00514 #endif 00515 FF_FILE *pFile; 00516 FF_ERROR Error = FF_ERR_NONE; 00517 FF_T_UINT8 EntryBuffer[32]; 00518 FF_FETCH_CONTEXT FetchContext; 00519 00520 pFile = FF_Open(pIoman, path, FF_MODE_READ, &Error); 00521 00522 if(!pFile) { 00523 return Error; // File in use or File not found! 00524 } 00525 00526 pFile->FileDeleted = FF_TRUE; 00527 00528 if(pFile->ObjectCluster) { // Ensure there is actually a cluster chain to delete! 00529 FF_lockFAT(pIoman); // Lock the FAT so its thread-safe. 00530 { 00531 Error = FF_UnlinkClusterChain(pIoman, pFile->ObjectCluster, 0); // 0 to delete the entire chain! 00532 } 00533 FF_unlockFAT(pIoman); 00534 00535 if(Error) { 00536 FF_Close(pFile); 00537 return Error; 00538 } 00539 } 00540 00541 // Edit the Directory Entry! (So it appears as deleted); 00542 FF_lockDIR(pIoman); 00543 { 00544 Error = FF_InitEntryFetch(pIoman, pFile->DirCluster, &FetchContext); 00545 if(Error) { 00546 FF_unlockDIR(pIoman); 00547 FF_Close(pFile); 00548 return Error; 00549 } 00550 Error = FF_RmLFNs(pIoman, pFile->DirEntry, &FetchContext); 00551 if(Error) { 00552 FF_CleanupEntryFetch(pIoman, &FetchContext); 00553 FF_unlockDIR(pIoman); 00554 FF_Close(pFile); 00555 return Error; 00556 } 00557 Error = FF_FetchEntryWithContext(pIoman, pFile->DirEntry, &FetchContext, EntryBuffer); 00558 if(Error) { 00559 FF_CleanupEntryFetch(pIoman, &FetchContext); 00560 FF_unlockDIR(pIoman); 00561 FF_Close(pFile); 00562 return Error; 00563 } 00564 EntryBuffer[0] = 0xE5; 00565 00566 Error = FF_PushEntryWithContext(pIoman, pFile->DirEntry, &FetchContext, EntryBuffer); 00567 if(Error) { 00568 FF_CleanupEntryFetch(pIoman, &FetchContext); 00569 FF_unlockDIR(pIoman); 00570 FF_Close(pFile); 00571 return Error; 00572 } 00573 00574 FF_CleanupEntryFetch(pIoman, &FetchContext); 00575 } 00576 FF_unlockDIR(pIoman); 00577 00578 Error = FF_FlushCache(pIoman); 00579 if(Error) { 00580 FF_Close(pFile); 00581 return Error; 00582 } 00583 00584 Error = FF_Close(pFile); // Free the file pointer resources 00585 return Error; 00586 } 00587 00603 #ifdef FF_UNICODE_SUPPORT 00604 FF_ERROR FF_Move(FF_IOMAN *pIoman, const FF_T_WCHAR *szSourceFile, const FF_T_WCHAR *szDestinationFile) { 00605 #else 00606 FF_ERROR FF_Move(FF_IOMAN *pIoman, const FF_T_INT8 *szSourceFile, const FF_T_INT8 *szDestinationFile) { 00607 #endif 00608 FF_ERROR Error; 00609 FF_FILE *pSrcFile, *pDestFile; 00610 FF_DIRENT MyFile; 00611 FF_T_UINT8 EntryBuffer[32]; 00612 FF_T_UINT16 i; 00613 FF_T_UINT32 DirCluster; 00614 FF_FETCH_CONTEXT FetchContext; 00615 00616 if(!pIoman) { 00617 return FF_ERR_NULL_POINTER; 00618 } 00619 00620 // Check destination file doesn't exist! 00621 pDestFile = FF_Open(pIoman, szDestinationFile, FF_MODE_READ, &Error); 00622 00623 if(pDestFile || (Error == FF_ERR_FILE_OBJECT_IS_A_DIR)) { 00624 FF_Close(pDestFile); 00625 return FF_ERR_FILE_DESTINATION_EXISTS; // YES -- FAIL 00626 } 00627 00628 pSrcFile = FF_Open(pIoman, szSourceFile, FF_MODE_READ, &Error); 00629 00630 if(Error == FF_ERR_FILE_OBJECT_IS_A_DIR) { 00631 // Open a directory for moving! 00632 pSrcFile = FF_Open(pIoman, szSourceFile, FF_MODE_DIR, &Error); 00633 } 00634 00635 if(!pSrcFile) { 00636 return Error; 00637 } 00638 00639 if(pSrcFile) { 00640 // Create the new dirent. 00641 Error = FF_InitEntryFetch(pIoman, pSrcFile->DirCluster, &FetchContext); 00642 if(Error) { 00643 FF_Close(pSrcFile); 00644 return Error; 00645 } 00646 Error = FF_FetchEntryWithContext(pIoman, pSrcFile->DirEntry, &FetchContext, EntryBuffer); 00647 if(Error) { 00648 FF_Close(pSrcFile); 00649 FF_CleanupEntryFetch(pIoman, &FetchContext); 00650 return Error; 00651 } 00652 //FF_FetchEntry(pIoman, pSrcFile->DirCluster, pSrcFile->DirEntry, EntryBuffer); 00653 MyFile.Attrib = FF_getChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB)); 00654 MyFile.Filesize = pSrcFile->Filesize; 00655 MyFile.ObjectCluster = pSrcFile->ObjectCluster; 00656 MyFile.CurrentItem = 0; 00657 00658 #ifdef FF_UNICODE_SUPPORT 00659 i = (FF_T_UINT16) wcslen(szDestinationFile); 00660 #else 00661 i = (FF_T_UINT16) strlen(szDestinationFile); 00662 #endif 00663 00664 while(i != 0) { 00665 if(szDestinationFile[i] == '\\' || szDestinationFile[i] == '/') { 00666 break; 00667 } 00668 i--; 00669 } 00670 00671 #ifdef FF_UNICODE_SUPPORT 00672 wcsncpy(MyFile.FileName, (szDestinationFile + i + 1), FF_MAX_FILENAME); 00673 #else 00674 strncpy(MyFile.FileName, (szDestinationFile + i + 1), FF_MAX_FILENAME); 00675 #endif 00676 00677 if(i == 0) { 00678 i = 1; 00679 } 00680 00681 00682 DirCluster = FF_FindDir(pIoman, szDestinationFile, i, &Error); 00683 if(Error) { 00684 FF_Close(pSrcFile); 00685 FF_CleanupEntryFetch(pIoman, &FetchContext); 00686 return Error; 00687 } 00688 00689 if(DirCluster) { 00690 00691 // Destination Dir was found, we can now create the new entry. 00692 Error = FF_CreateDirent(pIoman, DirCluster, &MyFile); 00693 if(Error) { 00694 FF_Close(pSrcFile); 00695 FF_CleanupEntryFetch(pIoman, &FetchContext); 00696 return Error; // FAILED 00697 } 00698 00699 // Edit the Directory Entry! (So it appears as deleted); 00700 FF_lockDIR(pIoman); 00701 { 00702 00703 Error = FF_RmLFNs(pIoman, pSrcFile->DirEntry, &FetchContext); 00704 if(Error) { 00705 FF_unlockDIR(pIoman); 00706 FF_Close(pSrcFile); 00707 FF_CleanupEntryFetch(pIoman, &FetchContext); 00708 return Error; 00709 } 00710 Error = FF_FetchEntryWithContext(pIoman, pSrcFile->DirEntry, &FetchContext, EntryBuffer); 00711 if(Error) { 00712 FF_unlockDIR(pIoman); 00713 FF_Close(pSrcFile); 00714 FF_CleanupEntryFetch(pIoman, &FetchContext); 00715 return Error; 00716 } 00717 EntryBuffer[0] = 0xE5; 00718 //FF_PushEntry(pIoman, pSrcFile->DirCluster, pSrcFile->DirEntry, EntryBuffer); 00719 Error = FF_PushEntryWithContext(pIoman, pSrcFile->DirEntry, &FetchContext, EntryBuffer); 00720 if(Error) { 00721 FF_unlockDIR(pIoman); 00722 FF_Close(pSrcFile); 00723 FF_CleanupEntryFetch(pIoman, &FetchContext); 00724 return Error; 00725 } 00726 FF_CleanupEntryFetch(pIoman, &FetchContext); 00727 } 00728 FF_unlockDIR(pIoman); 00729 FF_Close(pSrcFile); 00730 00731 FF_FlushCache(pIoman); 00732 00733 return FF_ERR_NONE; 00734 } 00735 00736 return FF_ERR_FILE_DIR_NOT_FOUND; 00737 00738 } 00739 00740 return FF_ERR_FILE_SOURCE_NOT_FOUND; // Source not found! 00741 } 00742 00743 00754 FF_T_BOOL FF_isEOF(FF_FILE *pFile) { 00755 if(!pFile) { 00756 return FF_FALSE; 00757 } 00758 if(pFile->FilePointer >= pFile->Filesize) { 00759 return FF_TRUE; 00760 } else { 00761 return FF_FALSE; 00762 } 00763 } 00764 00765 static FF_T_UINT32 FF_GetSequentialClusters(FF_IOMAN *pIoman, FF_T_UINT32 StartCluster, FF_T_UINT32 Limit, FF_ERROR *pError) { 00766 FF_T_UINT32 CurrentCluster; 00767 FF_T_UINT32 NextCluster = StartCluster; 00768 FF_T_UINT32 i = 0; 00769 00770 *pError = FF_ERR_NONE; 00771 00772 do { 00773 CurrentCluster = NextCluster; 00774 NextCluster = FF_getFatEntry(pIoman, CurrentCluster, pError); 00775 if(*pError) { 00776 return 0; 00777 } 00778 if(NextCluster == (CurrentCluster + 1)) { 00779 i++; 00780 } else { 00781 break; 00782 } 00783 00784 if(Limit) { 00785 if(i == Limit) { 00786 break; 00787 } 00788 } 00789 }while(NextCluster == (CurrentCluster + 1)); 00790 00791 return i; 00792 } 00793 00794 static FF_ERROR FF_ReadClusters(FF_FILE *pFile, FF_T_UINT32 Count, FF_T_UINT8 *buffer) { 00795 FF_T_UINT32 ulSectors; 00796 FF_T_UINT32 SequentialClusters = 0; 00797 FF_T_UINT32 nItemLBA; 00798 FF_T_SINT32 slRetVal; 00799 FF_ERROR Error; 00800 00801 while(Count != 0) { 00802 if((Count - 1) > 0) { 00803 SequentialClusters = FF_GetSequentialClusters(pFile->pIoman, pFile->AddrCurrentCluster, (Count - 1), &Error); 00804 if(Error) { 00805 return Error; 00806 } 00807 } 00808 ulSectors = (SequentialClusters + 1) * pFile->pIoman->pPartition->SectorsPerCluster; 00809 nItemLBA = FF_Cluster2LBA(pFile->pIoman, pFile->AddrCurrentCluster); 00810 nItemLBA = FF_getRealLBA(pFile->pIoman, nItemLBA); 00811 00812 slRetVal = FF_BlockRead(pFile->pIoman, nItemLBA, ulSectors, buffer); 00813 if(slRetVal < 0) { 00814 return slRetVal; 00815 } 00816 00817 Count -= (SequentialClusters + 1); 00818 pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->AddrCurrentCluster, (SequentialClusters + 1), &Error); 00819 if(Error) { 00820 return Error; 00821 } 00822 pFile->CurrentCluster += (SequentialClusters + 1); 00823 buffer += ulSectors * pFile->pIoman->BlkSize; 00824 SequentialClusters = 0; 00825 } 00826 00827 return FF_ERR_NONE; 00828 } 00829 00830 00831 static FF_ERROR FF_ExtendFile(FF_FILE *pFile, FF_T_UINT32 Size) { 00832 FF_IOMAN *pIoman = pFile->pIoman; 00833 FF_T_UINT32 nBytesPerCluster = pIoman->pPartition->BlkSize * pIoman->pPartition->SectorsPerCluster; 00834 FF_T_UINT32 nTotalClustersNeeded = Size / nBytesPerCluster; 00835 FF_T_UINT32 nClusterToExtend; 00836 FF_T_UINT32 CurrentCluster, NextCluster; 00837 FF_T_UINT32 i; 00838 FF_DIRENT OriginalEntry; 00839 FF_ERROR Error; 00840 00841 if((pFile->Mode & FF_MODE_WRITE) != FF_MODE_WRITE) { 00842 return FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE; 00843 } 00844 00845 if(pFile->Filesize == 0 && pFile->ObjectCluster == 0) { // No Allocated clusters. 00846 // Create a Cluster chain! 00847 pFile->AddrCurrentCluster = FF_CreateClusterChain(pFile->pIoman, &Error); 00848 00849 if(Error) { 00850 return Error; 00851 } 00852 00853 Error = FF_GetEntry(pIoman, pFile->DirEntry, pFile->DirCluster, &OriginalEntry); 00854 00855 if(!Error) { 00856 OriginalEntry.ObjectCluster = pFile->AddrCurrentCluster; 00857 Error = FF_PutEntry(pIoman, pFile->DirEntry, pFile->DirCluster, &OriginalEntry); 00858 } else { 00859 return Error; 00860 } 00861 00862 if(Error) { 00863 return Error; 00864 } 00865 00866 pFile->ObjectCluster = pFile->AddrCurrentCluster; 00867 pFile->iChainLength = 1; 00868 pFile->CurrentCluster = 0; 00869 pFile->iEndOfChain = pFile->AddrCurrentCluster; 00870 } 00871 00872 if(Size % nBytesPerCluster) { 00873 nTotalClustersNeeded += 1; 00874 } 00875 00876 if(pFile->iChainLength == 0) { // First extension requiring the chain length, 00877 pFile->iChainLength = FF_GetChainLength(pIoman, pFile->ObjectCluster, &pFile->iEndOfChain, &Error); 00878 if(Error) { 00879 return Error; 00880 } 00881 } 00882 00883 nClusterToExtend = (nTotalClustersNeeded - pFile->iChainLength); 00884 00885 if(nTotalClustersNeeded > pFile->iChainLength) { 00886 00887 NextCluster = pFile->AddrCurrentCluster; 00888 FF_lockFAT(pIoman); 00889 { 00890 for(i = 0; i <= nClusterToExtend; i++) { 00891 CurrentCluster = FF_FindEndOfChain(pIoman, NextCluster, &Error); 00892 if(Error) { 00893 FF_unlockFAT(pIoman); 00894 FF_DecreaseFreeClusters(pIoman, i); 00895 return Error; 00896 } 00897 NextCluster = FF_FindFreeCluster(pIoman, &Error); 00898 if(Error) { 00899 FF_unlockFAT(pIoman); 00900 FF_DecreaseFreeClusters(pIoman, i); 00901 return Error; 00902 } 00903 if(!NextCluster) { 00904 FF_unlockFAT(pIoman); 00905 FF_DecreaseFreeClusters(pIoman, i); 00906 return FF_ERR_FAT_NO_FREE_CLUSTERS; 00907 } 00908 00909 Error = FF_putFatEntry(pIoman, CurrentCluster, NextCluster); 00910 if(Error) { 00911 FF_unlockFAT(pIoman); 00912 FF_DecreaseFreeClusters(pIoman, i); 00913 return Error; 00914 } 00915 Error = FF_putFatEntry(pIoman, NextCluster, 0xFFFFFFFF); 00916 if(Error) { 00917 FF_unlockFAT(pIoman); 00918 FF_DecreaseFreeClusters(pIoman, i); 00919 return Error; 00920 } 00921 } 00922 00923 pFile->iEndOfChain = FF_FindEndOfChain(pIoman, NextCluster, &Error); 00924 if(Error) { 00925 FF_unlockFAT(pIoman); 00926 FF_DecreaseFreeClusters(pIoman, i); 00927 return Error; 00928 } 00929 } 00930 FF_unlockFAT(pIoman); 00931 00932 pFile->iChainLength += i; 00933 Error = FF_DecreaseFreeClusters(pIoman, i); // Keep Tab of Numbers for fast FreeSize() 00934 if(Error) { 00935 return Error; 00936 } 00937 } 00938 00939 return FF_ERR_NONE; 00940 } 00941 00942 static FF_ERROR FF_WriteClusters(FF_FILE *pFile, FF_T_UINT32 Count, FF_T_UINT8 *buffer) { 00943 FF_T_UINT32 ulSectors; 00944 FF_T_UINT32 SequentialClusters = 0; 00945 FF_T_UINT32 nItemLBA; 00946 FF_T_SINT32 slRetVal; 00947 FF_ERROR Error; 00948 00949 while(Count != 0) { 00950 if((Count - 1) > 0) { 00951 SequentialClusters = FF_GetSequentialClusters(pFile->pIoman, pFile->AddrCurrentCluster, (Count - 1), &Error); 00952 if(Error) { 00953 return Error; 00954 } 00955 } 00956 ulSectors = (SequentialClusters + 1) * pFile->pIoman->pPartition->SectorsPerCluster; 00957 nItemLBA = FF_Cluster2LBA(pFile->pIoman, pFile->AddrCurrentCluster); 00958 nItemLBA = FF_getRealLBA(pFile->pIoman, nItemLBA); 00959 00960 slRetVal = FF_BlockWrite(pFile->pIoman, nItemLBA, ulSectors, buffer); 00961 00962 if(slRetVal < 0) { 00963 return slRetVal; 00964 } 00965 00966 Count -= (SequentialClusters + 1); 00967 pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->AddrCurrentCluster, (SequentialClusters + 1), &Error); 00968 if(Error) { 00969 return Error; 00970 } 00971 pFile->CurrentCluster += (SequentialClusters + 1); 00972 buffer += ulSectors * pFile->pIoman->BlkSize; 00973 SequentialClusters = 0; 00974 } 00975 00976 return 0; 00977 } 00978 00991 FF_T_SINT32 FF_Read(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, FF_T_UINT8 *buffer) { 00992 FF_T_UINT32 nBytes = ElementSize * Count; 00993 FF_T_UINT32 nBytesRead = 0; 00994 FF_T_UINT32 nBytesToRead; 00995 FF_IOMAN *pIoman; 00996 FF_BUFFER *pBuffer; 00997 FF_T_UINT32 nRelBlockPos; 00998 FF_T_UINT32 nItemLBA; 00999 FF_T_SINT32 RetVal = 0; 01000 FF_T_UINT16 sSectors; 01001 FF_T_UINT32 nRelClusterPos; 01002 FF_T_UINT32 nBytesPerCluster; 01003 FF_T_UINT32 nClusterDiff; 01004 FF_ERROR Error; 01005 01006 if(!pFile) { 01007 return FF_ERR_NULL_POINTER; 01008 } 01009 01010 if(!(pFile->Mode & FF_MODE_READ)) { 01011 return FF_ERR_FILE_NOT_OPENED_IN_READ_MODE; 01012 } 01013 01014 pIoman = pFile->pIoman; 01015 01016 if(pFile->FilePointer == pFile->Filesize) { 01017 return 0; 01018 } 01019 01020 if((pFile->FilePointer + nBytes) > pFile->Filesize) { 01021 nBytes = pFile->Filesize - pFile->FilePointer; 01022 } 01023 01024 nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; 01025 if(nClusterDiff) { 01026 if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { 01027 pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff, &Error); 01028 if(Error) { 01029 return Error; 01030 } 01031 pFile->CurrentCluster += nClusterDiff; 01032 } 01033 } 01034 01035 nRelBlockPos = FF_getMinorBlockEntry(pIoman, pFile->FilePointer, 1); // Get the position within a block. 01036 01037 nItemLBA = FF_Cluster2LBA(pIoman, pFile->AddrCurrentCluster); 01038 nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1); 01039 01040 if((nRelBlockPos + nBytes) < pIoman->BlkSize) { // Bytes to read are within a block and less than a block size. 01041 pBuffer = FF_GetBuffer(pIoman, nItemLBA, FF_MODE_READ); 01042 { 01043 if(!pBuffer) { 01044 return FF_ERR_DEVICE_DRIVER_FAILED; 01045 } 01046 memcpy(buffer, (pBuffer->pBuffer + nRelBlockPos), nBytes); 01047 } 01048 FF_ReleaseBuffer(pIoman, pBuffer); 01049 01050 pFile->FilePointer += nBytes; 01051 01052 return nBytes; // Return the number of bytes read. 01053 01054 } else { 01055 01056 //---------- Read (memcpy) to a Sector Boundary 01057 if(nRelBlockPos != 0) { // Not on a sector boundary, at this point the LBA is known. 01058 nBytesToRead = pIoman->BlkSize - nRelBlockPos; 01059 pBuffer = FF_GetBuffer(pIoman, nItemLBA, FF_MODE_READ); 01060 { 01061 if(!pBuffer) { 01062 return FF_ERR_DEVICE_DRIVER_FAILED; 01063 } 01064 // Here we copy to the sector boudary. 01065 memcpy(buffer, (pBuffer->pBuffer + nRelBlockPos), nBytesToRead); 01066 } 01067 FF_ReleaseBuffer(pIoman, pBuffer); 01068 01069 nBytes -= nBytesToRead; 01070 nBytesRead += nBytesToRead; 01071 pFile->FilePointer += nBytesToRead; 01072 buffer += nBytesToRead; 01073 01074 } 01075 01076 //---------- Read to a Cluster Boundary 01077 01078 nRelClusterPos = FF_getClusterPosition(pIoman, pFile->FilePointer, 1); 01079 nBytesPerCluster = (pIoman->pPartition->SectorsPerCluster * pIoman->BlkSize); 01080 if(nRelClusterPos != 0 && nBytes >= nBytesPerCluster) { // Need to get to cluster boundary 01081 01082 nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; 01083 if(nClusterDiff) { 01084 if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { 01085 pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff, &Error); 01086 if(Error) { 01087 return Error; 01088 } 01089 pFile->CurrentCluster += nClusterDiff; 01090 } 01091 } 01092 01093 nItemLBA = FF_Cluster2LBA(pIoman, pFile->AddrCurrentCluster); 01094 nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1); 01095 01096 sSectors = (FF_T_UINT16) (pIoman->pPartition->SectorsPerCluster - (nRelClusterPos / pIoman->BlkSize)); 01097 01098 RetVal = FF_BlockRead(pIoman, nItemLBA, (FF_T_UINT32) sSectors, buffer); 01099 01100 nBytesToRead = sSectors * pIoman->BlkSize; 01101 nBytes -= nBytesToRead; 01102 buffer += nBytesToRead; 01103 nBytesRead += nBytesToRead; 01104 pFile->FilePointer += nBytesToRead; 01105 01106 } 01107 01108 //---------- Read Clusters 01109 if(nBytes >= nBytesPerCluster) { 01110 //----- Thanks to Christopher Clark of DigiPen Institute of Technology in Redmond, US adding this traversal check. 01111 nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; 01112 if(nClusterDiff) { 01113 if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { 01114 pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff, &Error); 01115 if(Error) { 01116 return Error; 01117 } 01118 pFile->CurrentCluster += nClusterDiff; 01119 } 01120 } 01121 //----- End of Contributor fix. 01122 01123 RetVal = FF_ReadClusters(pFile, (nBytes / nBytesPerCluster), buffer); 01124 if(RetVal < 0) { 01125 return RetVal; 01126 } 01127 nBytesToRead = (nBytesPerCluster * (nBytes / nBytesPerCluster)); 01128 01129 pFile->FilePointer += nBytesToRead; 01130 01131 nBytes -= nBytesToRead; 01132 buffer += nBytesToRead; 01133 nBytesRead += nBytesToRead; 01134 } 01135 01136 //---------- Read Remaining Blocks 01137 if(nBytes >= pIoman->BlkSize) { 01138 sSectors = (FF_T_UINT16) (nBytes / pIoman->BlkSize); 01139 01140 nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; 01141 if(nClusterDiff) { 01142 if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { 01143 pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff, &Error); 01144 if(Error) { 01145 return Error; 01146 } 01147 pFile->CurrentCluster += nClusterDiff; 01148 } 01149 } 01150 01151 nItemLBA = FF_Cluster2LBA(pIoman, pFile->AddrCurrentCluster); 01152 nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1); 01153 01154 RetVal = FF_BlockRead(pIoman, nItemLBA, (FF_T_UINT32) sSectors, buffer); 01155 01156 if(RetVal < 0) { 01157 return RetVal; 01158 } 01159 01160 nBytesToRead = sSectors * pIoman->BlkSize; 01161 pFile->FilePointer += nBytesToRead; 01162 nBytes -= nBytesToRead; 01163 buffer += nBytesToRead; 01164 nBytesRead += nBytesToRead; 01165 } 01166 01167 //---------- Read (memcpy) Remaining Bytes 01168 if(nBytes > 0) { 01169 01170 nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; 01171 if(nClusterDiff) { 01172 if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { 01173 pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff, &Error); 01174 if(Error) { 01175 return Error; 01176 } 01177 pFile->CurrentCluster += nClusterDiff; 01178 } 01179 } 01180 01181 nItemLBA = FF_Cluster2LBA(pIoman, pFile->AddrCurrentCluster); 01182 nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1); 01183 pBuffer = FF_GetBuffer(pIoman, nItemLBA, FF_MODE_READ); 01184 { 01185 if(!pBuffer) { 01186 return FF_ERR_DEVICE_DRIVER_FAILED; 01187 } 01188 memcpy(buffer, pBuffer->pBuffer, nBytes); 01189 } 01190 FF_ReleaseBuffer(pIoman, pBuffer); 01191 01192 nBytesToRead = nBytes; 01193 pFile->FilePointer += nBytesToRead; 01194 nBytes -= nBytesToRead; 01195 buffer += nBytesToRead; 01196 nBytesRead += nBytesToRead; 01197 01198 } 01199 } 01200 01201 return nBytesRead; 01202 } 01203 01204 01205 01206 01218 FF_T_SINT32 FF_GetC(FF_FILE *pFile) { 01219 FF_T_UINT32 fileLBA; 01220 FF_BUFFER *pBuffer; 01221 FF_T_UINT8 retChar; 01222 FF_T_UINT32 relMinorBlockPos; 01223 FF_T_UINT32 clusterNum; 01224 FF_T_UINT32 nClusterDiff; 01225 FF_ERROR Error; 01226 01227 01228 if(!pFile) { 01229 return FF_ERR_NULL_POINTER; 01230 } 01231 01232 if(!(pFile->Mode & FF_MODE_READ)) { 01233 return FF_ERR_FILE_NOT_OPENED_IN_READ_MODE; 01234 } 01235 01236 if(pFile->FilePointer >= pFile->Filesize) { 01237 return -1; // EOF! 01238 } 01239 01240 relMinorBlockPos = FF_getMinorBlockEntry(pFile->pIoman, pFile->FilePointer, 1); 01241 clusterNum = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1); 01242 01243 nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; 01244 if(nClusterDiff) { 01245 if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { 01246 pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->AddrCurrentCluster, nClusterDiff, &Error); 01247 if(Error) { 01248 return Error; 01249 } 01250 pFile->CurrentCluster += nClusterDiff; 01251 } 01252 } 01253 01254 01255 fileLBA = FF_Cluster2LBA(pFile->pIoman, pFile->AddrCurrentCluster) + FF_getMajorBlockNumber(pFile->pIoman, pFile->FilePointer, (FF_T_UINT16) 1); 01256 fileLBA = FF_getRealLBA (pFile->pIoman, fileLBA) + FF_getMinorBlockNumber(pFile->pIoman, pFile->FilePointer, (FF_T_UINT16) 1); 01257 01258 pBuffer = FF_GetBuffer(pFile->pIoman, fileLBA, FF_MODE_READ); 01259 { 01260 if(!pBuffer) { 01261 return FF_ERR_DEVICE_DRIVER_FAILED; 01262 } 01263 retChar = pBuffer->pBuffer[relMinorBlockPos]; 01264 } 01265 FF_ReleaseBuffer(pFile->pIoman, pBuffer); 01266 01267 pFile->FilePointer += 1; 01268 01269 return (FF_T_INT32) retChar; 01270 } 01271 01272 01291 FF_T_SINT32 FF_GetLine(FF_FILE *pFile, FF_T_INT8 *szLine, FF_T_UINT32 ulLimit) { 01292 FF_T_SINT32 c; 01293 FF_T_UINT32 i; 01294 01295 if(!pFile || !szLine) { 01296 return FF_ERR_NULL_POINTER; 01297 } 01298 01299 for(i = 0; i < (ulLimit - 1) && (c=FF_GetC(pFile)) >= 0 && c != '\n'; ++i) { 01300 if(c == '\r') { 01301 i--; 01302 } else { 01303 szLine[i] = (FF_T_INT8) c; 01304 } 01305 } 01306 01307 szLine[i] = '\0'; 01308 return i; 01309 } 01310 01311 FF_T_UINT32 FF_Tell(FF_FILE *pFile) { 01312 return pFile->FilePointer; 01313 } 01314 01315 01327 FF_T_SINT32 FF_Write(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, FF_T_UINT8 *buffer) { 01328 FF_T_UINT32 nBytes = ElementSize * Count; 01329 FF_T_UINT32 nBytesWritten = 0; 01330 FF_T_UINT32 nBytesToWrite; 01331 FF_IOMAN *pIoman; 01332 FF_BUFFER *pBuffer; 01333 FF_T_UINT32 nRelBlockPos; 01334 FF_T_UINT32 nItemLBA; 01335 FF_T_SINT32 slRetVal = 0; 01336 FF_T_UINT16 sSectors; 01337 FF_T_UINT32 nRelClusterPos; 01338 FF_T_UINT32 nBytesPerCluster, nClusterDiff, nClusters; 01339 FF_ERROR Error; 01340 01341 if(!pFile) { 01342 return FF_ERR_NULL_POINTER; 01343 } 01344 01345 if(!(pFile->Mode & FF_MODE_WRITE)) { 01346 return FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE; 01347 } 01348 01349 // Make sure a write is after the append point. 01350 if((pFile->Mode & FF_MODE_APPEND)) { 01351 if(pFile->FilePointer < pFile->Filesize) { 01352 FF_Seek(pFile, 0, FF_SEEK_END); 01353 } 01354 } 01355 01356 pIoman = pFile->pIoman; 01357 01358 nBytesPerCluster = (pIoman->pPartition->SectorsPerCluster * pIoman->BlkSize); 01359 01360 // Extend File for atleast nBytes! 01361 // Handle file-space allocation 01362 Error = FF_ExtendFile(pFile, pFile->FilePointer + nBytes); 01363 01364 if(Error) { 01365 return Error; 01366 } 01367 01368 nRelBlockPos = FF_getMinorBlockEntry(pIoman, pFile->FilePointer, 1); // Get the position within a block. 01369 01370 nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; 01371 if(nClusterDiff) { 01372 if(pFile->CurrentCluster != FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { 01373 pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff, &Error); 01374 if(Error) { 01375 return Error; 01376 } 01377 pFile->CurrentCluster += nClusterDiff; 01378 } 01379 } 01380 01381 nItemLBA = FF_Cluster2LBA(pIoman, pFile->AddrCurrentCluster); 01382 nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1); 01383 01384 if((nRelBlockPos + nBytes) < pIoman->BlkSize) { // Bytes to read are within a block and less than a block size. 01385 pBuffer = FF_GetBuffer(pIoman, nItemLBA, FF_MODE_WRITE); 01386 { 01387 if(!pBuffer) { 01388 return FF_ERR_DEVICE_DRIVER_FAILED; 01389 } 01390 memcpy((pBuffer->pBuffer + nRelBlockPos), buffer, nBytes); 01391 } 01392 FF_ReleaseBuffer(pIoman, pBuffer); 01393 01394 pFile->FilePointer += nBytes; 01395 nBytesWritten = nBytes; 01396 //return nBytes; // Return the number of bytes read. 01397 01398 } else { 01399 01400 //---------- Write (memcpy) to a Sector Boundary 01401 if(nRelBlockPos != 0) { // Not on a sector boundary, at this point the LBA is known. 01402 nBytesToWrite = pIoman->BlkSize - nRelBlockPos; 01403 pBuffer = FF_GetBuffer(pIoman, nItemLBA, FF_MODE_WRITE); 01404 { 01405 if(!pBuffer) { 01406 return FF_ERR_DEVICE_DRIVER_FAILED; 01407 } 01408 // Here we copy to the sector boudary. 01409 memcpy((pBuffer->pBuffer + nRelBlockPos), buffer, nBytesToWrite); 01410 } 01411 FF_ReleaseBuffer(pIoman, pBuffer); 01412 01413 nBytes -= nBytesToWrite; 01414 nBytesWritten += nBytesToWrite; 01415 pFile->FilePointer += nBytesToWrite; 01416 buffer += nBytesToWrite; 01417 } 01418 01419 //---------- Write to a Cluster Boundary 01420 01421 nRelClusterPos = FF_getClusterPosition(pIoman, pFile->FilePointer, 1); 01422 if(nRelClusterPos != 0 && nBytes >= nBytesPerCluster) { // Need to get to cluster boundary 01423 01424 nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; 01425 if(nClusterDiff) { 01426 if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { 01427 pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff, &Error); 01428 if(Error) { 01429 return Error; 01430 } 01431 pFile->CurrentCluster += nClusterDiff; 01432 } 01433 } 01434 01435 nItemLBA = FF_Cluster2LBA(pIoman, pFile->AddrCurrentCluster); 01436 nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1); 01437 01438 sSectors = (FF_T_UINT16) (pIoman->pPartition->SectorsPerCluster - (nRelClusterPos / pIoman->BlkSize)); 01439 01440 slRetVal = FF_BlockWrite(pFile->pIoman, nItemLBA, sSectors, buffer); 01441 if(slRetVal < 0) { 01442 return slRetVal; 01443 } 01444 01445 nBytesToWrite = sSectors * pIoman->BlkSize; 01446 nBytes -= nBytesToWrite; 01447 buffer += nBytesToWrite; 01448 nBytesWritten += nBytesToWrite; 01449 pFile->FilePointer += nBytesToWrite; 01450 01451 } 01452 01453 //---------- Write Clusters 01454 if(nBytes >= nBytesPerCluster) { 01455 //----- Thanks to Christopher Clark of DigiPen Institute of Technology in Redmond, US adding this traversal check. 01456 nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; 01457 if(nClusterDiff) { 01458 if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { 01459 pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff, &Error); 01460 if(Error) { 01461 return Error; 01462 } 01463 pFile->CurrentCluster += nClusterDiff; 01464 } 01465 } 01466 //----- End of Contributor fix. 01467 01468 nClusters = (nBytes / nBytesPerCluster); 01469 01470 slRetVal = FF_WriteClusters(pFile, nClusters, buffer); 01471 if(slRetVal < 0) { 01472 return slRetVal; 01473 } 01474 01475 nBytesToWrite = (nBytesPerCluster * nClusters); 01476 01477 pFile->FilePointer += nBytesToWrite; 01478 01479 nBytes -= nBytesToWrite; 01480 buffer += nBytesToWrite; 01481 nBytesWritten += nBytesToWrite; 01482 } 01483 01484 //---------- Write Remaining Blocks 01485 if(nBytes >= pIoman->BlkSize) { 01486 sSectors = (FF_T_UINT16) (nBytes / pIoman->BlkSize); 01487 01488 nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; 01489 if(nClusterDiff) { 01490 if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { 01491 pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff, &Error); 01492 if(Error) { 01493 return Error; 01494 } 01495 pFile->CurrentCluster += nClusterDiff; 01496 } 01497 } 01498 01499 nItemLBA = FF_Cluster2LBA(pIoman, pFile->AddrCurrentCluster); 01500 nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1); 01501 01502 slRetVal = FF_BlockWrite(pFile->pIoman, nItemLBA, sSectors, buffer); 01503 if(slRetVal < 0) { 01504 return slRetVal; 01505 } 01506 01507 nBytesToWrite = sSectors * pIoman->BlkSize; 01508 pFile->FilePointer += nBytesToWrite; 01509 nBytes -= nBytesToWrite; 01510 buffer += nBytesToWrite; 01511 nBytesWritten += nBytesToWrite; 01512 } 01513 01514 //---------- Write (memcpy) Remaining Bytes 01515 if(nBytes > 0) { 01516 01517 nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; 01518 if(nClusterDiff) { 01519 if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { 01520 pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff, &Error); 01521 if(Error) { 01522 return Error; 01523 } 01524 pFile->CurrentCluster += nClusterDiff; 01525 } 01526 } 01527 01528 nItemLBA = FF_Cluster2LBA(pIoman, pFile->AddrCurrentCluster); 01529 nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1); 01530 pBuffer = FF_GetBuffer(pIoman, nItemLBA, FF_MODE_WRITE); 01531 { 01532 if(!pBuffer) { 01533 return FF_ERR_DEVICE_DRIVER_FAILED; 01534 } 01535 memcpy(pBuffer->pBuffer, buffer, nBytes); 01536 } 01537 FF_ReleaseBuffer(pIoman, pBuffer); 01538 01539 nBytesToWrite = nBytes; 01540 pFile->FilePointer += nBytesToWrite; 01541 nBytes -= nBytesToWrite; 01542 buffer += nBytesToWrite; 01543 nBytesWritten += nBytesToWrite; 01544 01545 } 01546 } 01547 01548 if(pFile->FilePointer > pFile->Filesize) { 01549 pFile->Filesize = pFile->FilePointer; 01550 } 01551 01552 return nBytesWritten; 01553 } 01554 01555 01566 FF_T_SINT32 FF_PutC(FF_FILE *pFile, FF_T_UINT8 pa_cValue) { 01567 FF_BUFFER *pBuffer; 01568 FF_T_UINT32 iItemLBA; 01569 FF_T_UINT32 iRelPos; 01570 FF_T_UINT32 nClusterDiff; 01571 FF_ERROR Error; 01572 01573 if(!pFile) { // Ensure we don't have a Null file pointer on a Public interface. 01574 return FF_ERR_NULL_POINTER; 01575 } 01576 01577 if(!(pFile->Mode & FF_MODE_WRITE)) { 01578 return FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE; 01579 } 01580 01581 // Make sure a write is after the append point. 01582 if((pFile->Mode & FF_MODE_APPEND)) { 01583 if(pFile->FilePointer < pFile->Filesize) { 01584 FF_Seek(pFile, 0, FF_SEEK_END); 01585 } 01586 } 01587 01588 iRelPos = FF_getMinorBlockEntry(pFile->pIoman, pFile->FilePointer, 1); 01589 01590 // Handle File Space Allocation. 01591 Error = FF_ExtendFile(pFile, pFile->FilePointer + 1); 01592 if(Error) { 01593 return Error; 01594 } 01595 01596 nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; 01597 if(nClusterDiff) { 01598 if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { 01599 pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->AddrCurrentCluster, nClusterDiff, &Error); 01600 if(Error) { 01601 return Error; 01602 } 01603 pFile->CurrentCluster += nClusterDiff; 01604 } 01605 } 01606 01607 iItemLBA = FF_Cluster2LBA(pFile->pIoman, pFile->AddrCurrentCluster) + FF_getMajorBlockNumber(pFile->pIoman, pFile->FilePointer, (FF_T_UINT16) 1); 01608 iItemLBA = FF_getRealLBA (pFile->pIoman, iItemLBA) + FF_getMinorBlockNumber(pFile->pIoman, pFile->FilePointer, (FF_T_UINT16) 1); 01609 01610 pBuffer = FF_GetBuffer(pFile->pIoman, iItemLBA, FF_MODE_WRITE); 01611 { 01612 if(!pBuffer) { 01613 return FF_ERR_DEVICE_DRIVER_FAILED; 01614 } 01615 FF_putChar(pBuffer->pBuffer, (FF_T_UINT16) iRelPos, pa_cValue); 01616 } 01617 FF_ReleaseBuffer(pFile->pIoman, pBuffer); 01618 01619 pFile->FilePointer += 1; 01620 if(pFile->Filesize < (pFile->FilePointer)) { 01621 pFile->Filesize += 1; 01622 } 01623 return pa_cValue; 01624 } 01625 01626 01627 01642 FF_ERROR FF_Seek(FF_FILE *pFile, FF_T_SINT32 Offset, FF_T_INT8 Origin) { 01643 01644 FF_ERROR Error; 01645 01646 if(!pFile) { 01647 return FF_ERR_NULL_POINTER; 01648 } 01649 01650 Error = FF_FlushCache(pFile->pIoman); 01651 if(Error) { 01652 return Error; 01653 } 01654 01655 switch(Origin) { 01656 case FF_SEEK_SET: 01657 if((FF_T_UINT32) Offset <= pFile->Filesize && Offset >= 0) { 01658 pFile->FilePointer = Offset; 01659 pFile->CurrentCluster = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1); 01660 pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->ObjectCluster, pFile->CurrentCluster, &Error); 01661 if(Error) { 01662 return Error; 01663 } 01664 } else { 01665 return -2; 01666 } 01667 break; 01668 01669 case FF_SEEK_CUR: 01670 if((Offset + pFile->FilePointer) <= pFile->Filesize && (Offset + (FF_T_SINT32) pFile->FilePointer) >= 0) { 01671 pFile->FilePointer = Offset + pFile->FilePointer; 01672 pFile->CurrentCluster = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1); 01673 pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->ObjectCluster, pFile->CurrentCluster, &Error); 01674 if(Error) { 01675 return Error; 01676 } 01677 } else { 01678 return -2; 01679 } 01680 break; 01681 01682 case FF_SEEK_END: 01683 if((Offset + (FF_T_SINT32) pFile->Filesize) >= 0 && (Offset + pFile->Filesize) <= pFile->Filesize) { 01684 pFile->FilePointer = Offset + pFile->Filesize; 01685 pFile->CurrentCluster = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1); 01686 pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->ObjectCluster, pFile->CurrentCluster, &Error); 01687 if(Error) { 01688 return Error; 01689 } 01690 } else { 01691 return -2; 01692 } 01693 break; 01694 01695 default: 01696 return -3; 01697 01698 } 01699 01700 return 0; 01701 } 01702 01703 01714 FF_ERROR FF_Close(FF_FILE *pFile) { 01715 01716 FF_FILE *pFileChain; 01717 FF_DIRENT OriginalEntry; 01718 FF_ERROR Error; 01719 01720 if(!pFile) { 01721 return FF_ERR_NULL_POINTER; 01722 } 01723 // UpDate Dirent if File-size has changed? 01724 01725 // Update the Dirent! 01726 Error = FF_GetEntry(pFile->pIoman, pFile->DirEntry, pFile->DirCluster, &OriginalEntry); 01727 if(Error) { 01728 return Error; 01729 } 01730 01731 if(!pFile->FileDeleted) { 01732 if(pFile->Filesize != OriginalEntry.Filesize) { 01733 OriginalEntry.Filesize = pFile->Filesize; 01734 Error = FF_PutEntry(pFile->pIoman, pFile->DirEntry, pFile->DirCluster, &OriginalEntry); 01735 if(Error) { 01736 return Error; 01737 } 01738 } 01739 } 01740 01741 Error = FF_FlushCache(pFile->pIoman); // Ensure all modfied blocks are flushed to disk! 01742 01743 // Handle Linked list! 01744 FF_PendSemaphore(pFile->pIoman->pSemaphore); 01745 { // Semaphore is required, or linked list could become corrupted. 01746 if(pFile->pIoman->FirstFile == pFile) { 01747 pFile->pIoman->FirstFile = pFile->Next; 01748 } else { 01749 pFileChain = (FF_FILE *) pFile->pIoman->FirstFile; 01750 while(pFileChain->Next != pFile) { 01751 pFileChain = pFileChain->Next; 01752 } 01753 pFileChain->Next = pFile->Next; 01754 } 01755 } // Semaphore released, linked list was shortened! 01756 FF_ReleaseSemaphore(pFile->pIoman->pSemaphore); 01757 01758 // If file written, flush to disk 01759 FF_FREE(pFile); 01760 01761 if(Error) { 01762 return Error; 01763 } 01764 01765 // Simply free the pointer! 01766 return FF_ERR_NONE; 01767 } Generated on Sat May 26 2012 04:33:00 for ReactOS by
1.7.6.1
|