ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

ff_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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.