/** * @public * @brief Writes a char to a FILE. * * @param pFile FILE Pointer. * @param pa_cValue Char to be placed in the file. * * @return Returns the value written to the file, or a value less than 0. * **/ FF_T_SINT32 FF_PutC(FF_FILE *pFile, FF_T_UINT8 pa_cValue) { FF_BUFFER *pBuffer; FF_T_UINT32 iItemLBA; FF_T_UINT32 iRelPos; FF_T_UINT32 nClusterDiff; FF_ERROR Error; if(!pFile) { // Ensure we don't have a Null file pointer on a Public interface. return FF_ERR_NULL_POINTER; } if(!(pFile->Mode & FF_MODE_WRITE)) { return FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE; } // Make sure a write is after the append point. if((pFile->Mode & FF_MODE_APPEND)) { if(pFile->FilePointer < pFile->Filesize) { FF_Seek(pFile, 0, FF_SEEK_END); } } iRelPos = FF_getMinorBlockEntry(pFile->pIoman, pFile->FilePointer, 1); // Handle File Space Allocation. Error = FF_ExtendFile(pFile, pFile->FilePointer + 1); if(Error) { return Error; } nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; if(nClusterDiff) { if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->AddrCurrentCluster, nClusterDiff, &Error); if(Error) { return Error; } pFile->CurrentCluster += nClusterDiff; } } iItemLBA = FF_Cluster2LBA(pFile->pIoman, pFile->AddrCurrentCluster) + FF_getMajorBlockNumber(pFile->pIoman, pFile->FilePointer, (FF_T_UINT16) 1); iItemLBA = FF_getRealLBA (pFile->pIoman, iItemLBA) + FF_getMinorBlockNumber(pFile->pIoman, pFile->FilePointer, (FF_T_UINT16) 1); pBuffer = FF_GetBuffer(pFile->pIoman, iItemLBA, FF_MODE_WRITE); { if(!pBuffer) { return FF_ERR_DEVICE_DRIVER_FAILED; } FF_putChar(pBuffer->pBuffer, (FF_T_UINT16) iRelPos, pa_cValue); } FF_ReleaseBuffer(pFile->pIoman, pBuffer); pFile->FilePointer += 1; if(pFile->Filesize < (pFile->FilePointer)) { pFile->Filesize += 1; } return pa_cValue; }
/** * @public * @brief Equivalent to fgetc() * * @param pFile FF_FILE object that was created by FF_Open(). * * @return The character that was read (cast as a 32-bit interger). -1 on EOF. * @return -2 If a null file pointer was provided. * @return -3 Device access failed. * **/ FF_T_SINT32 FF_GetC(FF_FILE *pFile) { FF_T_UINT32 fileLBA; FF_BUFFER *pBuffer; FF_T_UINT8 retChar; FF_T_UINT32 relMinorBlockPos; FF_T_UINT32 clusterNum; FF_T_UINT32 nClusterDiff; FF_ERROR Error; if(!pFile) { return FF_ERR_NULL_POINTER; } if(!(pFile->Mode & FF_MODE_READ)) { return FF_ERR_FILE_NOT_OPENED_IN_READ_MODE; } if(pFile->FilePointer >= pFile->Filesize) { return -1; // EOF! } relMinorBlockPos = FF_getMinorBlockEntry(pFile->pIoman, pFile->FilePointer, 1); clusterNum = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1); nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; if(nClusterDiff) { if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->AddrCurrentCluster, nClusterDiff, &Error); if(Error) { return Error; } pFile->CurrentCluster += nClusterDiff; } } fileLBA = FF_Cluster2LBA(pFile->pIoman, pFile->AddrCurrentCluster) + FF_getMajorBlockNumber(pFile->pIoman, pFile->FilePointer, (FF_T_UINT16) 1); fileLBA = FF_getRealLBA (pFile->pIoman, fileLBA) + FF_getMinorBlockNumber(pFile->pIoman, pFile->FilePointer, (FF_T_UINT16) 1); pBuffer = FF_GetBuffer(pFile->pIoman, fileLBA, FF_MODE_READ); { if(!pBuffer) { return FF_ERR_DEVICE_DRIVER_FAILED; } retChar = pBuffer->pBuffer[relMinorBlockPos]; } FF_ReleaseBuffer(pFile->pIoman, pBuffer); pFile->FilePointer += 1; return (FF_T_INT32) retChar; }
FF_ERROR FF_CreatePartitionTable(FF_IOMAN *pIoman, FF_T_UINT32 ulTotalDeviceBlocks, FF_PARTITION_TABLE *pPTable) { FF_BUFFER *pBuffer = FF_GetBuffer(pIoman, 0, FF_MODE_WRITE); { if(!pBuffer) { return FF_ERR_DEVICE_DRIVER_FAILED; } } FF_ReleaseBuffer(pIoman, pBuffer); return FF_ERR_NONE; }
FF_ERROR FF_IncreaseFreeClusters(FF_IOMAN *pIoman, FF_T_UINT32 Count) { FF_ERROR Error; #ifdef FF_WRITE_FREE_COUNT FF_BUFFER *pBuffer; #endif if(!pIoman->pPartition->FreeClusterCount) { pIoman->pPartition->FreeClusterCount = FF_CountFreeClusters(pIoman, &Error); if(FF_isERR(Error)) { return Error; } } else { pIoman->pPartition->FreeClusterCount += Count; } #ifdef FF_WRITE_FREE_COUNT // FAT32 update the FSINFO sector. if(pIoman->pPartition->Type == FF_T_FAT32) { // Find the FSINFO sector. pBuffer = FF_GetBuffer(pIoman, pIoman->pPartition->FSInfoLBA, FF_MODE_WRITE); { if(!pBuffer) { return FF_ERR_DEVICE_DRIVER_FAILED | FF_INCREASEFREECLUSTERS; } if(FF_getLong(pBuffer->pBuffer, 0) == 0x41615252 && FF_getLong(pBuffer->pBuffer, 484) == 0x61417272) { // FSINFO sector magic nums we're verified. Safe to write. FF_putLong(pBuffer->pBuffer, 488, pIoman->pPartition->FreeClusterCount); FF_putLong(pBuffer->pBuffer, 492, pIoman->pPartition->LastFreeCluster); } } Error = FF_ReleaseBuffer(pIoman, pBuffer); if(FF_isERR(Error)) { return Error; } } #endif return FF_ERR_NONE; }
/** * @public * @brief Mounts the Specified partition, the volume specified by the FF_IOMAN object provided. * * The device drivers must adhere to the specification provided by * FF_WRITE_BLOCKS and FF_READ_BLOCKS. * * @param pIoman FF_IOMAN object. * @param PartitionNumber The primary partition number to be mounted. (0 - 3). * * @return 0 on success. * @return FF_ERR_NULL_POINTER if a pIoman object wasn't provided. * @return FF_ERR_IOMAN_INVALID_PARTITION_NUM if the partition number is out of range. * @return FF_ERR_IOMAN_NO_MOUNTABLE_PARTITION if no partition was found. * @return FF_ERR_IOMAN_INVALID_FORMAT if the master boot record or partition boot block didn't provide sensible data. * @return FF_ERR_IOMAN_NOT_FAT_FORMATTED if the volume or partition couldn't be determined to be FAT. (@see ff_config.h) * **/ FF_ERROR FF_MountPartition(FF_IOMAN *pIoman, FF_T_UINT8 PartitionNumber) { FF_PARTITION *pPart; FF_BUFFER *pBuffer = 0; FF_ERROR Error; FF_T_UINT8 ucPartitionType; int partCount; if(!pIoman) { return FF_ERR_NULL_POINTER; } /*if(PartitionNumber > 3) { return FF_ERR_IOMAN_INVALID_PARTITION_NUM; }*/ pPart = pIoman->pPartition; memset (pIoman->pBuffers, '\0', sizeof(FF_BUFFER) * pIoman->CacheSize); memset (pIoman->pCacheMem, '\0', pIoman->BlkSize * pIoman->CacheSize); FF_IOMAN_InitBufferDescriptors(pIoman); pIoman->FirstFile = 0; pBuffer = FF_GetBuffer(pIoman, 0, FF_MODE_READ); if(!pBuffer) { return FF_ERR_DEVICE_DRIVER_FAILED; } partCount = FF_PartitionCount (pBuffer->pBuffer); pPart->BlkSize = FF_getShort(pBuffer->pBuffer, FF_FAT_BYTES_PER_SECTOR); if (partCount == 0) { //(pPart->BlkSize % 512) == 0 && pPart->BlkSize > 0) { // Volume is not partitioned (MBR Found) pPart->BeginLBA = 0; } else { ucPartitionType = FF_getChar(pBuffer->pBuffer, FF_FAT_PTBL + FF_FAT_PTBL_ID); // Ensure its not an EFI partition! if(ucPartitionType != 0xEE) { if(PartitionNumber > 3) { FF_ReleaseBuffer(pIoman, pBuffer); return FF_ERR_IOMAN_INVALID_PARTITION_NUM; } // Primary Partitions to deal with! pPart->BeginLBA = FF_getLong(pBuffer->pBuffer, FF_FAT_PTBL + FF_FAT_PTBL_LBA + (16 * PartitionNumber)); } FF_ReleaseBuffer(pIoman, pBuffer); if(ucPartitionType == 0xEE) { pPart->BeginLBA = FF_getLong(pBuffer->pBuffer, FF_FAT_PTBL + FF_FAT_PTBL_LBA); Error = FF_GetEfiPartitionEntry(pIoman, PartitionNumber); if(Error) { return Error; } } if(!pPart->BeginLBA) { return FF_ERR_IOMAN_NO_MOUNTABLE_PARTITION; } // Now we get the Partition sector. pBuffer = FF_GetBuffer(pIoman, pPart->BeginLBA, FF_MODE_READ); if(!pBuffer) { return FF_ERR_DEVICE_DRIVER_FAILED; } pPart->BlkSize = FF_getShort(pBuffer->pBuffer, FF_FAT_BYTES_PER_SECTOR); if((pPart->BlkSize % 512) != 0 || pPart->BlkSize == 0) { FF_ReleaseBuffer(pIoman, pBuffer); return FF_ERR_IOMAN_INVALID_FORMAT; } } // Assume FAT16, then we'll adjust if its FAT32 pPart->ReservedSectors = FF_getShort(pBuffer->pBuffer, FF_FAT_RESERVED_SECTORS); pPart->FatBeginLBA = pPart->BeginLBA + pPart->ReservedSectors; pPart->NumFATS = (FF_T_UINT8) FF_getShort(pBuffer->pBuffer, FF_FAT_NUMBER_OF_FATS); pPart->SectorsPerFAT = (FF_T_UINT32) FF_getShort(pBuffer->pBuffer, FF_FAT_16_SECTORS_PER_FAT); pPart->SectorsPerCluster = FF_getChar(pBuffer->pBuffer, FF_FAT_SECTORS_PER_CLUS); pPart->BlkFactor = (FF_T_UINT8) (pPart->BlkSize / pIoman->BlkSize); // Set the BlockFactor (How many real-blocks in a fake block!). if(pPart->SectorsPerFAT == 0) { // FAT32 pPart->SectorsPerFAT = FF_getLong(pBuffer->pBuffer, FF_FAT_32_SECTORS_PER_FAT); pPart->RootDirCluster = FF_getLong(pBuffer->pBuffer, FF_FAT_ROOT_DIR_CLUSTER); pPart->ClusterBeginLBA = pPart->BeginLBA + pPart->ReservedSectors + (pPart->NumFATS * pPart->SectorsPerFAT); pPart->TotalSectors = (FF_T_UINT32) FF_getShort(pBuffer->pBuffer, FF_FAT_16_TOTAL_SECTORS); if(pPart->TotalSectors == 0) { pPart->TotalSectors = FF_getLong(pBuffer->pBuffer, FF_FAT_32_TOTAL_SECTORS); } memcpy (pPart->VolLabel, pBuffer->pBuffer + FF_FAT_32_VOL_LABEL, sizeof pPart->VolLabel); } else { // FAT16 pPart->ClusterBeginLBA = pPart->BeginLBA + pPart->ReservedSectors + (pPart->NumFATS * pPart->SectorsPerFAT); pPart->TotalSectors = (FF_T_UINT32) FF_getShort(pBuffer->pBuffer, FF_FAT_16_TOTAL_SECTORS); pPart->RootDirCluster = 1; // 1st Cluster is RootDir! if(pPart->TotalSectors == 0) { pPart->TotalSectors = FF_getLong(pBuffer->pBuffer, FF_FAT_32_TOTAL_SECTORS); } memcpy (pPart->VolLabel, pBuffer->pBuffer + FF_FAT_16_VOL_LABEL, sizeof pPart->VolLabel); } FF_ReleaseBuffer(pIoman, pBuffer); // Release the buffer finally! if(!pPart->BlkSize) { return FF_ERR_IOMAN_INVALID_FORMAT; } pPart->RootDirSectors = ((FF_getShort(pBuffer->pBuffer, FF_FAT_ROOT_ENTRY_COUNT) * 32) + pPart->BlkSize - 1) / pPart->BlkSize; pPart->FirstDataSector = pPart->ClusterBeginLBA + pPart->RootDirSectors; pPart->DataSectors = pPart->TotalSectors - (pPart->ReservedSectors + (pPart->NumFATS * pPart->SectorsPerFAT) + pPart->RootDirSectors); if(!pPart->SectorsPerCluster) { return FF_ERR_IOMAN_INVALID_FORMAT; } pPart->NumClusters = pPart->DataSectors / pPart->SectorsPerCluster; Error = FF_DetermineFatType(pIoman); if(Error) { return Error; } #ifdef FF_MOUNT_FIND_FREE pPart->LastFreeCluster = FF_FindFreeCluster(pIoman); pPart->FreeClusterCount = FF_CountFreeClusters(pIoman); #else pPart->LastFreeCluster = 0; pPart->FreeClusterCount = 0; #endif return FF_ERR_NONE; }
static FF_ERROR FF_GetEfiPartitionEntry(FF_IOMAN *pIoman, FF_T_UINT32 ulPartitionNumber) { // Continuing on from FF_MountPartition() pPartition->BeginLBA should be the sector of the GPT Header FF_BUFFER *pBuffer; FF_PARTITION *pPart = pIoman->pPartition; FF_T_UINT32 ulBeginGPT; FF_T_UINT32 ulEntrySector; FF_T_UINT32 ulSectorOffset; FF_T_UINT32 ulTotalPartitionEntries; FF_T_UINT32 ulPartitionEntrySize; FF_T_UINT32 ulGPTHeadCRC, ulGPTCrcCheck, ulGPTHeadLength; if(ulPartitionNumber >= 128) { return FF_ERR_IOMAN_INVALID_PARTITION_NUM; } pBuffer = FF_GetBuffer(pIoman, pPart->BeginLBA, FF_MODE_READ); { if(!pBuffer) { return FF_ERR_DEVICE_DRIVER_FAILED; } // Verify this is an EFI header if(memcmp(pBuffer->pBuffer, "EFI PART", 8) != 0) { FF_ReleaseBuffer(pIoman, pBuffer); return FF_ERR_IOMAN_INVALID_FORMAT; } ulBeginGPT = FF_getLong(pBuffer->pBuffer, FF_GPT_HEAD_PART_ENTRY_LBA); ulTotalPartitionEntries = FF_getLong(pBuffer->pBuffer, FF_GPT_HEAD_TOTAL_ENTRIES); ulPartitionEntrySize = FF_getLong(pBuffer->pBuffer, FF_GPT_HEAD_ENTRY_SIZE); ulGPTHeadCRC = FF_getLong(pBuffer->pBuffer, FF_GPT_HEAD_CRC); ulGPTHeadLength = FF_getLong(pBuffer->pBuffer, FF_GPT_HEAD_LENGTH); // Calculate Head CRC // Blank CRC field FF_putLong(pBuffer->pBuffer, FF_GPT_HEAD_CRC, 0x00000000); // Calculate CRC ulGPTCrcCheck = FF_GetCRC32(pBuffer->pBuffer, ulGPTHeadLength); // Restore The CRC field FF_putLong(pBuffer->pBuffer, FF_GPT_HEAD_CRC, ulGPTHeadCRC); } FF_ReleaseBuffer(pIoman, pBuffer); // Check CRC if(ulGPTHeadCRC != ulGPTCrcCheck) { return FF_ERR_IOMAN_GPT_HEADER_CORRUPT; } // Calculate Sector Containing the Partition Entry we want to use. ulEntrySector = ((ulPartitionNumber * ulPartitionEntrySize) / pIoman->BlkSize) + ulBeginGPT; ulSectorOffset = (ulPartitionNumber % (pIoman->BlkSize / ulPartitionEntrySize)) * ulPartitionEntrySize; pBuffer = FF_GetBuffer(pIoman, ulEntrySector, FF_MODE_READ); { if(!pBuffer) { return FF_ERR_DEVICE_DRIVER_FAILED; } pPart->BeginLBA = FF_getLong(pBuffer->pBuffer, ulSectorOffset + FF_GPT_ENTRY_FIRST_SECTOR_LBA); } FF_ReleaseBuffer(pIoman, pBuffer); if(!pPart->BeginLBA) { return FF_ERR_IOMAN_INVALID_PARTITION_NUM; } return FF_ERR_NONE; }
/** * @private **/ static FF_ERROR FF_DetermineFatType(FF_IOMAN *pIoman) { FF_PARTITION *pPart; FF_BUFFER *pBuffer; FF_T_UINT32 testLong; if(pIoman) { pPart = pIoman->pPartition; if(pPart->NumClusters < 4085) { // FAT12 pPart->Type = FF_T_FAT12; #ifdef FF_FAT_CHECK #ifdef FF_FAT12_SUPPORT pBuffer = FF_GetBuffer(pIoman, pIoman->pPartition->FatBeginLBA, FF_MODE_READ); { if(!pBuffer) { return FF_ERR_DEVICE_DRIVER_FAILED; } testLong = (FF_T_UINT32) FF_getShort(pBuffer->pBuffer, 0x0000); } FF_ReleaseBuffer(pIoman, pBuffer); if((testLong & 0x3FF) != 0x3F8) { return FF_ERR_IOMAN_NOT_FAT_FORMATTED; } #else return FF_ERR_IOMAN_NOT_FAT_FORMATTED; #endif #endif #ifdef FF_FAT12_SUPPORT return FF_ERR_NONE; #endif } else if(pPart->NumClusters < 65525) { // FAT 16 pPart->Type = FF_T_FAT16; #ifdef FF_FAT_CHECK pBuffer = FF_GetBuffer(pIoman, pIoman->pPartition->FatBeginLBA, FF_MODE_READ); { if(!pBuffer) { return FF_ERR_DEVICE_DRIVER_FAILED; } testLong = (FF_T_UINT32) FF_getShort(pBuffer->pBuffer, 0x0000); } FF_ReleaseBuffer(pIoman, pBuffer); if(testLong != 0xFFF8) { return FF_ERR_IOMAN_NOT_FAT_FORMATTED; } #endif return FF_ERR_NONE; } else { // FAT 32! pPart->Type = FF_T_FAT32; #ifdef FF_FAT_CHECK pBuffer = FF_GetBuffer(pIoman, pIoman->pPartition->FatBeginLBA, FF_MODE_READ); { if(!pBuffer) { return FF_ERR_DEVICE_DRIVER_FAILED; } testLong = FF_getLong(pBuffer->pBuffer, 0x0000); } FF_ReleaseBuffer(pIoman, pBuffer); if((testLong & 0x0FFFFFF8) != 0x0FFFFFF8 && (testLong & 0x0FFFFFF8) != 0x0FFFFFF0) { return FF_ERR_IOMAN_NOT_FAT_FORMATTED; } #endif return FF_ERR_NONE; } } return FF_ERR_IOMAN_NOT_FAT_FORMATTED; }
/** * @public * @brief Equivalent to fread() * * @param pFile FF_FILE object that was created by FF_Open(). * @param ElementSize The size of an element to read. * @param Count The number of elements to read. * @param buffer A pointer to a buffer of adequate size to be filled with the requested data. * * @return Number of bytes read. * **/ FF_T_SINT32 FF_Read(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, FF_T_UINT8 *buffer) { FF_T_UINT32 nBytes = ElementSize * Count; FF_T_UINT32 nBytesRead = 0; FF_T_UINT32 nBytesToRead; FF_IOMAN *pIoman; FF_BUFFER *pBuffer; FF_T_UINT32 nRelBlockPos; FF_T_UINT32 nItemLBA; FF_T_SINT32 RetVal = 0; FF_T_UINT16 sSectors; FF_T_UINT32 nRelClusterPos; FF_T_UINT32 nBytesPerCluster; FF_T_UINT32 nClusterDiff; if(!pFile) { return FF_ERR_NULL_POINTER; } if(!(pFile->Mode & FF_MODE_READ)) { return FF_ERR_FILE_NOT_OPENED_IN_READ_MODE; } pIoman = pFile->pIoman; if(pFile->FilePointer == pFile->Filesize) { return 0; } if((pFile->FilePointer + nBytes) > pFile->Filesize) { nBytes = pFile->Filesize - pFile->FilePointer; } nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; if(nClusterDiff) { if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff); pFile->CurrentCluster += nClusterDiff; } } nRelBlockPos = FF_getMinorBlockEntry(pIoman, pFile->FilePointer, 1); // Get the position within a block. nItemLBA = FF_Cluster2LBA(pIoman, pFile->AddrCurrentCluster); nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1); if((nRelBlockPos + nBytes) < pIoman->BlkSize) { // Bytes to read are within a block and less than a block size. pBuffer = FF_GetBuffer(pIoman, nItemLBA, FF_MODE_READ); { memcpy(buffer, (pBuffer->pBuffer + nRelBlockPos), nBytes); } FF_ReleaseBuffer(pIoman, pBuffer); pFile->FilePointer += nBytes; return nBytes; // Return the number of bytes read. } else { //---------- Read (memcpy) to a Sector Boundary if(nRelBlockPos != 0) { // Not on a sector boundary, at this point the LBA is known. nBytesToRead = pIoman->BlkSize - nRelBlockPos; pBuffer = FF_GetBuffer(pIoman, nItemLBA, FF_MODE_READ); { // Here we copy to the sector boudary. memcpy(buffer, (pBuffer->pBuffer + nRelBlockPos), nBytesToRead); } FF_ReleaseBuffer(pIoman, pBuffer); nBytes -= nBytesToRead; nBytesRead += nBytesToRead; pFile->FilePointer += nBytesToRead; buffer += nBytesToRead; } //---------- Read to a Cluster Boundary nRelClusterPos = FF_getClusterPosition(pIoman, pFile->FilePointer, 1); nBytesPerCluster = (pIoman->pPartition->SectorsPerCluster * pIoman->BlkSize); if(nRelClusterPos != 0 && nBytes >= nBytesPerCluster) { // Need to get to cluster boundary nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; if(nClusterDiff) { if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff); pFile->CurrentCluster += nClusterDiff; } } nItemLBA = FF_Cluster2LBA(pIoman, pFile->AddrCurrentCluster); nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1); sSectors = (FF_T_UINT16) (pIoman->pPartition->SectorsPerCluster - (nRelClusterPos / pIoman->BlkSize)); do { if(pIoman->pBlkDevice->fnReadBlocks) { #ifdef FF_BLKDEV_USES_SEM FF_PendSemaphore(pFile->pIoman->pSemaphore); #endif RetVal = pFile->pIoman->pBlkDevice->fnReadBlocks(buffer, nItemLBA, sSectors, pIoman->pBlkDevice->pParam); #ifdef FF_BLKDEV_USES_SEM FF_ReleaseSemaphore(pFile->pIoman->pSemaphore); #endif } if(RetVal == FF_ERR_DRIVER_BUSY) { FF_Yield(); FF_Sleep(FF_DRIVER_BUSY_SLEEP); } }while(RetVal == FF_ERR_DRIVER_BUSY); nBytesToRead = sSectors * pIoman->BlkSize; nBytes -= nBytesToRead; buffer += nBytesToRead; nBytesRead += nBytesToRead; pFile->FilePointer += nBytesToRead; } //---------- Read Clusters if(nBytes >= nBytesPerCluster) { //----- Thanks to Christopher Clark of DigiPen Institute of Technology in Redmond, US adding this traversal check. nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; if(nClusterDiff) { if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff); pFile->CurrentCluster += nClusterDiff; } } //----- End of Contributor fix. FF_ReadClusters(pFile, (nBytes / nBytesPerCluster), buffer); nBytesToRead = (nBytesPerCluster * (nBytes / nBytesPerCluster)); pFile->FilePointer += nBytesToRead; nBytes -= nBytesToRead; buffer += nBytesToRead; nBytesRead += nBytesToRead; } //---------- Read Remaining Blocks if(nBytes >= pIoman->BlkSize) { sSectors = (FF_T_UINT16) (nBytes / pIoman->BlkSize); nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; if(nClusterDiff) { if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff); pFile->CurrentCluster += nClusterDiff; } } nItemLBA = FF_Cluster2LBA(pIoman, pFile->AddrCurrentCluster); nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1); do { if(pIoman->pBlkDevice->fnReadBlocks) { #ifdef FF_BLKDEV_USES_SEM FF_PendSemaphore(pFile->pIoman->pSemaphore); #endif RetVal = pFile->pIoman->pBlkDevice->fnReadBlocks(buffer, nItemLBA, sSectors, pIoman->pBlkDevice->pParam); #ifdef FF_BLKDEV_USES_SEM FF_ReleaseSemaphore(pFile->pIoman->pSemaphore); #endif } if(RetVal == FF_ERR_DRIVER_BUSY) { FF_Yield(); FF_Sleep(FF_DRIVER_BUSY_SLEEP); } }while(RetVal == FF_ERR_DRIVER_BUSY); nBytesToRead = sSectors * pIoman->BlkSize; pFile->FilePointer += nBytesToRead; nBytes -= nBytesToRead; buffer += nBytesToRead; nBytesRead += nBytesToRead; } //---------- Read (memcpy) Remaining Bytes if(nBytes > 0) { nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; if(nClusterDiff) { if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff); pFile->CurrentCluster += nClusterDiff; } } nItemLBA = FF_Cluster2LBA(pIoman, pFile->AddrCurrentCluster); nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1); pBuffer = FF_GetBuffer(pIoman, nItemLBA, FF_MODE_READ); { memcpy(buffer, pBuffer->pBuffer, nBytes); } FF_ReleaseBuffer(pIoman, pBuffer); nBytesToRead = nBytes; pFile->FilePointer += nBytesToRead; nBytes -= nBytesToRead; buffer += nBytesToRead; nBytesRead += nBytesToRead; } } return nBytesRead; }
/** * @public * @brief Writes data to a File. * * @param pFile FILE Pointer. * @param ElementSize Size of an Element of Data to be copied. (in bytes). * @param Count Number of Elements of Data to be copied. (ElementSize * Count must not exceed ((2^31)-1) bytes. (2GB). For best performance, multiples of 512 bytes or Cluster sizes are best. * @param buffer Byte-wise buffer containing the data to be written. * * @return **/ FF_T_SINT32 FF_Write(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, FF_T_UINT8 *buffer) { FF_T_UINT32 nBytes = ElementSize * Count; FF_T_UINT32 nBytesWritten = 0; FF_T_UINT32 nBytesToWrite; FF_IOMAN *pIoman; FF_BUFFER *pBuffer; FF_T_UINT32 nRelBlockPos; FF_T_UINT32 nItemLBA; FF_T_SINT32 RetVal = 0; FF_T_UINT16 sSectors; FF_T_UINT32 nRelClusterPos; FF_T_UINT32 nBytesPerCluster, nClusterDiff, nClusters; FF_ERROR Error; if(!pFile) { return FF_ERR_NULL_POINTER; } if(!(pFile->Mode & FF_MODE_WRITE)) { return FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE; } // Make sure a write is after the append point. if((pFile->Mode & FF_MODE_APPEND)) { if(pFile->FilePointer < pFile->Filesize) { FF_Seek(pFile, 0, FF_SEEK_END); } } pIoman = pFile->pIoman; nBytesPerCluster = (pIoman->pPartition->SectorsPerCluster * pIoman->BlkSize); // Extend File for atleast nBytes! // Handle file-space allocation Error = FF_ExtendFile(pFile, pFile->FilePointer + nBytes); if(Error) { return Error; } nRelBlockPos = FF_getMinorBlockEntry(pIoman, pFile->FilePointer, 1); // Get the position within a block. nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; if(nClusterDiff) { if(pFile->CurrentCluster != FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff); pFile->CurrentCluster += nClusterDiff; } } nItemLBA = FF_Cluster2LBA(pIoman, pFile->AddrCurrentCluster); nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1); if((nRelBlockPos + nBytes) < pIoman->BlkSize) { // Bytes to read are within a block and less than a block size. pBuffer = FF_GetBuffer(pIoman, nItemLBA, FF_MODE_WRITE); { memcpy((pBuffer->pBuffer + nRelBlockPos), buffer, nBytes); } FF_ReleaseBuffer(pIoman, pBuffer); pFile->FilePointer += nBytes; nBytesWritten = nBytes; //return nBytes; // Return the number of bytes read. } else { //---------- Write (memcpy) to a Sector Boundary if(nRelBlockPos != 0) { // Not on a sector boundary, at this point the LBA is known. nBytesToWrite = pIoman->BlkSize - nRelBlockPos; pBuffer = FF_GetBuffer(pIoman, nItemLBA, FF_MODE_WRITE); { // Here we copy to the sector boudary. memcpy((pBuffer->pBuffer + nRelBlockPos), buffer, nBytesToWrite); } FF_ReleaseBuffer(pIoman, pBuffer); nBytes -= nBytesToWrite; nBytesWritten += nBytesToWrite; pFile->FilePointer += nBytesToWrite; buffer += nBytesToWrite; } //---------- Write to a Cluster Boundary nRelClusterPos = FF_getClusterPosition(pIoman, pFile->FilePointer, 1); if(nRelClusterPos != 0 && nBytes >= nBytesPerCluster) { // Need to get to cluster boundary nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; if(nClusterDiff) { if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff); pFile->CurrentCluster += nClusterDiff; } } nItemLBA = FF_Cluster2LBA(pIoman, pFile->AddrCurrentCluster); nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1); sSectors = (FF_T_UINT16) (pIoman->pPartition->SectorsPerCluster - (nRelClusterPos / pIoman->BlkSize)); do { if(pIoman->pBlkDevice->fnWriteBlocks) { #ifdef FF_BLKDEV_USES_SEM FF_PendSemaphore(pFile->pIoman->pSemaphore); #endif RetVal = pFile->pIoman->pBlkDevice->fnWriteBlocks(buffer, nItemLBA, sSectors, pIoman->pBlkDevice->pParam); #ifdef FF_BLKDEV_USES_SEM FF_ReleaseSemaphore(pFile->pIoman->pSemaphore); #endif } if(RetVal == FF_ERR_DRIVER_BUSY) { FF_Yield(); FF_Sleep(FF_DRIVER_BUSY_SLEEP); } }while(RetVal == FF_ERR_DRIVER_BUSY); nBytesToWrite = sSectors * pIoman->BlkSize; nBytes -= nBytesToWrite; buffer += nBytesToWrite; nBytesWritten += nBytesToWrite; pFile->FilePointer += nBytesToWrite; } //---------- Write Clusters if(nBytes >= nBytesPerCluster) { //----- Thanks to Christopher Clark of DigiPen Institute of Technology in Redmond, US adding this traversal check. nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; if(nClusterDiff) { if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff); pFile->CurrentCluster += nClusterDiff; } } //----- End of Contributor fix. nClusters = (nBytes / nBytesPerCluster); FF_WriteClusters(pFile, nClusters, buffer); nBytesToWrite = (nBytesPerCluster * nClusters); pFile->FilePointer += nBytesToWrite; nBytes -= nBytesToWrite; buffer += nBytesToWrite; nBytesWritten += nBytesToWrite; } //---------- Write Remaining Blocks if(nBytes >= pIoman->BlkSize) { sSectors = (FF_T_UINT16) (nBytes / pIoman->BlkSize); nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; if(nClusterDiff) { if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff); pFile->CurrentCluster += nClusterDiff; } } nItemLBA = FF_Cluster2LBA(pIoman, pFile->AddrCurrentCluster); nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1); do { if(pIoman->pBlkDevice->fnWriteBlocks) { #ifdef FF_BLKDEV_USES_SEM FF_PendSemaphore(pFile->pIoman->pSemaphore); #endif RetVal = pFile->pIoman->pBlkDevice->fnWriteBlocks(buffer, nItemLBA, sSectors, pIoman->pBlkDevice->pParam); #ifdef FF_BLKDEV_USES_SEM FF_ReleaseSemaphore(pFile->pIoman->pSemaphore); #endif } if(RetVal == FF_ERR_DRIVER_BUSY) { FF_Yield(); FF_Sleep(FF_DRIVER_BUSY_SLEEP); } }while(RetVal == FF_ERR_DRIVER_BUSY); nBytesToWrite = sSectors * pIoman->BlkSize; pFile->FilePointer += nBytesToWrite; nBytes -= nBytesToWrite; buffer += nBytesToWrite; nBytesWritten += nBytesToWrite; } //---------- Write (memcpy) Remaining Bytes if(nBytes > 0) { nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster; if(nClusterDiff) { if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) { pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff); pFile->CurrentCluster += nClusterDiff; } } nItemLBA = FF_Cluster2LBA(pIoman, pFile->AddrCurrentCluster); nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1); pBuffer = FF_GetBuffer(pIoman, nItemLBA, FF_MODE_WRITE); { memcpy(pBuffer->pBuffer, buffer, nBytes); } FF_ReleaseBuffer(pIoman, pBuffer); nBytesToWrite = nBytes; pFile->FilePointer += nBytesToWrite; nBytes -= nBytesToWrite; buffer += nBytesToWrite; nBytesWritten += nBytesToWrite; } } if(pFile->FilePointer > pFile->Filesize) { pFile->Filesize = pFile->FilePointer; } return nBytesWritten; }
/** * @private **/ static FF_ERROR FF_DetermineFatType(FF_IOMAN *pIoman) { FF_PARTITION *pPart; FF_BUFFER *pBuffer; FF_T_UINT32 testLong; FF_ERROR Error; if(pIoman) { pPart = pIoman->pPartition; if(pPart->NumClusters < 4085) { // FAT12 pPart->Type = FF_T_FAT12; #ifdef FF_FAT_CHECK #ifdef FF_FAT12_SUPPORT pBuffer = FF_GetBuffer(pIoman, pIoman->pPartition->FatBeginLBA, FF_MODE_READ); { if(!pBuffer) { return FF_ERR_DEVICE_DRIVER_FAILED | FF_DETERMINEFATTYPE; } testLong = (FF_T_UINT32) FF_getShort(pBuffer->pBuffer, 0x0000); } Error = FF_ReleaseBuffer(pIoman, pBuffer); if(FF_isERR(Error)) { return Error; } if((testLong & 0x3FF) != 0x3F8) { return FF_ERR_IOMAN_NOT_FAT_FORMATTED | FF_DETERMINEFATTYPE; } #else return FF_ERR_IOMAN_NOT_FAT_FORMATTED | FF_DETERMINEFATTYPE; #endif #endif #ifdef FF_FAT12_SUPPORT return FF_ERR_NONE; #endif } else if(pPart->NumClusters < 65525) { // FAT 16 pPart->Type = FF_T_FAT16; #ifdef FF_FAT_CHECK pBuffer = FF_GetBuffer(pIoman, pIoman->pPartition->FatBeginLBA, FF_MODE_READ); { if(!pBuffer) { return FF_ERR_DEVICE_DRIVER_FAILED | FF_DETERMINEFATTYPE; } testLong = (FF_T_UINT32) FF_getShort(pBuffer->pBuffer, 0x0000); } Error = FF_ReleaseBuffer(pIoman, pBuffer); if(FF_isERR(Error)) { return Error; } if(testLong == 0xFFF8) return FF_ERR_NONE; #endif } else { // FAT 32! pPart->Type = FF_T_FAT32; #ifdef FF_FAT_CHECK pBuffer = FF_GetBuffer(pIoman, pIoman->pPartition->FatBeginLBA, FF_MODE_READ); { if(!pBuffer) { return FF_ERR_DEVICE_DRIVER_FAILED | FF_DETERMINEFATTYPE; } testLong = FF_getLong(pBuffer->pBuffer, 0x0000); } Error = FF_ReleaseBuffer(pIoman, pBuffer); if(FF_isERR(Error)) { return Error; } if((testLong & 0x0FFFFFF8) != 0x0FFFFFF8 && (testLong & 0x0FFFFFF8) != 0x0FFFFFF0) { // HT: // I had an SD-card which worked well in Linux/W32 // but FullFAT returned me this error // So for me I left out this check (just issue a warning for now) return FF_ERR_NONE; // FF_ERR_IOMAN_NOT_FAT_FORMATTED; } #endif return FF_ERR_NONE; } } return FF_ERR_IOMAN_NOT_FAT_FORMATTED | FF_DETERMINEFATTYPE; }
FF_ERROR FF_FormatPartition(FF_IOMAN *pIoman, FF_T_UINT32 ulPartitionNumber, FF_T_UINT32 ulClusterSize) { FF_BUFFER *pBuffer; FF_T_SINT8 scPartitionCount; FF_T_UINT32 maxClusters, f16MaxClusters, f32MaxClusters; FF_T_UINT32 fatSize = 32; // Default to a fat32 format. FF_PARTITION_ENTRY partitionGeom; FF_T_UINT32 ulBPRLba; ///< The LBA of the boot partition record. FF_T_UINT32 fat32Size, fat16Size, newFat32Size, newFat16Size, finalFatSize; FF_T_UINT32 sectorsPerCluster = ulClusterSize / pIoman->BlkSize; FF_T_UINT32 ulReservedSectors, ulTotalSectors; FF_T_UINT32 ul32DataSectors, ul16DataSectors; FF_T_UINT32 i; FF_T_UINT32 ulClusterBeginLBA; FF_ERROR Error = FF_ERR_NONE; // Get Partition Metrics, and pass on to FF_Format() function pBuffer = FF_GetBuffer(pIoman, 0, FF_MODE_READ); { if(!pBuffer) { return FF_ERR_DEVICE_DRIVER_FAILED | FF_FORMATPARTITION; } scPartitionCount = FF_PartitionCount(pBuffer->pBuffer); if(!scPartitionCount) { // Get Partition Geom from volume boot record. ulBPRLba = 0; partitionGeom.ulStartLBA = FF_getShort(pBuffer->pBuffer, FF_FAT_RESERVED_SECTORS); // Get offset to start of where we can actually put the FAT table. ulReservedSectors = partitionGeom.ulStartLBA; partitionGeom.ulLength = (FF_T_UINT32) FF_getShort(pBuffer->pBuffer, FF_FAT_16_TOTAL_SECTORS); if(partitionGeom.ulLength == 0) { // 32-bit entry was used. partitionGeom.ulLength = FF_getLong(pBuffer->pBuffer, FF_FAT_32_TOTAL_SECTORS); } ulTotalSectors = partitionGeom.ulLength; partitionGeom.ulLength -= partitionGeom.ulStartLBA; // Remove the reserved sectors from the count. } else { // Get partition Geom from the partition table entry. } // Calculate the max possiblenumber of clusters based on clustersize. maxClusters = partitionGeom.ulLength / sectorsPerCluster; // Determine the size of a FAT table required to support this. fat32Size = (maxClusters * 4) / pIoman->BlkSize; // Potential size in sectors of a fat32 table. if((maxClusters * 4) % pIoman->BlkSize) { fat32Size++; } fat32Size *= 2; // Officially there are 2 copies of the FAT. fat16Size = (maxClusters * 2) / pIoman->BlkSize; // Potential size in bytes of a fat16 table. if((maxClusters * 2) % pIoman->BlkSize) { fat16Size++; } fat16Size *= 2; // A real number of sectors to be available is therefore ~~ ul16DataSectors = partitionGeom.ulLength - fat16Size; ul32DataSectors = partitionGeom.ulLength - fat32Size; f16MaxClusters = ul16DataSectors / sectorsPerCluster; f32MaxClusters = ul32DataSectors / sectorsPerCluster; newFat16Size = (f16MaxClusters * 2) / pIoman->BlkSize; if((f16MaxClusters * 2) % pIoman->BlkSize) { newFat16Size++; } newFat32Size = (f32MaxClusters * 4) / pIoman->BlkSize; if((f32MaxClusters * 4) % pIoman->BlkSize) { newFat32Size++; } // Now determine if this should be fat16/32 format? if(f16MaxClusters < 65525) { fatSize = 16; finalFatSize = newFat16Size; } else { fatSize = 32; finalFatSize = newFat32Size; } FF_ReleaseBuffer(pIoman, pBuffer); for(i = 0; i < finalFatSize*2; i++) { // Ensure the FAT table is clear. if(i == 0) { pBuffer = FF_GetBuffer(pIoman, partitionGeom.ulStartLBA, FF_MODE_WR_ONLY); if(!pBuffer) { return FF_ERR_DEVICE_DRIVER_FAILED; } memset(pBuffer->pBuffer, 0, pIoman->BlkSize); } else { FF_BlockWrite(pIoman, partitionGeom.ulStartLBA+i, 1, pBuffer->pBuffer, FF_FALSE); } } switch(fatSize) { case 16: { FF_putShort(pBuffer->pBuffer, 0, 0xFFF8); // First FAT entry. FF_putShort(pBuffer->pBuffer, 2, 0xFFFF); // RESERVED alloc. break; } case 32: { FF_putLong(pBuffer->pBuffer, 0, 0x0FFFFFF8); // FAT32 FAT sig. FF_putLong(pBuffer->pBuffer, 4, 0xFFFFFFFF); // RESERVED alloc. FF_putLong(pBuffer->pBuffer, 8, 0x0FFFFFFF); // Root dir allocation. break; } default: break; } FF_ReleaseBuffer(pIoman, pBuffer); // Clear and initialise the root dir. ulClusterBeginLBA = partitionGeom.ulStartLBA + (finalFatSize*2); for(i = 0; i < sectorsPerCluster; i++) { if(i == 0) { pBuffer = FF_GetBuffer(pIoman, ulClusterBeginLBA, FF_MODE_WR_ONLY); memset(pBuffer->pBuffer, 0, pIoman->BlkSize); } else { FF_BlockWrite(pIoman, ulClusterBeginLBA+i, 1, pBuffer->pBuffer, FF_FALSE); } } FF_ReleaseBuffer(pIoman, pBuffer); // Correctly modify the second FAT item again. pBuffer = FF_GetBuffer(pIoman, partitionGeom.ulStartLBA + finalFatSize, FF_MODE_WRITE); { switch(fatSize) { case 16: { FF_putShort(pBuffer->pBuffer, 0, 0xFFF8); FF_putShort(pBuffer->pBuffer, 2, 0xFFFF); break; } case 32: FF_putLong(pBuffer->pBuffer, 0, 0x0FFFFFF8); FF_putLong(pBuffer->pBuffer, 4, 0xFFFFFFFF); FF_putLong(pBuffer->pBuffer, 8, 0x0FFFFFFF); // Root dir allocation. } } FF_ReleaseBuffer(pIoman, pBuffer); // Modify the fields in the VBR/PBR for correct mounting. pBuffer = FF_GetBuffer(pIoman, ulBPRLba, FF_MODE_WRITE); // Modify the FAT descriptions. { // -- First section Common vars to Fat12/16 and 32. memset(pBuffer->pBuffer, 0, pIoman->BlkSize); // Clear the boot record. FF_putChar(pBuffer->pBuffer, 0, 0xEB); // Place the Jump to bootstrap x86 instruction. FF_putChar(pBuffer->pBuffer, 1, 0x3C); // Even though we won't populate the bootstrap code. FF_putChar(pBuffer->pBuffer, 2, 0x90); // Some devices look for this as a signature. memcpy(((FF_T_UINT8 *)pBuffer->pBuffer+3), "FULLFAT2", 8); // Place the FullFAT OEM code. FF_putShort(pBuffer->pBuffer, 11, pIoman->BlkSize); FF_putChar(pBuffer->pBuffer, 13, (FF_T_UINT8) sectorsPerCluster); FF_putShort(pBuffer->pBuffer, FF_FAT_RESERVED_SECTORS, (FF_T_UINT16)partitionGeom.ulStartLBA); // Number of reserved sectors. (1 for fat12/16, 32 for f32). FF_putShort(pBuffer->pBuffer, FF_FAT_NUMBER_OF_FATS, 2); // Always 2 copies. //FF_putShort(pBuffer->pBuffer, 19, 0); // Number of sectors in partition if size < 32mb. FF_putChar(pBuffer->pBuffer, 21, 0xF8); // Media type -- HDD. FF_putShort(pBuffer->pBuffer, 510, 0xAA55); // MBR sig. FF_putLong(pBuffer->pBuffer, 32, partitionGeom.ulLength+partitionGeom.ulStartLBA); // Total sectors of this partition. if(fatSize == 32) { FF_putShort(pBuffer->pBuffer, 36, (FF_T_UINT16)finalFatSize); // Number of sectors per fat. FF_putShort(pBuffer->pBuffer, 44, 2); // Root dir cluster (2). FF_putShort(pBuffer->pBuffer, 48, 1); // FSINFO sector at LBA1. FF_putShort(pBuffer->pBuffer, 50, 6); // 0 for no backup boot sector. FF_putChar(pBuffer->pBuffer, 66, 0x29); // Indicate extended signature is present. memcpy(((FF_T_UINT8 *)pBuffer->pBuffer+71), "FullFAT2-V", 10); // Volume name. memcpy(((FF_T_UINT8 *)pBuffer->pBuffer+81), "FAT32 ", 8); // Put backup boot sector. FF_BlockWrite(pIoman, 6, 1, pBuffer->pBuffer, FF_FALSE); } else { FF_putChar(pBuffer->pBuffer, 38, 0x28); // Signal this contains an extended signature. memcpy(((FF_T_UINT8 *)pBuffer->pBuffer+43), "FullFAT2-V", 10); // Volume name. memcpy(((FF_T_UINT8 *)pBuffer->pBuffer+54), "FAT16 ", 8); FF_putShort(pBuffer->pBuffer, FF_FAT_16_SECTORS_PER_FAT, (FF_T_UINT16) finalFatSize); FF_putShort(pBuffer->pBuffer, 17, 512); // Number of Dir entries. (FAT32 0). //FF_putShort(pBuffer->pBuffer, FF_FAT_ROOT_ENTRY_COUNT, } } } FF_ReleaseBuffer(pIoman, pBuffer); if(fatSize == 32) { // Finally if FAT32, create an FSINFO sector. pBuffer = FF_GetBuffer(pIoman, 1, FF_MODE_WRITE); { memset(pBuffer->pBuffer, 0, pIoman->BlkSize); FF_putLong(pBuffer->pBuffer, 0, 0x41615252); // FSINFO sect magic number. FF_putLong(pBuffer->pBuffer, 484, 0x61417272); // FSINFO second sig. // Calculate total sectors, -1 for the root dir allocation. (Free sectors count). FF_putLong(pBuffer->pBuffer, 488, ((ulTotalSectors - (ulReservedSectors + (2*finalFatSize))) / sectorsPerCluster)-1); FF_putLong(pBuffer->pBuffer, 492, 2); // Hint for next free cluster. FF_putShort(pBuffer->pBuffer, 510, 0xAA55); } FF_ReleaseBuffer(pIoman, pBuffer); } FF_FlushCache(pIoman); return Error; }
/** * @private **/ FF_T_SINT32 FF_getFatEntry(FF_IOMAN *pIoman, FF_T_UINT32 nCluster) { FF_BUFFER *pBuffer; FF_T_UINT32 FatOffset; FF_T_UINT32 FatSector; FF_T_UINT32 FatSectorEntry; FF_T_UINT32 FatEntry; FF_T_UINT8 LBAadjust; FF_T_UINT16 relClusterEntry; #ifdef FF_FAT12_SUPPORT FF_T_UINT8 F12short[2]; // For FAT12 FAT Table Across sector boundary traversal. #endif if(pIoman->pPartition->Type == FF_T_FAT32) { FatOffset = nCluster * 4; } else if(pIoman->pPartition->Type == FF_T_FAT16) { FatOffset = nCluster * 2; }else { FatOffset = nCluster + (nCluster / 2); } FatSector = pIoman->pPartition->FatBeginLBA + (FatOffset / pIoman->pPartition->BlkSize); FatSectorEntry = FatOffset % pIoman->pPartition->BlkSize; LBAadjust = (FF_T_UINT8) (FatSectorEntry / pIoman->BlkSize); relClusterEntry = (FF_T_UINT32) (FatSectorEntry % pIoman->BlkSize); FatSector = FF_getRealLBA(pIoman, FatSector); #ifdef FF_FAT12_SUPPORT if(pIoman->pPartition->Type == FF_T_FAT12) { if(relClusterEntry == (FF_T_UINT32)(pIoman->BlkSize - 1)) { // Fat Entry SPANS a Sector! // First Buffer get the last Byte in buffer (first byte of our address)! pBuffer = FF_GetBuffer(pIoman, FatSector + LBAadjust, FF_MODE_READ); { if(!pBuffer) { return FF_ERR_DEVICE_DRIVER_FAILED; } F12short[0] = FF_getChar(pBuffer->pBuffer, (FF_T_UINT16)(pIoman->BlkSize - 1)); } FF_ReleaseBuffer(pIoman, pBuffer); // Second Buffer get the first Byte in buffer (second byte of out address)! pBuffer = FF_GetBuffer(pIoman, FatSector + LBAadjust + 1, FF_MODE_READ); { if(!pBuffer) { return FF_ERR_DEVICE_DRIVER_FAILED; } F12short[1] = FF_getChar(pBuffer->pBuffer, 0); } FF_ReleaseBuffer(pIoman, pBuffer); FatEntry = (FF_T_UINT32) FF_getShort((FF_T_UINT8*)&F12short, 0); // Guarantee correct Endianess! if(nCluster & 0x0001) { FatEntry = FatEntry >> 4; } FatEntry &= 0x0FFF; return (FF_T_SINT32) FatEntry; }