fat.c

来自「老外的一个开源项目」· C语言 代码 · 共 1,460 行 · 第 1/4 页

C
1,460
字号
        if(drEntry.FileName[0] == DIRENTRY_NEVERUSED){
            break; // no used entry, exit
        }
        // compare filename, if match update ppCurItem to next
        if(CompareFileName(drEntry.FileName, ppCurItem)){
            // update pFileInfo to new entry
			InitFileInfo(pFileInfo, pFileInfo->PartitionNumber,
                drEntry.StartingCluster, drEntry.FileLength, drEntry.Attribute);
            return TRUE;
        }
    }
    return FALSE;
}


// help routine for initialization
static DWORD GetDefaultSectorSize(){
    return DEFAULT_SECTOR_SIZE;
}

static BOOL InitPartition(BOOL fBootable, DWORD dwFileSystem, DWORD dwStart, DWORD dwLength){
    DWORD dwFileType;
    DWORD dwFATSectors, dwTotalSectors;
    DWORD dwRootStart, dwRootSectors, dwRootLength;
    DWORD dwDataStart, dwDataSectors, dwDataClusters;
    UINT8 buf[DEFAULT_SECTOR_SIZE];
    PRAWPARTITION pPart = (PRAWPARTITION)buf;

	// we just support 26 partition
    if(PartitionNumber >= MAX_PARTITION){
        return FALSE;
    }
    // read first sector
    if(FATReadDisk(pPart, sizeof(*pPart), dwStart) != sizeof(*pPart)){
        return FALSE;
    }
    // check field
    if(pPart->SectorSize == 0){
        return FALSE;
    }
    if(pPart->SectorPerCluster == 0){
        return FALSE;
    }
    if(pPart->ReservedSector == 0){
        return FALSE;
    }
    if(pPart->NumberOfFAT == 0){
        return FALSE;
    }
    if(pPart->NumberOfRootEntry==0 && pPart->FAT32.RootEntryCluster==0){
        return FALSE;
    }
    if(pPart->TotalSector != 0){
        if(pPart->TotalSector2 != 0){
            return FALSE;
        }
    }
    else if(pPart->TotalSector2 == 0){
        return FALSE;
    }
    if(pPart->SectorPerFAT==0 && pPart->FAT32.SectorPerFAT==0){
        return FALSE;
    }
    if(pPart->EFDCSignature!=RAWPARTITION_EFDCSIGNATURE &&
       pPart->FAT32.EFDCSignature!=RAWPARTITION_EFDCSIGNATURE){
        return FALSE;
    }
    if(pPart->Signature != RAWPARTITION_SIGNATURE){
        return FALSE;
    }
    // determine FAT type
    if(pPart->SectorPerFAT){
        dwFATSectors = pPart->NumberOfFAT*pPart->SectorPerFAT;
    }
    else{
        dwFATSectors = pPart->NumberOfFAT*pPart->FAT32.SectorPerFAT;
    }
    if(pPart->TotalSector){
        dwTotalSectors = pPart->TotalSector;
    }
    else{
        dwTotalSectors = pPart->TotalSector2;
    }
    dwRootStart    = pPart->SectorSize*(pPart->ReservedSector+dwFATSectors);
    dwRootLength   = 32*pPart->NumberOfRootEntry;
    dwRootSectors  = (dwRootLength+pPart->SectorSize-1)/pPart->SectorSize;
    dwDataStart    = dwRootStart+pPart->SectorSize*dwRootSectors;
    dwDataSectors  = dwTotalSectors-pPart->ReservedSector-dwFATSectors-dwRootSectors;
    dwDataClusters = dwDataSectors/pPart->SectorPerCluster;
    if(dwDataClusters < 4085){
        dwFileType = PART_FAT12;
    }
    else if(dwDataClusters < 65525){
        dwFileType = PART_FAT16;
    }
    else{
        dwFileType = PART_FAT32;
        dwRootStart = pPart->FAT32.RootEntryCluster;
    }
    // check consistent
    if(dwFileSystem != dwFileType){
        if(dwFileSystem != PART_UNKNOWN){
            return FALSE;
        }
    }
    // validated FAT, update global state
    Partition[PartitionNumber].Bootable          = fBootable;
    Partition[PartitionNumber].FileSystem        = dwFileType;
    Partition[PartitionNumber].StartingPartition = dwStart;
    Partition[PartitionNumber].PartitionLength   = dwLength;
    Partition[PartitionNumber].StartingFATEntry  = pPart->SectorSize*pPart->ReservedSector;
    Partition[PartitionNumber].FATEntryNumber    = dwDataClusters+2; // +2 for format identifier
    Partition[PartitionNumber].StartingRootEntry = dwRootStart;
    Partition[PartitionNumber].RootEntryLength   = dwRootLength;
    Partition[PartitionNumber].StartingCluster   = dwDataStart;
    Partition[PartitionNumber].LengthPerCluster  = pPart->SectorSize*pPart->SectorPerCluster;
    memcpy(&RawPartition[PartitionNumber++], pPart, sizeof(*pPart));
    return TRUE;
}

