FAT16文件系统解析(C 版本)

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow

也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

               

 

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

        
// 跳转指令不合法
         if  (bytData[ 0 !=   0xeb   &&  bytData[ 0 !=   0xe9 return   0 ;

        
// 每扇区包含的字节数(一般为512个字节)
        UInt16 BPB_BytsPerSec  =  (UInt16)(bytData[ 12 <<   8   |  bytData[ 11 ]);

        
// 仅处理512个字节的扇区
         if  (BPB_BytsPerSec  !=   512 return   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  !=   2 return   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 

猜你喜欢

转载自blog.csdn.net/gfuugfd/article/details/83927147