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_ioman.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 
00045 #include <string.h>
00046 
00047 #include "ff_ioman.h"   // Includes ff_types.h, ff_safety.h, <stdio.h>
00048 #include "ff_fatdef.h"
00049 #include "ff_crc.h"
00050 
00051 //extern FF_T_UINT32 FF_FindFreeCluster     (FF_IOMAN *pIoman);
00052 extern FF_T_UINT32 FF_CountFreeClusters     (FF_IOMAN *pIoman, FF_ERROR *pError);
00053 
00054 static void FF_IOMAN_InitBufferDescriptors(FF_IOMAN *pIoman);
00055 
00069 FF_IOMAN *FF_CreateIOMAN(FF_T_UINT8 *pCacheMem, FF_T_UINT32 Size, FF_T_UINT16 BlkSize, FF_ERROR *pError) {
00070 
00071     FF_IOMAN    *pIoman = NULL;
00072     FF_T_UINT32 *pLong  = NULL; // Force malloc to malloc memory on a 32-bit boundary.
00073 #ifdef FF_PATH_CACHE
00074     FF_T_UINT32 i;
00075 #endif
00076 
00077     if(pError) {
00078         *pError = FF_ERR_NONE;
00079     }
00080 
00081     if((BlkSize % 512) != 0 || BlkSize == 0) {
00082         if(pError) {
00083             *pError = FF_ERR_IOMAN_BAD_BLKSIZE | FF_CREATEIOMAN;
00084         }
00085         return NULL;    // BlkSize Size not a multiple of 512 > 0
00086     }
00087 
00088     if((Size % BlkSize) != 0 || Size == 0 || Size == BlkSize) {  // Size must now be atleast 2 * BlkSize (or a deadlock will occur).
00089         if(pError) {
00090             *pError = FF_ERR_IOMAN_BAD_MEMSIZE | FF_CREATEIOMAN;
00091         }
00092         return NULL;    // Memory Size not a multiple of BlkSize > 0
00093     }
00094 
00095     pIoman = (FF_IOMAN *) FF_MALLOC(sizeof(FF_IOMAN));
00096 
00097     if(!pIoman) {       // Ensure malloc() succeeded.
00098         if(pError) {
00099             *pError = FF_ERR_NOT_ENOUGH_MEMORY | FF_CREATEIOMAN;
00100         }
00101         return NULL;
00102     }
00103 
00104     memset (pIoman, '\0', sizeof(FF_IOMAN));
00105 
00106     // This is just a bit-mask, to use a byte to keep track of memory.
00107     // pIoman->MemAllocation = 0x00;    // Unset all allocation identifiers.
00108     pIoman->pPartition  = (FF_PARTITION  *) FF_MALLOC(sizeof(FF_PARTITION));
00109     if(!pIoman->pPartition) {
00110         if(pError) {
00111             *pError = FF_ERR_NOT_ENOUGH_MEMORY | FF_CREATEIOMAN;
00112         }
00113         FF_DestroyIOMAN(pIoman);
00114         return NULL;
00115     }
00116     memset (pIoman->pPartition, '\0', sizeof(FF_PARTITION));
00117 
00118     pIoman->MemAllocation |= FF_IOMAN_ALLOC_PART;   // If succeeded, flag that allocation.
00119     pIoman->pPartition->LastFreeCluster = 0;
00120     pIoman->pPartition->PartitionMounted = FF_FALSE;    // This should be checked by FF_Open();
00121 #ifdef FF_PATH_CACHE
00122     pIoman->pPartition->PCIndex = 0;
00123     for(i = 0; i < FF_PATH_CACHE_DEPTH; i++) {
00124         pIoman->pPartition->PathCache[i].DirCluster = 0;
00125         pIoman->pPartition->PathCache[i].Path[0] = '\0';
00126 /*#ifdef FF_HASH_TABLE_SUPPORT
00127         pIoman->pPartition->PathCache[i].pHashTable = FF_CreateHashTable();
00128         pIoman->pPartition->PathCache[i].bHashed = FF_FALSE;
00129 #endif*/
00130     }
00131 #endif
00132 
00133 #ifdef FF_HASH_CACHE
00134     for(i = 0; i < FF_HASH_CACHE_DEPTH; i++) {
00135         pIoman->HashCache[i].pHashTable     = FF_CreateHashTable();
00136         pIoman->HashCache[i].ulDirCluster   = 0;
00137         pIoman->HashCache[i].ulMisses       = 100;
00138     }
00139 #endif
00140 
00141     pIoman->pBlkDevice  = (FF_BLK_DEVICE *) FF_MALLOC(sizeof(FF_BLK_DEVICE));
00142     if(!pIoman->pBlkDevice) {   // If succeeded, flag that allocation.
00143         if(pError) {
00144             *pError = FF_ERR_NOT_ENOUGH_MEMORY | FF_CREATEIOMAN;
00145         }
00146         FF_DestroyIOMAN(pIoman);
00147         return NULL;
00148     }
00149     memset (pIoman->pBlkDevice, '\0', sizeof(FF_BLK_DEVICE));
00150     pIoman->MemAllocation |= FF_IOMAN_ALLOC_BLKDEV;
00151 
00152     // Make sure all pointers are NULL
00153     pIoman->pBlkDevice->fnpReadBlocks = NULL;
00154     pIoman->pBlkDevice->fnpWriteBlocks = NULL;
00155     pIoman->pBlkDevice->pParam = NULL;
00156 
00157     // Organise the memory provided, or create our own!
00158     if(pCacheMem) {
00159         pIoman->pCacheMem = pCacheMem;
00160     }else { // No-Cache buffer provided (malloc)
00161         pLong = (FF_T_UINT32 *) FF_MALLOC(Size);
00162         pIoman->pCacheMem = (FF_T_UINT8 *) pLong;
00163         if(!pIoman->pCacheMem) {
00164             if(pError) {
00165                 *pError = FF_ERR_NOT_ENOUGH_MEMORY | FF_CREATEIOMAN;
00166             }
00167             FF_DestroyIOMAN(pIoman);
00168             return NULL;
00169         }
00170         pIoman->MemAllocation |= FF_IOMAN_ALLOC_BUFFERS;
00171 
00172     }
00173     memset (pIoman->pCacheMem, '\0', Size);
00174 
00175     pIoman->BlkSize      = BlkSize;
00176     pIoman->CacheSize    = (FF_T_UINT16) (Size / BlkSize);
00177     pIoman->FirstFile    = NULL;
00178     pIoman->Locks        = 0;
00179 
00180     /*  Malloc() memory for buffer objects. (FullFAT never refers to a buffer directly
00181         but uses buffer objects instead. Allows us to provide thread safety.
00182     */
00183     pIoman->pBuffers = (FF_BUFFER *) FF_MALLOC(sizeof(FF_BUFFER) * pIoman->CacheSize);
00184 
00185     if(!pIoman->pBuffers) {
00186         if(pError) {
00187             *pError = FF_ERR_NOT_ENOUGH_MEMORY | FF_CREATEIOMAN;
00188         }
00189         FF_DestroyIOMAN(pIoman);
00190         return NULL;    // HT added
00191     }
00192     memset (pIoman->pBuffers, '\0', sizeof(FF_BUFFER) * pIoman->CacheSize);
00193 
00194     pIoman->MemAllocation |= FF_IOMAN_ALLOC_BUFDESCR;
00195     FF_IOMAN_InitBufferDescriptors(pIoman);
00196 
00197     // Finally create a Semaphore for Buffer Description modifications.
00198     pIoman->pSemaphore = FF_CreateSemaphore();
00199 
00200 #ifdef FF_BLKDEV_USES_SEM
00201     pIoman->pBlkDevSemaphore = FF_CreateSemaphore();
00202 #endif
00203 
00204     return pIoman;  // Sucess, return the created object.
00205 }
00206 
00216 FF_ERROR FF_DestroyIOMAN(FF_IOMAN *pIoman) {
00217 
00218 #ifdef FF_HASH_CACHE
00219     FF_T_UINT32 i;
00220 #endif
00221 
00222     // Ensure no NULL pointer was provided.
00223     if(!pIoman) {
00224         return FF_ERR_NULL_POINTER | FF_DESTROYIOMAN;
00225     }
00226 
00227     // Ensure pPartition pointer was allocated.
00228     if((pIoman->MemAllocation & FF_IOMAN_ALLOC_PART)) {
00229         FF_FREE(pIoman->pPartition);
00230     }
00231 
00232     // Ensure pBlkDevice pointer was allocated.
00233     if((pIoman->MemAllocation & FF_IOMAN_ALLOC_BLKDEV)) {
00234         FF_FREE(pIoman->pBlkDevice);
00235     }
00236 
00237     // Ensure pBuffers pointer was allocated.
00238     if((pIoman->MemAllocation & FF_IOMAN_ALLOC_BUFDESCR)) {
00239         FF_FREE(pIoman->pBuffers);
00240     }
00241 
00242     // Ensure pCacheMem pointer was allocated.
00243     if((pIoman->MemAllocation & FF_IOMAN_ALLOC_BUFFERS)) {
00244         FF_FREE(pIoman->pCacheMem);
00245     }
00246 
00247     // Destroy any Semaphore that was created.
00248     if(pIoman->pSemaphore) {
00249         FF_DestroySemaphore(pIoman->pSemaphore);
00250     }
00251 #ifdef FF_BLKDEV_USES_SEM
00252     if(pIoman->pBlkDevSemaphore) {
00253         FF_DestroySemaphore(pIoman->pBlkDevSemaphore);
00254     }
00255 #endif
00256 
00257     // Destroy HashCache
00258 #ifdef FF_HASH_CACHE
00259     for(i = 0; i < FF_HASH_CACHE_DEPTH; i++) {
00260         FF_DestroyHashTable(pIoman->HashCache[i].pHashTable);
00261     }
00262 #endif
00263 
00264     // Finally free the FF_IOMAN object.
00265     FF_FREE(pIoman);
00266 
00267     return FF_ERR_NONE;
00268 }
00269 
00277 static void FF_IOMAN_InitBufferDescriptors(FF_IOMAN *pIoman) {
00278     FF_T_UINT16 i;
00279     FF_BUFFER *pBuffer = pIoman->pBuffers;
00280     pIoman->LastReplaced = 0;
00281     // HT : it is assmued that pBuffer was cleared by memset ()
00282     for(i = 0; i < pIoman->CacheSize; i++) {
00283         pBuffer->pBuffer        = (FF_T_UINT8 *)((pIoman->pCacheMem) + (pIoman->BlkSize * i));
00284         pBuffer++;
00285     }
00286 }
00287 
00288 
00297 FF_ERROR FF_FlushCache(FF_IOMAN *pIoman) {
00298 
00299     FF_T_UINT16 i,x;
00300 
00301     if(!pIoman) {
00302         return FF_ERR_NULL_POINTER | FF_FLUSHCACHE;
00303     }
00304 
00305     FF_PendSemaphore(pIoman->pSemaphore);
00306     {
00307         for(i = 0; i < pIoman->CacheSize; i++) {
00308             if((pIoman->pBuffers + i)->NumHandles == 0 && (pIoman->pBuffers + i)->Modified == FF_TRUE) {
00309 
00310                 FF_BlockWrite(pIoman, (pIoman->pBuffers + i)->Sector, 1, (pIoman->pBuffers + i)->pBuffer);
00311 
00312                 // Buffer has now been flushed, mark it as a read buffer and unmodified.
00313                 (pIoman->pBuffers + i)->Mode = FF_MODE_READ;
00314                 (pIoman->pBuffers + i)->Modified = FF_FALSE;
00315 
00316                 // Search for other buffers that used this sector, and mark them as modified
00317                 // So that further requests will result in the new sector being fetched.
00318                 for(x = 0; x < pIoman->CacheSize; x++) {
00319                     if(x != i) {
00320                         if((pIoman->pBuffers + x)->Sector == (pIoman->pBuffers + i)->Sector && (pIoman->pBuffers + x)->Mode == FF_MODE_READ) {
00321                             (pIoman->pBuffers + x)->Modified = FF_TRUE;
00322                         }
00323                     }
00324                 }
00325             }
00326         }
00327     }
00328     FF_ReleaseSemaphore(pIoman->pSemaphore);
00329 
00330     return FF_ERR_NONE;
00331 }
00332 
00333 FF_BUFFER *FF_GetBuffer(FF_IOMAN *pIoman, FF_T_UINT32 Sector, FF_T_UINT8 Mode) {
00334     FF_BUFFER   *pBuffer;
00335     FF_BUFFER   *pBufLRU    = NULL;
00336     FF_BUFFER   *pBufLHITS  = NULL;
00337     FF_BUFFER   *pBufMatch  = NULL;
00338 
00339     FF_T_UINT32 i;
00340 
00341     while(!pBufMatch) {
00342         FF_PendSemaphore(pIoman->pSemaphore);
00343         {
00344             pBuffer = pIoman->pBuffers;
00345             // HT if a perfect match has priority, find that first
00346             for(i = 0; i < pIoman->CacheSize; i++, pBuffer++) {
00347                 pBuffer = (pIoman->pBuffers + i);
00348                 if(pBuffer->Sector == Sector && pBuffer->Valid == FF_TRUE) {
00349                     pBufMatch = pBuffer;
00350                     break;  // Why look further if you found a perfect match?
00351                 }
00352             }
00353 
00354             if(pBufMatch) {
00355                 // A Match was found process!
00356                 if(Mode == FF_MODE_READ && pBufMatch->Mode == FF_MODE_READ) {
00357                     pBufMatch->NumHandles += 1;
00358                     pBufMatch->Persistance += 1;
00359                     FF_ReleaseSemaphore(pIoman->pSemaphore);
00360                     return pBufMatch;
00361                 }
00362 
00363                 if(pBufMatch->Mode == FF_MODE_WRITE && pBufMatch->NumHandles == 0) {    // This buffer has no attached handles.
00364                     pBufMatch->Mode = Mode;
00365                     pBufMatch->NumHandles = 1;
00366                     pBufMatch->Persistance += 1;
00367                     FF_ReleaseSemaphore(pIoman->pSemaphore);
00368                     return pBufMatch;
00369                 }
00370 
00371                 if(pBufMatch->Mode == FF_MODE_READ && Mode == FF_MODE_WRITE && pBufMatch->NumHandles == 0) {
00372                     pBufMatch->Mode = Mode;
00373                     pBufMatch->Modified = FF_TRUE;
00374                     pBufMatch->NumHandles = 1;
00375                     pBufMatch->Persistance += 1;
00376                     FF_ReleaseSemaphore(pIoman->pSemaphore);
00377                     return pBufMatch;
00378                 }
00379 
00380                 pBufMatch = NULL;   // Sector is already in use, keep yielding until its available!
00381 
00382             } else {
00383                 pBuffer = pIoman->pBuffers;
00384                 for(i = 0; i < pIoman->CacheSize; i++, pBuffer++) {
00385                     if(pBuffer->NumHandles == 0) {
00386                         pBuffer->LRU += 1;
00387 
00388                         if(!pBufLRU) {
00389                             pBufLRU = pBuffer;
00390                         }
00391                         if(!pBufLHITS) {
00392                             pBufLHITS = pBuffer;
00393                         }
00394 
00395                         if(pBuffer->LRU >= pBufLRU->LRU) {
00396                             if(pBuffer->LRU == pBufLRU->LRU) {
00397                                 if(pBuffer->Persistance > pBufLRU->Persistance) {
00398                                     pBufLRU = pBuffer;
00399                                 }
00400                             } else {
00401                                 pBufLRU = pBuffer;
00402                             }
00403                         }
00404 
00405                         if(pBuffer->Persistance < pBufLHITS->Persistance) {
00406                             pBufLHITS = pBuffer;
00407                         }
00408                     }
00409                 }
00410 
00411                 if(pBufLRU) {
00412                     // Process the suitable candidate.
00413                     if(pBufLRU->Modified == FF_TRUE) {
00414                         FF_BlockWrite(pIoman, pBufLRU->Sector, 1, pBufLRU->pBuffer);
00415                     }
00416                     pBufLRU->Mode = Mode;
00417                     pBufLRU->Persistance = 1;
00418                     pBufLRU->LRU = 0;
00419                     pBufLRU->NumHandles = 1;
00420                     pBufLRU->Sector = Sector;
00421 
00422                     if(Mode == FF_MODE_WRITE) {
00423                         pBufLRU->Modified = FF_TRUE;
00424                     } else {
00425                         pBufLRU->Modified = FF_FALSE;
00426                     }
00427 
00428                     FF_BlockRead(pIoman, Sector, 1, pBufLRU->pBuffer);
00429                     pBufLRU->Valid = FF_TRUE;
00430                     FF_ReleaseSemaphore(pIoman->pSemaphore);
00431                     return pBufLRU;
00432                 }
00433 
00434             }
00435         }
00436         FF_ReleaseSemaphore(pIoman->pSemaphore);
00437         FF_Yield(); // Better to go asleep to give low-priority task a chance to release buffer(s)
00438     }
00439 
00440     return pBufMatch;   // Return the Matched Buffer!
00441 }
00442 
00443 
00452 void FF_ReleaseBuffer(FF_IOMAN *pIoman, FF_BUFFER *pBuffer) {
00453     // Protect description changes with a semaphore.
00454     FF_PendSemaphore(pIoman->pSemaphore);
00455     {
00456         if (pBuffer->NumHandles) {
00457             pBuffer->NumHandles--;
00458         } else {
00459             //printf ("FF_ReleaseBuffer: buffer not claimed\n");
00460         }
00461     }
00462     FF_ReleaseSemaphore(pIoman->pSemaphore);
00463 }
00464 
00480 FF_ERROR FF_RegisterBlkDevice(FF_IOMAN *pIoman, FF_T_UINT16 BlkSize, FF_WRITE_BLOCKS fnWriteBlocks, FF_READ_BLOCKS fnReadBlocks, void *pParam) {
00481     if(!pIoman) {   // We can't do anything without an IOMAN object.
00482         return FF_ERR_NULL_POINTER | FF_REGISTERBLKDEVICE;
00483     }
00484 
00485     if((BlkSize % 512) != 0 || BlkSize == 0) {
00486         return FF_ERR_IOMAN_DEV_INVALID_BLKSIZE | FF_REGISTERBLKDEVICE; // BlkSize Size not a multiple of IOMAN's Expected BlockSize > 0
00487     }
00488 
00489     if((BlkSize % pIoman->BlkSize) != 0 || BlkSize == 0) {
00490         return FF_ERR_IOMAN_DEV_INVALID_BLKSIZE | FF_REGISTERBLKDEVICE; // BlkSize Size not a multiple of IOMAN's Expected BlockSize > 0
00491     }
00492 
00493     // Ensure that a device cannot be re-registered "mid-flight"
00494     // Doing so would corrupt the context of FullFAT
00495     if(pIoman->pBlkDevice->fnpReadBlocks) {
00496         return FF_ERR_IOMAN_DEV_ALREADY_REGD | FF_REGISTERBLKDEVICE;
00497     }
00498     if(pIoman->pBlkDevice->fnpWriteBlocks) {
00499         return FF_ERR_IOMAN_DEV_ALREADY_REGD | FF_REGISTERBLKDEVICE;
00500     }
00501     if(pIoman->pBlkDevice->pParam) {
00502         return FF_ERR_IOMAN_DEV_ALREADY_REGD | FF_REGISTERBLKDEVICE;
00503     }
00504 
00505     // Here we shall just set the values.
00506     // FullFAT checks before using any of these values.
00507     pIoman->pBlkDevice->devBlkSize      = BlkSize;
00508     pIoman->pBlkDevice->fnpReadBlocks   = fnReadBlocks;
00509     pIoman->pBlkDevice->fnpWriteBlocks  = fnWriteBlocks;
00510     pIoman->pBlkDevice->pParam          = pParam;
00511 
00512     return FF_ERR_NONE; // Success
00513 }
00514 
00515 /*
00516     New Interface for FullFAT to read blocks.
00517 */
00518 
00519 FF_T_SINT32 FF_BlockRead(FF_IOMAN *pIoman, FF_T_UINT32 ulSectorLBA, FF_T_UINT32 ulNumSectors, void *pBuffer) {
00520     FF_T_SINT32 slRetVal = 0;
00521 
00522     if(pIoman->pPartition->TotalSectors) {
00523         if((ulSectorLBA + ulNumSectors) > (pIoman->pPartition->TotalSectors + pIoman->pPartition->BeginLBA)) {
00524             return -(FF_ERR_IOMAN_OUT_OF_BOUNDS_READ | FF_BLOCKREAD);       
00525         }
00526     }
00527     
00528     if(pIoman->pBlkDevice->fnpReadBlocks) { // Make sure we don't execute a NULL.
00529 #ifdef  FF_BLKDEV_USES_SEM
00530         FF_PendSemaphore(pIoman->pBlkDevSemaphore);
00531 #endif
00532         slRetVal = pIoman->pBlkDevice->fnpReadBlocks(pBuffer, ulSectorLBA, ulNumSectors, pIoman->pBlkDevice->pParam);
00533 #ifdef  FF_BLKDEV_USES_SEM
00534         FF_ReleaseSemaphore(pIoman->pBlkDevSemaphore);
00535 #endif
00536         if(FF_GETERROR(slRetVal) == FF_ERR_DRIVER_BUSY) {
00537             FF_Sleep(FF_DRIVER_BUSY_SLEEP);
00538         }
00539     } while(FF_GETERROR(slRetVal) == FF_ERR_DRIVER_BUSY);
00540 
00541     return slRetVal;
00542 }
00543 
00544 FF_T_SINT32 FF_BlockWrite(FF_IOMAN *pIoman, FF_T_UINT32 ulSectorLBA, FF_T_UINT32 ulNumSectors, void *pBuffer) {
00545     FF_T_SINT32 slRetVal = 0;
00546 
00547     if(pIoman->pPartition->TotalSectors) {
00548         if((ulSectorLBA + ulNumSectors) > (pIoman->pPartition->TotalSectors + pIoman->pPartition->BeginLBA)) {
00549             return -(FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_BLOCKWRITE);     
00550         }
00551     }
00552     
00553     if(pIoman->pBlkDevice->fnpWriteBlocks) {    // Make sure we don't execute a NULL.
00554 #ifdef  FF_BLKDEV_USES_SEM
00555         FF_PendSemaphore(pIoman->pBlkDevSemaphore);
00556 #endif
00557         slRetVal = pIoman->pBlkDevice->fnpWriteBlocks(pBuffer, ulSectorLBA, ulNumSectors, pIoman->pBlkDevice->pParam);
00558 #ifdef  FF_BLKDEV_USES_SEM
00559         FF_ReleaseSemaphore(pIoman->pBlkDevSemaphore);
00560 #endif
00561         if(FF_GETERROR(slRetVal) == FF_ERR_DRIVER_BUSY) {
00562             FF_Sleep(FF_DRIVER_BUSY_SLEEP);
00563         }
00564     } while(FF_GETERROR(slRetVal) == FF_ERR_DRIVER_BUSY);
00565 
00566     return slRetVal;
00567 }
00568 
00569 
00573 static FF_ERROR FF_DetermineFatType(FF_IOMAN *pIoman) {
00574 
00575     FF_PARTITION    *pPart;
00576     FF_BUFFER       *pBuffer;
00577     FF_T_UINT32     testLong;
00578     if(pIoman) {
00579         pPart = pIoman->pPartition;
00580 
00581         if(pPart->NumClusters < 4085) {
00582             // FAT12
00583             pPart->Type = FF_T_FAT12;
00584 #ifdef FF_FAT_CHECK
00585 #ifdef FF_FAT12_SUPPORT
00586             pBuffer = FF_GetBuffer(pIoman, pIoman->pPartition->FatBeginLBA, FF_MODE_READ);
00587             {
00588                 if(!pBuffer) {
00589                     return FF_ERR_DEVICE_DRIVER_FAILED;
00590                 }
00591                 testLong = (FF_T_UINT32) FF_getShort(pBuffer->pBuffer, 0x0000);
00592             }
00593             FF_ReleaseBuffer(pIoman, pBuffer);
00594             if((testLong & 0x3FF) != 0x3F8) {
00595                 return FF_ERR_IOMAN_NOT_FAT_FORMATTED;
00596             }
00597 #else
00598             return FF_ERR_IOMAN_NOT_FAT_FORMATTED;
00599 #endif
00600 #endif
00601 #ifdef FF_FAT12_SUPPORT
00602             return FF_ERR_NONE;
00603 #endif
00604 
00605         } else if(pPart->NumClusters < 65525) {
00606             // FAT 16
00607             pPart->Type = FF_T_FAT16;
00608 #ifdef FF_FAT_CHECK
00609             pBuffer = FF_GetBuffer(pIoman, pIoman->pPartition->FatBeginLBA, FF_MODE_READ);
00610             {
00611                 if(!pBuffer) {
00612                     return FF_ERR_DEVICE_DRIVER_FAILED;
00613                 }
00614                 testLong = (FF_T_UINT32) FF_getShort(pBuffer->pBuffer, 0x0000);
00615             }
00616             FF_ReleaseBuffer(pIoman, pBuffer);
00617             if(testLong != 0xFFF8) {
00618                 return FF_ERR_IOMAN_NOT_FAT_FORMATTED;
00619             }
00620 #endif
00621             return FF_ERR_NONE;
00622         }
00623         else {
00624             // FAT 32!
00625             pPart->Type = FF_T_FAT32;
00626 #ifdef FF_FAT_CHECK
00627             pBuffer = FF_GetBuffer(pIoman, pIoman->pPartition->FatBeginLBA, FF_MODE_READ);
00628             {
00629                 if(!pBuffer) {
00630                     return FF_ERR_DEVICE_DRIVER_FAILED;
00631                 }
00632                 testLong = FF_getLong(pBuffer->pBuffer, 0x0000);
00633             }
00634             FF_ReleaseBuffer(pIoman, pBuffer);
00635             if((testLong & 0x0FFFFFF8) != 0x0FFFFFF8 && (testLong & 0x0FFFFFF8) != 0x0FFFFFF0) {
00636                 return FF_ERR_IOMAN_NOT_FAT_FORMATTED;
00637             }
00638 #endif
00639             return FF_ERR_NONE;
00640         }
00641     }
00642 
00643     return FF_ERR_IOMAN_NOT_FAT_FORMATTED;
00644 }
00645 
00646 static FF_T_SINT8 FF_PartitionCount (FF_T_UINT8 *pBuffer)
00647 {
00648     FF_T_SINT8 count = 0;
00649     FF_T_SINT8 part;
00650     // Check PBR or MBR signature
00651     if (FF_getChar(pBuffer, FF_FAT_MBR_SIGNATURE) != 0x55 &&
00652         FF_getChar(pBuffer, FF_FAT_MBR_SIGNATURE) != 0xAA ) {
00653         // No MBR, but is it a PBR ?
00654         if (FF_getChar(pBuffer, 0) == 0xEB &&          // PBR Byte 0
00655             FF_getChar(pBuffer, 2) == 0x90 &&          // PBR Byte 2
00656             (FF_getChar(pBuffer, 21) & 0xF0) == 0xF0) {// PBR Byte 21 : Media byte
00657             return 1;   // No MBR but PBR exist then only one partition
00658         }
00659         return 0;   // No MBR and no PBR then no partition found
00660     }
00661     for (part = 0; part < 4; part++)  {
00662         FF_T_UINT8 active = FF_getChar(pBuffer, FF_FAT_PTBL + FF_FAT_PTBL_ACTIVE + (16 * part));
00663         FF_T_UINT8 part_id = FF_getChar(pBuffer, FF_FAT_PTBL + FF_FAT_PTBL_ID + (16 * part));
00664         // The first sector must be a MBR, then check the partition entry in the MBR
00665         if (active != 0x80 && (active != 0 || part_id == 0)) {
00666             break;
00667         }
00668         count++;
00669     }
00670     return count;
00671 }
00672 
00673 /*
00674     Mount GPT Partition Tables
00675 */
00676 
00677 #define FF_GPT_HEAD_ENTRY_SIZE          0x54
00678 #define FF_GPT_HEAD_TOTAL_ENTRIES       0x50
00679 #define FF_GPT_HEAD_PART_ENTRY_LBA      0x48
00680 #define FF_GPT_ENTRY_FIRST_SECTOR_LBA   0x20
00681 #define FF_GPT_HEAD_CRC                 0x10
00682 #define FF_GPT_HEAD_LENGTH              0x0C
00683 
00684 static FF_ERROR FF_GetEfiPartitionEntry(FF_IOMAN *pIoman, FF_T_UINT32 ulPartitionNumber) {
00685     // Continuing on from FF_MountPartition() pPartition->BeginLBA should be the sector of the GPT Header
00686     FF_BUFFER       *pBuffer;
00687     FF_PARTITION    *pPart = pIoman->pPartition;
00688 
00689     FF_T_UINT32     ulBeginGPT;
00690     FF_T_UINT32     ulEntrySector;
00691     FF_T_UINT32     ulSectorOffset;
00692     FF_T_UINT32     ulTotalPartitionEntries;
00693     FF_T_UINT32     ulPartitionEntrySize;
00694     FF_T_UINT32     ulGPTHeadCRC, ulGPTCrcCheck, ulGPTHeadLength;
00695 
00696     if(ulPartitionNumber >= 128) {
00697         return FF_ERR_IOMAN_INVALID_PARTITION_NUM;
00698     }
00699 
00700     pBuffer = FF_GetBuffer(pIoman, pPart->BeginLBA, FF_MODE_READ);
00701     {
00702         if(!pBuffer) {
00703             return FF_ERR_DEVICE_DRIVER_FAILED;
00704         }
00705 
00706         // Verify this is an EFI header
00707         if(memcmp(pBuffer->pBuffer, "EFI PART", 8) != 0) {
00708             FF_ReleaseBuffer(pIoman, pBuffer);
00709             return FF_ERR_IOMAN_INVALID_FORMAT;
00710         }
00711 
00712         ulBeginGPT                  = FF_getLong(pBuffer->pBuffer, FF_GPT_HEAD_PART_ENTRY_LBA);
00713         ulTotalPartitionEntries     = FF_getLong(pBuffer->pBuffer, FF_GPT_HEAD_TOTAL_ENTRIES);
00714         ulPartitionEntrySize        = FF_getLong(pBuffer->pBuffer, FF_GPT_HEAD_ENTRY_SIZE);
00715         ulGPTHeadCRC                = FF_getLong(pBuffer->pBuffer, FF_GPT_HEAD_CRC);
00716         ulGPTHeadLength             = FF_getLong(pBuffer->pBuffer, FF_GPT_HEAD_LENGTH);
00717 
00718         // Calculate Head CRC
00719 
00720         // Blank CRC field
00721         FF_putLong(pBuffer->pBuffer, FF_GPT_HEAD_CRC, 0x00000000);
00722 
00723         // Calculate CRC
00724         ulGPTCrcCheck = FF_GetCRC32(pBuffer->pBuffer, ulGPTHeadLength);
00725 
00726         // Restore The CRC field
00727         FF_putLong(pBuffer->pBuffer, FF_GPT_HEAD_CRC, ulGPTHeadCRC);
00728     }
00729     FF_ReleaseBuffer(pIoman, pBuffer);
00730 
00731     // Check CRC
00732     if(ulGPTHeadCRC != ulGPTCrcCheck) {
00733         return FF_ERR_IOMAN_GPT_HEADER_CORRUPT;
00734     }
00735     
00736     // Calculate Sector Containing the Partition Entry we want to use.
00737 
00738     ulEntrySector   = ((ulPartitionNumber * ulPartitionEntrySize) / pIoman->BlkSize) + ulBeginGPT;
00739     ulSectorOffset  = (ulPartitionNumber % (pIoman->BlkSize / ulPartitionEntrySize)) * ulPartitionEntrySize;
00740     
00741     pBuffer = FF_GetBuffer(pIoman, ulEntrySector, FF_MODE_READ);
00742     {
00743         if(!pBuffer) {
00744             return FF_ERR_DEVICE_DRIVER_FAILED;
00745         }
00746 
00747         pPart->BeginLBA = FF_getLong(pBuffer->pBuffer, ulSectorOffset + FF_GPT_ENTRY_FIRST_SECTOR_LBA);
00748     }
00749     FF_ReleaseBuffer(pIoman, pBuffer);
00750 
00751     if(!pPart->BeginLBA) {
00752         return FF_ERR_IOMAN_INVALID_PARTITION_NUM;
00753     }
00754 
00755     return FF_ERR_NONE;
00756 }
00757 
00776 FF_ERROR FF_MountPartition(FF_IOMAN *pIoman, FF_T_UINT8 PartitionNumber) {
00777     FF_PARTITION    *pPart;
00778     FF_BUFFER       *pBuffer = 0;
00779     FF_ERROR        Error;
00780 
00781     FF_T_UINT8      ucPartitionType;
00782 
00783     int partCount;
00784 
00785     if(!pIoman) {
00786         return FF_ERR_NULL_POINTER;
00787     }
00788 
00789     /*if(PartitionNumber > 3) {
00790         return FF_ERR_IOMAN_INVALID_PARTITION_NUM;
00791     }*/
00792 
00793     pPart = pIoman->pPartition;
00794 
00795     memset (pIoman->pBuffers, '\0', sizeof(FF_BUFFER) * pIoman->CacheSize);
00796     memset (pIoman->pCacheMem, '\0', pIoman->BlkSize * pIoman->CacheSize);
00797 
00798     FF_IOMAN_InitBufferDescriptors(pIoman);
00799     pIoman->FirstFile = 0;
00800 
00801     pBuffer = FF_GetBuffer(pIoman, 0, FF_MODE_READ);
00802     if(!pBuffer) {
00803         return FF_ERR_DEVICE_DRIVER_FAILED;
00804     }
00805 
00806     partCount = FF_PartitionCount (pBuffer->pBuffer);
00807 
00808     pPart->BlkSize = FF_getShort(pBuffer->pBuffer, FF_FAT_BYTES_PER_SECTOR);
00809 
00810     if (partCount == 0) { //(pPart->BlkSize % 512) == 0 && pPart->BlkSize > 0) {
00811         // Volume is not partitioned (MBR Found)
00812         pPart->BeginLBA = 0;
00813     } else {
00814         
00815         ucPartitionType = FF_getChar(pBuffer->pBuffer, FF_FAT_PTBL + FF_FAT_PTBL_ID);   // Ensure its not an EFI partition!
00816 
00817         if(ucPartitionType != 0xEE) {
00818 
00819             if(PartitionNumber > 3) {
00820                 FF_ReleaseBuffer(pIoman, pBuffer);
00821                 return FF_ERR_IOMAN_INVALID_PARTITION_NUM;
00822             }
00823 
00824             // Primary Partitions to deal with!
00825             pPart->BeginLBA = FF_getLong(pBuffer->pBuffer, FF_FAT_PTBL + FF_FAT_PTBL_LBA + (16 * PartitionNumber));
00826         }
00827 
00828         FF_ReleaseBuffer(pIoman, pBuffer);
00829 
00830         if(ucPartitionType == 0xEE) {
00831 
00832             pPart->BeginLBA = FF_getLong(pBuffer->pBuffer, FF_FAT_PTBL + FF_FAT_PTBL_LBA);
00833             Error = FF_GetEfiPartitionEntry(pIoman, PartitionNumber);
00834 
00835             if(Error) {
00836                 return Error;
00837             }
00838         }
00839 
00840         if(!pPart->BeginLBA) {
00841             return FF_ERR_IOMAN_NO_MOUNTABLE_PARTITION;
00842         }
00843         // Now we get the Partition sector.
00844         pBuffer = FF_GetBuffer(pIoman, pPart->BeginLBA, FF_MODE_READ);
00845         if(!pBuffer) {
00846             return FF_ERR_DEVICE_DRIVER_FAILED;
00847         }
00848         pPart->BlkSize = FF_getShort(pBuffer->pBuffer, FF_FAT_BYTES_PER_SECTOR);
00849         if((pPart->BlkSize % 512) != 0 || pPart->BlkSize == 0) {
00850             FF_ReleaseBuffer(pIoman, pBuffer);
00851             return FF_ERR_IOMAN_INVALID_FORMAT;
00852         }
00853     }
00854 
00855     // Assume FAT16, then we'll adjust if its FAT32
00856     pPart->ReservedSectors = FF_getShort(pBuffer->pBuffer, FF_FAT_RESERVED_SECTORS);
00857     pPart->FatBeginLBA = pPart->BeginLBA + pPart->ReservedSectors;
00858 
00859     pPart->NumFATS = (FF_T_UINT8) FF_getShort(pBuffer->pBuffer, FF_FAT_NUMBER_OF_FATS);
00860     pPart->SectorsPerFAT = (FF_T_UINT32) FF_getShort(pBuffer->pBuffer, FF_FAT_16_SECTORS_PER_FAT);
00861 
00862     pPart->SectorsPerCluster = FF_getChar(pBuffer->pBuffer, FF_FAT_SECTORS_PER_CLUS);
00863 
00864     pPart->BlkFactor = (FF_T_UINT8) (pPart->BlkSize / pIoman->BlkSize);    // Set the BlockFactor (How many real-blocks in a fake block!).
00865 
00866     if(pPart->SectorsPerFAT == 0) { // FAT32
00867         pPart->SectorsPerFAT    = FF_getLong(pBuffer->pBuffer, FF_FAT_32_SECTORS_PER_FAT);
00868         pPart->RootDirCluster   = FF_getLong(pBuffer->pBuffer, FF_FAT_ROOT_DIR_CLUSTER);
00869         pPart->ClusterBeginLBA  = pPart->BeginLBA + pPart->ReservedSectors + (pPart->NumFATS * pPart->SectorsPerFAT);
00870         pPart->TotalSectors     = (FF_T_UINT32) FF_getShort(pBuffer->pBuffer, FF_FAT_16_TOTAL_SECTORS);
00871         if(pPart->TotalSectors == 0) {
00872             pPart->TotalSectors = FF_getLong(pBuffer->pBuffer, FF_FAT_32_TOTAL_SECTORS);
00873         }
00874         memcpy (pPart->VolLabel, pBuffer->pBuffer + FF_FAT_32_VOL_LABEL, sizeof pPart->VolLabel);
00875     } else {    // FAT16
00876         pPart->ClusterBeginLBA  = pPart->BeginLBA + pPart->ReservedSectors + (pPart->NumFATS * pPart->SectorsPerFAT);
00877         pPart->TotalSectors     = (FF_T_UINT32) FF_getShort(pBuffer->pBuffer, FF_FAT_16_TOTAL_SECTORS);
00878         pPart->RootDirCluster   = 1; // 1st Cluster is RootDir!
00879         if(pPart->TotalSectors == 0) {
00880             pPart->TotalSectors = FF_getLong(pBuffer->pBuffer, FF_FAT_32_TOTAL_SECTORS);
00881         }
00882         memcpy (pPart->VolLabel, pBuffer->pBuffer + FF_FAT_16_VOL_LABEL, sizeof pPart->VolLabel);
00883     }
00884 
00885     FF_ReleaseBuffer(pIoman, pBuffer);  // Release the buffer finally!
00886 
00887     if(!pPart->BlkSize) {
00888         return FF_ERR_IOMAN_INVALID_FORMAT;
00889     }
00890     
00891     pPart->RootDirSectors   = ((FF_getShort(pBuffer->pBuffer, FF_FAT_ROOT_ENTRY_COUNT) * 32) + pPart->BlkSize - 1) / pPart->BlkSize;
00892     pPart->FirstDataSector  = pPart->ClusterBeginLBA + pPart->RootDirSectors;
00893     pPart->DataSectors      = pPart->TotalSectors - (pPart->ReservedSectors + (pPart->NumFATS * pPart->SectorsPerFAT) + pPart->RootDirSectors);
00894     
00895     if(!pPart->SectorsPerCluster) {
00896         return FF_ERR_IOMAN_INVALID_FORMAT;
00897     }
00898     
00899     pPart->NumClusters      = pPart->DataSectors / pPart->SectorsPerCluster;
00900 
00901     Error = FF_DetermineFatType(pIoman);
00902     
00903     if(Error) {
00904         return Error;
00905     }
00906 
00907 #ifdef FF_MOUNT_FIND_FREE
00908     pPart->LastFreeCluster  = FF_FindFreeCluster(pIoman);
00909     pPart->FreeClusterCount = FF_CountFreeClusters(pIoman);
00910 #else
00911     pPart->LastFreeCluster  = 0;
00912     pPart->FreeClusterCount = 0;
00913 #endif
00914 
00915     return FF_ERR_NONE;
00916 }
00917 
00928 FF_ERROR FF_UnregisterBlkDevice(FF_IOMAN *pIoman) {
00929 
00930     FF_T_SINT8 RetVal = FF_ERR_NONE;
00931 
00932     if(!pIoman) {
00933         return FF_ERR_NULL_POINTER;
00934     }
00935 
00936     FF_PendSemaphore(pIoman->pSemaphore);
00937     {
00938         if(pIoman->pPartition->PartitionMounted == FF_FALSE) {
00939             pIoman->pBlkDevice->devBlkSize      = 0;
00940             pIoman->pBlkDevice->fnpReadBlocks   = NULL;
00941             pIoman->pBlkDevice->fnpWriteBlocks  = NULL;
00942             pIoman->pBlkDevice->pParam          = NULL;
00943         } else {
00944             RetVal = FF_ERR_IOMAN_PARTITION_MOUNTED;
00945         }
00946     }
00947     FF_ReleaseSemaphore(pIoman->pSemaphore);
00948 
00949     return RetVal;
00950 }
00951 
00962 static FF_T_BOOL FF_ActiveHandles(FF_IOMAN *pIoman) {
00963     FF_T_UINT32 i;
00964     FF_BUFFER   *pBuffer;
00965 
00966     for(i = 0; i < pIoman->CacheSize; i++) {
00967         pBuffer = (pIoman->pBuffers + i);
00968         if(pBuffer->NumHandles) {
00969             return FF_TRUE;
00970         }
00971     }
00972 
00973     return FF_FALSE;
00974 }
00975 
00976 
00985 FF_ERROR FF_UnmountPartition(FF_IOMAN *pIoman) {
00986     FF_T_SINT8 RetVal = FF_ERR_NONE;
00987 
00988     if(!pIoman) {
00989         return FF_ERR_NULL_POINTER;
00990     }
00991 
00992     FF_PendSemaphore(pIoman->pSemaphore);   // Ensure that there are no File Handles
00993     {
00994         if(!FF_ActiveHandles(pIoman)) {
00995             if(pIoman->FirstFile == NULL) {
00996                 // Release Semaphore to call this function!
00997                 FF_ReleaseSemaphore(pIoman->pSemaphore);
00998                 FF_FlushCache(pIoman);          // Flush any unwritten sectors to disk.
00999                 // Reclaim Semaphore
01000                 FF_PendSemaphore(pIoman->pSemaphore);
01001                 pIoman->pPartition->PartitionMounted = FF_FALSE;
01002             } else {
01003                 RetVal = FF_ERR_IOMAN_ACTIVE_HANDLES;
01004             }
01005         } else {
01006             RetVal = FF_ERR_IOMAN_ACTIVE_HANDLES;   // Active handles found on the cache.
01007         }
01008     }
01009     FF_ReleaseSemaphore(pIoman->pSemaphore);
01010 
01011     return RetVal;
01012 }
01013 
01014 
01015 FF_ERROR FF_IncreaseFreeClusters(FF_IOMAN *pIoman, FF_T_UINT32 Count) {
01016 
01017     FF_ERROR Error;
01018     //FF_PendSemaphore(pIoman->pSemaphore);
01019     //{
01020         if(!pIoman->pPartition->FreeClusterCount) {
01021             pIoman->pPartition->FreeClusterCount = FF_CountFreeClusters(pIoman, &Error);
01022             if(Error) {
01023                 return Error;
01024             }
01025         } else {
01026             pIoman->pPartition->FreeClusterCount += Count;
01027         }
01028     //}
01029     //FF_ReleaseSemaphore(pIoman->pSemaphore);
01030 
01031     return FF_ERR_NONE;
01032 }
01033 
01034 FF_ERROR FF_DecreaseFreeClusters(FF_IOMAN *pIoman, FF_T_UINT32 Count) {
01035 
01036     FF_ERROR Error;
01037 
01038     //FF_lockFAT(pIoman);
01039     //{
01040         if(!pIoman->pPartition->FreeClusterCount) {
01041             pIoman->pPartition->FreeClusterCount = FF_CountFreeClusters(pIoman, &Error);
01042             if(Error) {
01043                 return Error;
01044             }
01045         } else {
01046             pIoman->pPartition->FreeClusterCount -= Count;
01047         }
01048     //}
01049     //FF_unlockFAT(pIoman);
01050 
01051     return FF_ERR_NONE;
01052 }
01053 
01054 
01068 FF_T_SINT32 FF_GetPartitionBlockSize(FF_IOMAN *pIoman) {
01069 
01070     if(pIoman) {
01071         return (FF_T_SINT32) pIoman->pPartition->BlkSize;
01072     }
01073 
01074     return FF_ERR_NULL_POINTER;
01075 }
01076 
01077 #ifdef FF_64_NUM_SUPPORT
01078 
01086 FF_T_UINT64 FF_GetVolumeSize(FF_IOMAN *pIoman) {
01087     if(pIoman) {
01088         FF_T_UINT32 TotalClusters = pIoman->pPartition->DataSectors / pIoman->pPartition->SectorsPerCluster;
01089         return (FF_T_UINT64) ((FF_T_UINT64)TotalClusters * (FF_T_UINT64)((FF_T_UINT64)pIoman->pPartition->SectorsPerCluster * (FF_T_UINT64)pIoman->pPartition->BlkSize));
01090     }
01091     return 0;
01092 }
01093 
01094 #else
01095 FF_T_UINT32 FF_GetVolumeSize(FF_IOMAN *pIoman) {
01096     FF_T_UINT32 TotalClusters = pIoman->pPartition->DataSectors / pIoman->pPartition->SectorsPerCluster;
01097     return (FF_T_UINT32) (TotalClusters * (pIoman->pPartition->SectorsPerCluster * pIoman->pPartition->BlkSize));
01098 }
01099 #endif
01100 

Generated on Sun May 27 2012 04:34:09 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.