static BOOL InitMasterBootRecord(DWORD dwStart, DWORD dwLength){
    int i, j;
    BOOL fBootable;
    UINT8 buf[DEFAULT_SECTOR_SIZE];
    PARTITION_TABLE EmptyPart = {0}; // all zero
    PPARTITION_TABLE pPart1, pPart2;
    DWORD dwPartStart, dwPartLength;
    PMASTERBOOT_RECORD pMBR = (PMASTERBOOT_RECORD)buf;
    // we just support 26 MBR
    if(MasterBootRecordNumber >= MAX_PARTITION){
        return FALSE;
    }
    // read first sector
    if(FATReadDisk(pMBR, sizeof(*pMBR), dwStart) != sizeof(*pMBR)){
        return FALSE;
    }
    // check signature
    if(pMBR->Signature != MASTERBOOT_SIGNATURE){
        return FALSE;
    }
    // check partition table
    for(i = 0; i < PARTITION_NUMBER; ++i){
        pPart1 = &pMBR->Partition[i];
        // check empty partition
        if(pPart1->SystemId == PARTITION_EMPTY){
            if(memcmp(pPart1, &EmptyPart, sizeof(EmptyPart)) != 0){
                return FALSE; // empty partition should be all zero
            }
            continue; // skip follow check
        }
        // check boot indicator
        if(pPart1->BootIndicator!=PARTITION_NORMAL && pPart1->BootIndicator!=PARTITION_SYSTEM){
            return FALSE;
        }
        // check header(0-254)
        if(pPart1->StartingHead==0xFF || pPart1->EndingHead==0xFF){
            return FALSE;
        }
        // check sector(1-63)
        if(pPart1->StartingSector==0 || pPart1->EndingSector==0){
            return FALSE;
        }
        // check start&length
        dwPartStart = pPart1->RelativeSector*GetDefaultSectorSize();
        dwPartLength = pPart1->TotalSector*GetDefaultSectorSize();
        if(dwPartStart >= dwLength){
            return FALSE;
        }
        if(dwPartLength==0 || dwPartStart+dwPartLength>dwLength){
            return FALSE;
        }
        // check overlap
        for(j = i+1; j < PARTITION_NUMBER; ++j){
            pPart2 = &pMBR->Partition[j];
            // skip empty
            if(pPart2->SystemId == PARTITION_EMPTY){
                continue;
            }
            // check start point
            if(pPart2->RelativeSector>=pPart1->RelativeSector &&
               pPart2->RelativeSector<pPart1->RelativeSector+pPart1->TotalSector){
                return FALSE;
            }
            // check end point
            if(pPart2->RelativeSector+pPart2->TotalSector>pPart1->RelativeSector &&
               pPart2->RelativeSector+pPart2->TotalSector<=pPart1->RelativeSector+pPart1->TotalSector){
               return FALSE;
            }
        }
    }
    // validated MBR, copy it!
    memcpy(&MasterBootRecord[MasterBootRecordNumber++], pMBR, sizeof(*pMBR));
    // init individual partition 
    for(i = 0; i < PARTITION_NUMBER; ++i){
        pPart1 = &pMBR->Partition[i];
        fBootable = (pPart1->BootIndicator==PARTITION_SYSTEM);
        dwPartStart = dwStart + GetDefaultSectorSize()*pPart1->RelativeSector;
        dwPartLength = GetDefaultSectorSize()*pPart1->TotalSector;
        switch(pPart1->SystemId){
        case PARTITION_FAT12: // FAT12
            InitPartition(fBootable, PART_FAT12, dwPartStart, dwPartLength);
            break;
        case PARTITION_FAT16: // FAT16
        case PARTITION_FAT16B:
        case PARTITION_FAT16L:
            InitPartition(fBootable, PART_FAT16, dwPartStart, dwPartLength);
            break;
        case PARTITION_FAT32: // FAT32
        case PARTITION_FAT32L:
            InitPartition(fBootable, PART_FAT32, dwPartStart, dwPartLength);
            break;
        case PARTITION_EXT:   // Extend
        case PARTITION_EXTL:
            InitMasterBootRecord(dwPartStart, dwPartLength); // recursion!
            break;
        case PARTITION_EMPTY:
            break; // no action
        default:
            //InitPartition(PART_UNKNOWN, dwPartStart, dwPartLength); // try it?
            break;
        }
    }
    return TRUE;
}


