Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenff_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
1.7.6.1
|