FAT16文件系統解析(C#版本)

 
下圖是用文件瀏覽器查看的結果。
磁盤系統的MDR和DBR信息如下。
爲了便於後來者,把主要的結構聲明代碼羅列如下,希望有借鑑意義。
//基本類 [葉帆工作室] http://blog.csdn.net/yefanqiu/
public class DiskBase
{
    
#region //MBR http://blog.csdn.net/yefanqiu/
    
public struct PartitionTable
    {
        
public byte BootFlag;            //分區活動標誌 只能選00H和80H。80H爲活動,00H爲非活動
        public CHS StartCHS;             //分區開始的柱面、磁頭、扇區  
        public byte SystemID;            //分區類型  01 FAT32  04 FAT16<32M  06 FAT16 07 HPFS/NTFS  05 0F 擴展分區
        public CHS EndCHS;               //分區結束的柱面、磁頭、扇區  
        public UInt32 RelativeSectors;   //分區起始扇區數,指分區相對於記錄該分區的分區表的扇區位置之差 (該分區表:LBA=0x0)。 
        public UInt32 TotalSectors;      //分區總扇區數 
    }
    
public struct CHS
    {
        
public byte Head;                //磁頭
        public byte Sector;              //扇區 六位
        public UInt16 Cylinder;          //柱面 十位
    }
    
public struct MBR
    {
        
public byte[] bytBootCode;       //ofs:0.引導代碼446字節 "FA 33 C0 8E D0 BC…"
        public PartitionTable[] PT;      //ofs:446.64個字節 分區表 length=4*16
        public UInt16 EndingFlag;        //ofs:510.結束標識:0xAA55。

        
public MBR(byte[] bytData)
        {
            
int i;
            bytBootCode 
= new byte[446];
            
for (i = 0; i < 446; i++) bytBootCode[i] = bytData[i];

            PT 
= new PartitionTable[4];
            
for (i = 0; i < 4; i++)
            {
                PT[i].BootFlag 
= bytData[446 + i * 16 + 0];
                PT[i].StartCHS.Head 
= bytData[446 + i * 16 + 1];
                PT[i].StartCHS.Sector 
= (byte)(bytData[446 + i * 16 + 2& 0x3f);
                PT[i].StartCHS.Cylinder 
= (UInt16)(((bytData[446 + i * 16 + 2& 0xc0<< 2| bytData[446 + i * 16 + 3]);
                PT[i].SystemID 
= bytData[446 + i * 16 + 4];
                PT[i].EndCHS.Head 
= bytData[446 + i * 16 + 5];
                PT[i].EndCHS.Sector 
= (byte)(bytData[446 + i * 16 + 6& 0x3f);
                PT[i].EndCHS.Cylinder 
= (UInt16)(((bytData[446 + i * 16 + 6& 0xc0<< 2| bytData[446 + i * 16 + 7]);
                PT[i].RelativeSectors 
= (UInt32)(bytData[446 + i * 16 + 11<< 24 | bytData[446 + i * 16 + 10<< 16 | bytData[446 + i * 16 + 9<< 8 | bytData[446 + i * 16 + 8]);
                PT[i].TotalSectors 
= (UInt32)(bytData[446 + i * 16 + 15<< 24 | bytData[446 + i * 16 + 14<< 16 | bytData[446 + i * 16 + 13<< 8 | bytData[446 + i * 16 + 12]);
            }
            EndingFlag 
= (UInt16)(bytData[510<< 8 | bytData[511]);
        }

    
#endregion        

    
#region //DBR  http://blog.csdn.net/yefanqiu/
    
//系統引導記錄(兼容FAT16和FAT32)
    public struct DBR
    {
        
public byte[] BS_JmpBoot;            //ofs:0.典型的如:0xEB,0x3E,0x90。
        public byte[] BS_OEMName;            //ofs:3.典型的如:“MSWIN4.1”。 
        public UInt16 BPB_BytsPerSec;        //ofs:11.每扇區字節數。 
        public byte BPB_SecPerClus;          //ofs:13.每簇扇區數。 
        public UInt16 BPB_RsvdSecCnt;        //ofs:14.保留扇區數,從 DBR到 FAT的扇區數。
        public byte BPB_NumFATs;             //ofs:16.FAT的個數。 
        public UInt16 BPB_RootEntCnt;        //ofs:17.根目錄項數。 
        public UInt16 BPB_TotSec16;          //ofs:19.分區總扇區數(<32M時用)。 
        public byte BPB_Media;               //ofs:21.分區介質標識,優盤一般用 0xF8。 
        public UInt16 BPB_FATSz16;           //ofs:22.每個 FAT佔的扇區數。 
        public UInt16 BPB_SecPerTrk;         //ofs:24.每道扇區數。 
        public UInt16 BPB_NumHeads;          //ofs:26.磁頭數。 
        public UInt32 BPB_HiddSec;           //ofs:28.隱藏扇區數,從 MBR到 DBR的扇區數。 
        public UInt32 BPB_TotSec32;          //ofs:32.分區總扇區數(>=32M時用)。

        
//---------------------
        
//FAT32特有
        public UInt32 BPB_FATSz32;          //ofs:36.每個 FAT佔的扇區數。
        public UInt16 BPB_ExtFlags;         //ofs:40.FAT標誌
        public UInt16 BPB_FSVer;            //ofs:42.版本號 高字節主版本 低字節次版本號
        public UInt32 BPB_RootClus;         //ofs:44.根目錄所在第一個簇的簇號,通常該數值爲2,但不是必須爲2。
        public UInt16 BPB_FSInfo;           //ofs:48.保留區中FAT32 卷FSINFO 結構所佔的扇區數,通常爲1。
        public UInt16 BPB_BkBootSec;        //ofs:50.如果不爲0,表示在保留區中引導記錄的備份數據所佔的扇區數,通常爲6。同時不建議使用6 以外的其他數值。
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
        
public byte[] BPB_Reserved;         //ofs:52.備用     

        
//---------------------
        public byte BS_drvNum;              //ofs:64/36.軟盤使用 0x00,硬盤使用 0x80。 
        public byte BS_Reserved1;           //ofs:65/37.保留。 
        public byte BS_BootSig;             //ofs:66/38.擴展引導標記:0x29。 
        public byte[] BS_VolID;             //ofs:67/39.盤序列號。
        public byte[] BS_VolLab;            //ofs:71/43.“Msdos      ”。 
        public byte[] BS_FilSysType;        //ofs:82/54.“FAT32   ”。 
        public byte[] ExecutableCode;       //ofs:90/62.引導代碼。 
        public UInt16 EndingFlag;           //ofs:510.結束標識:0xAA55。

        
//---------------------
        
//0-未知 1-FAT12 2-FAT16 3-FAT32 其它值爲未知
        public byte FATType;

        
//獲取信息
        public DBR(byte[] bytData)
        {
            FATType 
= IsType(bytData);
            
int i;
            BS_JmpBoot 
= new byte[3];
            
for (i = 0; i < 2; i++) BS_JmpBoot[i] = bytData[i];
            BS_OEMName 
= new byte[8];
            
for (i = 0; i < 8; i++) BS_OEMName[i] = bytData[i + 3];
            BPB_BytsPerSec 
= (UInt16)(bytData[12<< 8 | bytData[11]);
            BPB_SecPerClus 
= bytData[13];
            BPB_RsvdSecCnt 
= (UInt16)(bytData[15<< 8 | bytData[14]);
            BPB_NumFATs 
= bytData[16];
            BPB_RootEntCnt 
= (UInt16)(bytData[18<< 8 | bytData[17]);
            BPB_TotSec16 
= (UInt16)(bytData[20<< 8 | bytData[19]);
            BPB_Media 
= bytData[21];
            BPB_FATSz16 
= (UInt16)(bytData[23<< 8 | bytData[22]);
            BPB_SecPerTrk 
= (UInt16)(bytData[25<< 8 | bytData[24]);
            BPB_NumHeads 
= (UInt16)(bytData[27<< 8 | bytData[26]);
            BPB_HiddSec 
= (UInt32)(bytData[31<< 24 | bytData[30<< 16 | bytData[29<< 8 | bytData[28]);
            BPB_TotSec32 
= (UInt32)(bytData[35<< 24 | bytData[34<< 16 | bytData[33<< 8 | bytData[32]);
            
//----------
            if (FATType == 3)
            {
                
//FAT32
                BPB_FATSz32 = (UInt32)(bytData[39<< 24 | bytData[38<< 16 | bytData[37<< 8 | bytData[36]);
                BPB_ExtFlags 
= (UInt16)(bytData[41<< 8 | bytData[40]);
                BPB_FSVer 
= (UInt16)(bytData[43<< 8 | bytData[42]);
                BPB_RootClus 
= (UInt32)(bytData[47<< 24 | bytData[46<< 16 | bytData[45<< 8 | bytData[44]);
                BPB_FSInfo 
= (UInt16)(bytData[49<< 8 | bytData[48]);
                BPB_BkBootSec 
= (UInt16)(bytData[51<< 8 | bytData[50]);
                BPB_Reserved 
= new byte[12];
                
for (i = 0; i < 12; i++) BPB_Reserved[i] = bytData[i + 52];
                
//----------
                BS_drvNum = bytData[64];
                BS_Reserved1 
= bytData[65];
                BS_BootSig 
= bytData[66];
                BS_VolID 
= new byte[4];
                
for (i = 0; i < 4; i++) BS_VolID[i] = bytData[67 + i];
                BS_VolLab 
= new byte[11];
                
for (i = 0; i < 11; i++) BS_VolLab[i] = bytData[71 + i];
                BS_FilSysType 
= new byte[8];
                
for (i = 0; i < 8; i++) BS_FilSysType[i] = bytData[82 + i];
                ExecutableCode 
= new byte[420];
                
for (i = 0; i < 420; i++) ExecutableCode[i] = bytData[90 + i];
            }
            
else
            {
                
//FAT16
                BS_drvNum = bytData[36];
                BS_Reserved1 
= bytData[37];
                BS_BootSig 
= bytData[38];
                BS_VolID 
= new byte[4];
                
for (i = 0; i < 4; i++) BS_VolID[i] = bytData[39 + i];
                BS_VolLab 
= new byte[11];
                
for (i = 0; i < 11; i++) BS_VolLab[i] = bytData[43 + i];
                BS_FilSysType 
= new byte[8];
                
for (i = 0; i < 8; i++) BS_FilSysType[i] = bytData[54 + i];
                ExecutableCode 
= new byte[448];
                
for (i = 0; i < 448; i++) ExecutableCode[i] = bytData[62 + i];

                
//FAT32
                BPB_FATSz32 = 0;
                BPB_ExtFlags 
= 0;
                BPB_FSVer 
= 0;
                BPB_RootClus 
= 0;
                BPB_FSInfo 
= 0;
                BPB_BkBootSec 
= 0;
                BPB_Reserved 
= new byte[12];
            }
            
//----------
            EndingFlag = (UInt16)(bytData[510<< 8 | bytData[511]);
        }
    
#endregion

    
//文件系統判斷(採用微軟的判斷方法)        
    public static byte IsType(byte[] bytData)
    {
        
//不是合法BPB扇區數據
        if (bytData[510!= 0x55 || bytData[511!= 0xaareturn 0;

        
//跳轉指令不合法
        if (bytData[0!= 0xeb && bytData[0!= 0xe9return 0;

        
//每扇區包含的字節數(一般爲512個字節)
        UInt16 BPB_BytsPerSec = (UInt16)(bytData[12<< 8 | bytData[11]);

        
//僅處理512個字節的扇區
        if (BPB_BytsPerSec != 512return 0;

        
//每簇扇區數
        byte BPB_SecPerClus = bytData[13];
        
//保留扇區數
        UInt16 BPB_RsvdSecCnt = (UInt16)(bytData[15<< 8 | bytData[14]);
        
//FAT表的個數
        byte BPB_NumFATs = bytData[16];

        
//FAT表的個數必須爲2
        if (BPB_NumFATs != 2return 0;

        
//根目錄項數(32字節爲單位)
        UInt16 BPB_RootEntCnt = (UInt16)(bytData[18<< 8 | bytData[17]);
        
//分區總扇區數(<32M時用)
        UInt16 BPB_TotSec16 = (UInt16)(bytData[20<< 8 | bytData[19]);
        
//每個FAT佔的扇區數
        UInt16 BPB_FATSz16 = (UInt16)(bytData[23<< 8 | bytData[22]);
        
//分區總扇區數(>=32M時用)
        UInt32 BPB_TotSec32 = (UInt32)(bytData[35<< 24 | bytData[34<< 16 | bytData[33<< 8 | bytData[32]);
        
//每個FAT佔的扇區數(FAT32)
        UInt32 BPB_FATSz32 = (UInt32)(bytData[39<< 24 | bytData[38<< 16 | bytData[37<< 8 | bytData[36]);

        UInt64 FATSz 
= 0, TotSec = 0, DataSec = 0;
        UInt64 RootDirSectors 
= (UInt64)(((BPB_RootEntCnt * 32+ (BPB_BytsPerSec - 1)) / BPB_BytsPerSec);

        
if (BPB_FATSz16 != 0)
            FATSz 
= BPB_FATSz16;
        
else
            FATSz 
= BPB_FATSz32;

        
if (BPB_TotSec16 != 0)
            TotSec 
= BPB_TotSec16;
        
else
            TotSec 
= BPB_TotSec32;

        DataSec 
= TotSec - (BPB_RsvdSecCnt + (BPB_NumFATs * FATSz) + RootDirSectors);
        UInt64 CountofClusters 
= DataSec / BPB_SecPerClus;
        
if (CountofClusters < 4085)
        {
            
/* FAT 類型是FAT12 */
            
return 1;
        }
        
else if (CountofClusters < 65525)
        {
            
/* FAT 類型是FAT16 */
            
return 2;
        }
        
else
        {
            
/* FAT 類型是FAT32*/
            
return 3;
        }
    }           
}
 今天FAT文件系統總算告一個段落了,已經可以非常完美的讀取包含FAT16文件系統的磁盤了。由於是採用C#編寫,直接借鑑的代碼很少,並且考慮到MF不支持二進制序列化,所以對數據結構的解析,是一個一個字節進行的,所以很耗費時間。下面就是程序運行後的結果(可以識別物理磁盤及物理磁盤的分區)。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章