// disk function
BOOL FATInitDisk(){
    // try to init MBR
    if(InitMasterBootRecord(0, FATGetDiskSize())){
        return TRUE;
    }
    // no MBR, try to init partition
    if(InitPartition(TRUE, PART_UNKNOWN, 0, FATGetDiskSize())){
        return TRUE;
    }
    // no FAT partition, fail!
    return FALSE;
}

DWORD FATGetDiskSize(){
    return 0xFFFFFFFF; // TODO: get from SD Card
}


DWORD FATReadDisk(PVOID pBuffer, DWORD dwLength, DWORD dwAddress)
{
	// cache for speed up
	static DWORD CacheAddress = -1;
	static BYTE  CacheBuffer[DEFAULT_SECTOR_SIZE];
	DWORD dwBytesRead;


	// parameter check
    if(dwAddress >= FATGetDiskSize())
	{
        return 0;
    }
    // adjust dwLength if need
    if(dwAddress+dwLength > FATGetDiskSize()){
        dwLength = FATGetDiskSize()-dwAddress;
    }
	
	dwBytesRead = dwLength;

	while(dwLength){
		// 1. check cache hit
		if(dwAddress>=CacheAddress && dwAddress<CacheAddress+DEFAULT_SECTOR_SIZE)
		{
			DWORD dwOffset  = dwAddress-CacheAddress;
			DWORD dwCopyLen = DEFAULT_SECTOR_SIZE-dwOffset;
			if(dwLength > dwCopyLen)
			{
				memcpy(pBuffer, CacheBuffer+dwOffset, dwCopyLen);
				(PBYTE)pBuffer   += dwCopyLen;
				dwAddress        += dwCopyLen;
				dwLength         -= dwCopyLen;
			}
			else
			{
				memcpy(pBuffer, CacheBuffer+dwOffset, dwLength);
				break;
			}
		}

		if(dwLength<=DEFAULT_SECTOR_SIZE || dwAddress%DEFAULT_SECTOR_SIZE)
		{
			// fill cache in following condition:
			// 1.read buffer less than one block length
			// 2.address doesn't align on block length
			if (ReadSectors((dwAddress&BLOCK_MASK)/DEFAULT_SECTOR_SIZE, 1, CacheBuffer))
			{
				return FAT_ERROR;
			}
			CacheAddress = dwAddress&BLOCK_MASK; // update cache start address
		}
		else
		{
			// directly read if space is enough and address is alignment
			if (!ReadSectors((dwAddress&BLOCK_MASK)/DEFAULT_SECTOR_SIZE, 1, pBuffer))
			{
				(PBYTE)pBuffer   += DEFAULT_SECTOR_SIZE;
				dwAddress        += DEFAULT_SECTOR_SIZE;
				dwLength         -= DEFAULT_SECTOR_SIZE;
			}
			else
			{
				return FAT_ERROR;
			}
		}
	}

    return dwBytesRead;
}


// partition function
DWORD FATGetPartitionNumber(){
    return PartitionNumber;
}

DWORD FATGetPartitionSize(DWORD dwPartNo){
    return dwPartNo<PartitionNumber?Partition[dwPartNo].PartitionLength:FAT_ERROR;
}

DWORD FATReadPartition(DWORD dwPartNo, PVOID pBuffer, DWORD dwLength, DWORD dwPos){
    // parameter check
    if(dwPartNo >= PartitionNumber){
        return FAT_ERROR;
    }
    if(dwPos >= Partition[dwPartNo].PartitionLength){
        return 0;
    }
    // adjust dwLength if need
    if(dwPos+dwLength > Partition[dwPartNo].PartitionLength){
        dwLength = Partition[dwPartNo].PartitionLength-dwPos;
    }
    return FATReadDisk(pBuffer, dwLength, Partition[dwPartNo].StartingPartition+dwPos);
}


// file function
BOOL FATOpenFile(PFILEINFO pFileInfo, PCSTR pFileName){
    FILEINFO fnFileInfo;
    // invalid pFileInfo
    ClearFileInfo(pFileInfo);
    // find root directory
    if(!FindRootDirEntry(&fnFileInfo, &pFileName)){
        return FALSE;
    }

	// find each directory and last file
    while(*pFileName){
        if(!FATIsDirectory(&fnFileInfo)){ // not directory
            return FALSE;
        }
        if(!FindNextDirEntry(&fnFileInfo, &pFileName)){
            return FALSE;
        }
    }
    // copy it
    memcpy(pFileInfo, &fnFileInfo, sizeof(*pFileInfo));
    return TRUE;
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?