static FF_T_SINT8 FF_PartitionCount (FF_T_UINT8 *pBuffer) { FF_T_SINT8 count = 0; FF_T_SINT8 part; // Check PBR or MBR signature if (FF_getChar(pBuffer, FF_FAT_MBR_SIGNATURE) != 0x55 && FF_getChar(pBuffer, FF_FAT_MBR_SIGNATURE) != 0xAA ) { // No MBR, but is it a PBR ? if (FF_getChar(pBuffer, 0) == 0xEB && // PBR Byte 0 FF_getChar(pBuffer, 2) == 0x90 && // PBR Byte 2 (FF_getChar(pBuffer, 21) & 0xF0) == 0xF0) {// PBR Byte 21 : Media byte return 1; // No MBR but PBR exist then only one partition } return 0; // No MBR and no PBR then no partition found } for (part = 0; part < 4; part++) { FF_T_UINT8 active = FF_getChar(pBuffer, FF_FAT_PTBL + FF_FAT_PTBL_ACTIVE + (16 * part)); FF_T_UINT8 part_id = FF_getChar(pBuffer, FF_FAT_PTBL + FF_FAT_PTBL_ID + (16 * part)); // The first sector must be a MBR, then check the partition entry in the MBR if (active != 0x80 && (active != 0 || part_id == 0)) { break; } count++; } return count; }
/** * @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; }
/** * @public * @brief Moves a file or directory from source to destination. * * @param pIoman The FF_IOMAN object pointer. * @param szSourceFile String of the source file to be moved or renamed. * @param szDestinationFile String of the destination file to where the source should be moved or renamed. * * @return FF_ERR_NONE on success. * @return FF_ERR_FILE_DESTINATION_EXISTS if the destination file exists. * @return FF_ERR_FILE_COULD_NOT_CREATE_DIRENT if dirent creation failed (fatal error!). * @return FF_ERR_FILE_DIR_NOT_FOUND if destination directory was not found. * @return FF_ERR_FILE_SOURCE_NOT_FOUND if the source file was not found. * **/ FF_ERROR FF_Move(FF_IOMAN *pIoman, const FF_T_INT8 *szSourceFile, const FF_T_INT8 *szDestinationFile) { FF_ERROR Error; FF_FILE *pSrcFile, *pDestFile; FF_DIRENT MyFile; FF_T_UINT8 EntryBuffer[32]; FF_T_UINT16 i; FF_T_UINT32 DirCluster; if(!pIoman) { return FF_ERR_NULL_POINTER; } // Check destination file doesn't exist! pDestFile = FF_Open(pIoman, szDestinationFile, FF_MODE_READ, &Error); if(pDestFile || (Error == FF_ERR_FILE_OBJECT_IS_A_DIR)) { FF_Close(pDestFile); return FF_ERR_FILE_DESTINATION_EXISTS; // YES -- FAIL } pSrcFile = FF_Open(pIoman, szSourceFile, FF_MODE_READ, &Error); if(Error == FF_ERR_FILE_OBJECT_IS_A_DIR) { // Open a directory for moving! pSrcFile = FF_Open(pIoman, szSourceFile, FF_MODE_DIR, &Error); } if(pSrcFile) { // Create the new dirent. FF_FetchEntry(pIoman, pSrcFile->DirCluster, pSrcFile->DirEntry, EntryBuffer); MyFile.Attrib = FF_getChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB)); MyFile.Filesize = pSrcFile->Filesize; MyFile.ObjectCluster = pSrcFile->ObjectCluster; MyFile.CurrentItem = 0; i = (FF_T_UINT16) strlen(szDestinationFile); while(i != 0) { if(szDestinationFile[i] == '\\' || szDestinationFile[i] == '/') { break; } i--; } strncpy(MyFile.FileName, (szDestinationFile + i + 1), FF_MAX_FILENAME); if(i == 0) { i = 1; } DirCluster = FF_FindDir(pIoman, szDestinationFile, i); if(DirCluster) { // Destination Dir was found, we can now create the new entry. if(FF_CreateDirent(pIoman, DirCluster, &MyFile)) { FF_Close(pSrcFile); return FF_ERR_FILE_COULD_NOT_CREATE_DIRENT; // FAILED } // Edit the Directory Entry! (So it appears as deleted); FF_lockDIR(pIoman); { FF_RmLFNs(pIoman, pSrcFile->DirCluster, pSrcFile->DirEntry); FF_FetchEntry(pIoman, pSrcFile->DirCluster, pSrcFile->DirEntry, EntryBuffer); EntryBuffer[0] = 0xE5; FF_PushEntry(pIoman, pSrcFile->DirCluster, pSrcFile->DirEntry, EntryBuffer); } FF_unlockDIR(pIoman); FF_Close(pSrcFile); FF_FlushCache(pIoman); return FF_ERR_NONE; } return FF_ERR_FILE_DIR_NOT_FOUND; } return FF_ERR_FILE_SOURCE_NOT_FOUND; // Source not found! }
/** * @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; }