今天FAT文件系统总算告一个段落了,已经可以非常完美的读取包含FAT16文件系统的磁盘了。由于是采用C#编写,直接借鉴的代码很少,并且考虑到MF不支持二进制序列化,所以对数据结构的解析,是一个一个字节进行的,所以很耗费时间。下面就是程序运行后的结果(可以识别物理磁盘及物理磁盘的分区)。

 

FAT16文件系统解析(C#版本)_第1张图片

下图是用文件浏览器查看的结果。

 

FAT16文件系统解析(C#版本)_第2张图片

磁盘系统的MDR和DBR信息如下。

 

FAT16文件系统解析(C#版本)_第3张图片

为了便于后来者,把主要的结构声明代码罗列如下,希望有借鉴意义。
 

   
   
   
   
  1. //基本类 [叶帆工作室]   
  2. public class DiskBase  
  3. {  
  4.     #region //MBR   
  5.     public struct PartitionTable  
  6.     {  
  7.         public byte BootFlag;            //分区活动标志 只能选00H和80H。80H为活动,00H为非活动  
  8.         public CHS StartCHS;             //分区开始的柱面、磁头、扇区    
  9.         public byte SystemID;            //分区类型  01 FAT32  04 FAT16<32M  06 FAT16 07 HPFS/NTFS  05 0F 扩展分区  
  10.         public CHS EndCHS;               //分区结束的柱面、磁头、扇区    
  11.         public UInt32 RelativeSectors;   //分区起始扇区数,指分区相对于记录该分区的分区表的扇区位置之差 (该分区表:LBA=0x0)。   
  12.         public UInt32 TotalSectors;      //分区总扇区数   
  13.     }  
  14.     public struct CHS  
  15.     {  
  16.         public byte Head;                //磁头  
  17.         public byte Sector;              //扇区 六位  
  18.         public UInt16 Cylinder;          //柱面 十位  
  19.     }  
  20.     public struct MBR  
  21.     {  
  22.         public byte[] bytBootCode;       //ofs:0.引导代码446字节 "FA 33 C0 8E D0 BC…"  
  23.         public PartitionTable[] PT;      //ofs:446.64个字节 分区表 length=4*16  
  24.         public UInt16 EndingFlag;        //ofs:510.结束标识:0xAA55。  
  25.  
  26.         public MBR(byte[] bytData)  
  27.         {  
  28.             int i;  
  29.             bytBootCode = new byte[446];  
  30.             for (i = 0; i < 446; i++) bytBootCode[i] = bytData[i];  
  31.  
  32.             PT = new PartitionTable[4];  
  33.             for (i = 0; i < 4; i++)  
  34.             {  
  35.                 PT[i].BootFlag = bytData[446 + i * 16 + 0];  
  36.                 PT[i].StartCHS.Head = bytData[446 + i * 16 + 1];  
  37.                 PT[i].StartCHS.Sector = (byte)(bytData[446 + i * 16 + 2] & 0x3f);  
  38.                 PT[i].StartCHS.Cylinder = (UInt16)(((bytData[446 + i * 16 + 2] & 0xc0) << 2) | bytData[446 + i * 16 + 3]);  
  39.                 PT[i].SystemID = bytData[446 + i * 16 + 4];  
  40.                 PT[i].EndCHS.Head = bytData[446 + i * 16 + 5];  
  41.                 PT[i].EndCHS.Sector = (byte)(bytData[446 + i * 16 + 6] & 0x3f);  
  42.                 PT[i].EndCHS.Cylinder = (UInt16)(((bytData[446 + i * 16 + 6] & 0xc0) << 2) | bytData[446 + i * 16 + 7]);  
  43.                 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]);  
  44.                 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]);  
  45.             }  
  46.             EndingFlag = (UInt16)(bytData[510] << 8 | bytData[511]);  
  47.         }  
  48.  
  49.     #endregion          
  50.  
  51.     #region //DBR  http://yfsoft.blog.51cto.com  
  52.     //系统引导记录(兼容FAT16和FAT32)  
  53.     public struct DBR  
  54.     {  
  55.         public byte[] BS_JmpBoot;            //ofs:0.典型的如:0xEB,0x3E,0x90。  
  56.         public byte[] BS_OEMName;            //ofs:3.典型的如:“MSWIN4.1”。   
  57.         public UInt16 BPB_BytsPerSec;        //ofs:11.每扇区字节数。   
  58.         public byte BPB_SecPerClus;          //ofs:13.每簇扇区数。   
  59.         public UInt16 BPB_RsvdSecCnt;        //ofs:14.保留扇区数,从 DBR到 FAT的扇区数。  
  60.         public byte BPB_NumFATs;             //ofs:16.FAT的个数。   
  61.         public UInt16 BPB_RootEntCnt;        //ofs:17.根目录项数。   
  62.         public UInt16 BPB_TotSec16;          //ofs:19.分区总扇区数(<32M时用)。   
  63.         public byte BPB_Media;               //ofs:21.分区介质标识,优盘一般用 0xF8。   
  64.         public UInt16 BPB_FATSz16;           //ofs:22.每个 FAT占的扇区数。   
  65.         public UInt16 BPB_SecPerTrk;         //ofs:24.每道扇区数。   
  66.         public UInt16 BPB_NumHeads;          //ofs:26.磁头数。   
  67.         public UInt32 BPB_HiddSec;           //ofs:28.隐藏扇区数,从 MBR到 DBR的扇区数。   
  68.         public UInt32 BPB_TotSec32;          //ofs:32.分区总扇区数(>=32M时用)。  
  69.  
  70.         //---------------------  
  71.         //FAT32特有  
  72.         public UInt32 BPB_FATSz32;          //ofs:36.每个 FAT占的扇区数。  
  73.         public UInt16 BPB_ExtFlags;         //ofs:40.FAT标志  
  74.         public UInt16 BPB_FSVer;            //ofs:42.版本号 高字节主版本 低字节次版本号  
  75.         public UInt32 BPB_RootClus;         //ofs:44.根目录所在第一个簇的簇号,通常该数值为2,但不是必须为2。  
  76.         public UInt16 BPB_FSInfo;           //ofs:48.保留区中FAT32 卷FSINFO 结构所占的扇区数,通常为1。  
  77.         public UInt16 BPB_BkBootSec;        //ofs:50.如果不为0,表示在保留区中引导记录的备份数据所占的扇区数,通常为6。同时不建议使用6 以外的其他数值。  
  78.         [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]  
  79.         public byte[] BPB_Reserved;         //ofs:52.备用       
  80.  
  81.         //---------------------  
  82.         public byte BS_drvNum;              //ofs:64/36.软盘使用 0x00,硬盘使用 0x80。   
  83.         public byte BS_Reserved1;           //ofs:65/37.保留。   
  84.         public byte BS_BootSig;             //ofs:66/38.扩展引导标记:0x29。   
  85.         public byte[] BS_VolID;             //ofs:67/39.盘序列号。  
  86.         public byte[] BS_VolLab;            //ofs:71/43.“Msdos      ”。   
  87.         public byte[] BS_FilSysType;        //ofs:82/54.“FAT32   ”。   
  88.         public byte[] ExecutableCode;       //ofs:90/62.引导代码。   
  89.         public UInt16 EndingFlag;           //ofs:510.结束标识:0xAA55。  
  90.  
  91.         //---------------------  
  92.         //0-未知 1-FAT12 2-FAT16 3-FAT32 其它值为未知  
  93.         public byte FATType;  
  94.  
  95.         //获取信息  
  96.         public DBR(byte[] bytData)  
  97.         {  
  98.             FATType = IsType(bytData);  
  99.             int i;  
  100.             BS_JmpBoot = new byte[3];  
  101.             for (i = 0; i < 2; i++) BS_JmpBoot[i] = bytData[i];  
  102.             BS_OEMName = new byte[8];  
  103.             for (i = 0; i < 8; i++) BS_OEMName[i] = bytData[i + 3];  
  104.             BPB_BytsPerSec = (UInt16)(bytData[12] << 8 | bytData[11]);  
  105.             BPB_SecPerClus = bytData[13];  
  106.             BPB_RsvdSecCnt = (UInt16)(bytData[15] << 8 | bytData[14]);  
  107.             BPB_NumFATs = bytData[16];  
  108.             BPB_RootEntCnt = (UInt16)(bytData[18] << 8 | bytData[17]);  
  109.             BPB_TotSec16 = (UInt16)(bytData[20] << 8 | bytData[19]);  
  110.             BPB_Media = bytData[21];  
  111.             BPB_FATSz16 = (UInt16)(bytData[23] << 8 | bytData[22]);  
  112.             BPB_SecPerTrk = (UInt16)(bytData[25] << 8 | bytData[24]);  
  113.             BPB_NumHeads = (UInt16)(bytData[27] << 8 | bytData[26]);  
  114.             BPB_HiddSec = (UInt32)(bytData[31] << 24 | bytData[30] << 16 | bytData[29] << 8 | bytData[28]);  
  115.             BPB_TotSec32 = (UInt32)(bytData[35] << 24 | bytData[34] << 16 | bytData[33] << 8 | bytData[32]);  
  116.             //----------  
  117.             if (FATType == 3)  
  118.             {  
  119.                 //FAT32  
  120.                 BPB_FATSz32 = (UInt32)(bytData[39] << 24 | bytData[38] << 16 | bytData[37] << 8 | bytData[36]);  
  121.                 BPB_ExtFlags = (UInt16)(bytData[41] << 8 | bytData[40]);  
  122.                 BPB_FSVer = (UInt16)(bytData[43] << 8 | bytData[42]);  
  123.                 BPB_RootClus = (UInt32)(bytData[47] << 24 | bytData[46] << 16 | bytData[45] << 8 | bytData[44]);  
  124.                 BPB_FSInfo = (UInt16)(bytData[49] << 8 | bytData[48]);  
  125.                 BPB_BkBootSec = (UInt16)(bytData[51] << 8 | bytData[50]);  
  126.                 BPB_Reserved = new byte[12];  
  127.                 for (i = 0; i < 12; i++) BPB_Reserved[i] = bytData[i + 52];  
  128.                 //----------  
  129.                 BS_drvNum = bytData[64];  
  130.                 BS_Reserved1 = bytData[65];  
  131.                 BS_BootSig = bytData[66];  
  132.                 BS_VolID = new byte[4];  
  133.                 for (i = 0; i < 4; i++) BS_VolID[i] = bytData[67 + i];  
  134.                 BS_VolLab = new byte[11];  
  135.                 for (i = 0; i < 11; i++) BS_VolLab[i] = bytData[71 + i];  
  136.                 BS_FilSysType = new byte[8];  
  137.                 for (i = 0; i < 8; i++) BS_FilSysType[i] = bytData[82 + i];  
  138.                 ExecutableCode = new byte[420];  
  139.                 for (i = 0; i < 420; i++) ExecutableCode[i] = bytData[90 + i];  
  140.             }  
  141.             else 
  142.             {  
  143.                 //FAT16  
  144.                 BS_drvNum = bytData[36];  
  145.                 BS_Reserved1 = bytData[37];  
  146.                 BS_BootSig = bytData[38];  
  147.                 BS_VolID = new byte[4];  
  148.                 for (i = 0; i < 4; i++) BS_VolID[i] = bytData[39 + i];  
  149.                 BS_VolLab = new byte[11];  
  150.                 for (i = 0; i < 11; i++) BS_VolLab[i] = bytData[43 + i];  
  151.                 BS_FilSysType = new byte[8];  
  152.                 for (i = 0; i < 8; i++) BS_FilSysType[i] = bytData[54 + i];  
  153.                 ExecutableCode = new byte[448];  
  154.                 for (i = 0; i < 448; i++) ExecutableCode[i] = bytData[62 + i];  
  155.  
  156.                 //FAT32  
  157.                 BPB_FATSz32 = 0;  
  158.                 BPB_ExtFlags = 0;  
  159.                 BPB_FSVer = 0;  
  160.                 BPB_RootClus = 0;  
  161.                 BPB_FSInfo = 0;  
  162.                 BPB_BkBootSec = 0;  
  163.                 BPB_Reserved = new byte[12];  
  164.             }  
  165.             //----------  
  166.             EndingFlag = (UInt16)(bytData[510] << 8 | bytData[511]);  
  167.         }  
  168.     #endregion  
  169.  
  170.     //文件系统判断(采用微软的判断方法)          
  171.     public static byte IsType(byte[] bytData)  
  172.     {  
  173.         //不是合法BPB扇区数据  
  174.         if (bytData[510] != 0x55 || bytData[511] != 0xaa) return 0;  
  175.  
  176.         //跳转指令不合法  
  177.         if (bytData[0] != 0xeb && bytData[0] != 0xe9) return 0;  
  178.  
  179.         //每扇区包含的字节数(一般为512个字节)  
  180.         UInt16 BPB_BytsPerSec = (UInt16)(bytData[12] << 8 | bytData[11]);  
  181.  
  182.         //仅处理512个字节的扇区  
  183.         if (BPB_BytsPerSec != 512) return 0;  
  184.  
  185.         //每簇扇区数  
  186.         byte BPB_SecPerClus = bytData[13];  
  187.         //保留扇区数  
  188.         UInt16 BPB_RsvdSecCnt = (UInt16)(bytData[15] << 8 | bytData[14]);  
  189.         //FAT表的个数  
  190.         byte BPB_NumFATs = bytData[16];  
  191.  
  192.         //FAT表的个数必须为2  
  193.         if (BPB_NumFATs != 2) return 0;  
  194.  
  195.         //根目录项数(32字节为单位)  
  196.         UInt16 BPB_RootEntCnt = (UInt16)(bytData[18] << 8 | bytData[17]);  
  197.         //分区总扇区数(<32M时用)  
  198.         UInt16 BPB_TotSec16 = (UInt16)(bytData[20] << 8 | bytData[19]);  
  199.         //每个FAT占的扇区数  
  200.         UInt16 BPB_FATSz16 = (UInt16)(bytData[23] << 8 | bytData[22]);  
  201.         //分区总扇区数(>=32M时用)  
  202.         UInt32 BPB_TotSec32 = (UInt32)(bytData[35] << 24 | bytData[34] << 16 | bytData[33] << 8 | bytData[32]);  
  203.         //每个FAT占的扇区数(FAT32)  
  204.         UInt32 BPB_FATSz32 = (UInt32)(bytData[39] << 24 | bytData[38] << 16 | bytData[37] << 8 | bytData[36]);  
  205.  
  206.         UInt64 FATSz = 0, TotSec = 0, DataSec = 0;  
  207.         UInt64 RootDirSectors = (UInt64)(((BPB_RootEntCnt * 32) + (BPB_BytsPerSec - 1)) / BPB_BytsPerSec);  
  208.  
  209.         if (BPB_FATSz16 != 0)  
  210.             FATSz = BPB_FATSz16;  
  211.         else 
  212.             FATSz = BPB_FATSz32;  
  213.  
  214.         if (BPB_TotSec16 != 0)  
  215.             TotSec = BPB_TotSec16;  
  216.         else 
  217.             TotSec = BPB_TotSec32;  
  218.  
  219.         DataSec = TotSec - (BPB_RsvdSecCnt + (BPB_NumFATs * FATSz) + RootDirSectors);  
  220.         UInt64 CountofClusters = DataSec / BPB_SecPerClus;  
  221.         if (CountofClusters < 4085)  
  222.         {  
  223.             /* FAT 类型是FAT12 */ 
  224.             return 1;  
  225.         }  
  226.         else if (CountofClusters < 65525)  
  227.         {  
  228.             /* FAT 类型是FAT16 */ 
  229.             return 2;  
  230.         }  
  231.         else 
  232.         {  
  233.             /* FAT 类型是FAT32*/ 
  234.             return 3;  
  235.         }  
  236.     }             
  237. }  
  238.