zeerd's blog         Search     Categories     Tags     Feed

闲来生雅趣,无事乐逍遥。对窗相望雪,一盏茶香飘。

1.44MB 软盘镜像文件FDT/FAT简析

#Fat #FileSystem @OperatingSystem


准备:

  1. 一张干净的1.44MB软盘,使用windows98附带的Dos进行完全格式化;
  2. 使用sys命令向磁盘传送系统文件;
  3. 立刻将磁盘做成镜像(保证磁盘的“干净”)。

FAT12的结构网上有很多,这里不进行累述。 下面是针对镜像文件进行的数据分析(下面提到的地址范围只指用UE等打开之后看到的地址)。

0面0道第2扇区到第10扇区的9个扇区是FAT表的存放位置。

FAT地址范围:0x0200 ~ 0x13FF

0面0道的第11扇区到1面0道第1扇区的9个扇区是第2个FAT表的存放位置,这第2个FAT是备用的。

备份FAT地址范围:0x1400 ~ 0x25FF

1面0道的第2扇区起到1面0道的第15扇区(共14个扇区)用于存放 FDT。

FDT起始地址:0x2600 ~ 0x41FF

以IO.SYS为例:

0x2600~0x260A :文件名
0x260B:07:只读、隐藏的系统文件
0x260C~0x2615:保留
0x2616~0x2617:20A0=0xA020(10100 000001 00000):文件最后修改时间20:01:00
0x2618~0x2619:D324=0x24D3(0010010 0110 10011):文件最后修改日期1998/06/19
0x261A~0x261B:0200:文件首簇号002,其他附后
0x261C~0x261F:966B0300=0x00036B96:文件的长度224150Byte

文件簇号分析: 其中,簇号0x002可知:

逻辑扇区号 = 0x002+31 = 33
因此,IO.SYS文件的存储起始位置为:逻辑扇区号 * 512 = 0x04200
文件首簇号002指向的位置为:0x200+(0x002*3/2)=0x200+3=0x203+0(簇号从0x203开始)。
因为0能被3整除(姑且这样认为),因此,簇号002指向的位置为0x203+0=0x203的位置。
0x203位置的数据为034000=0x004003,即第二簇为003

以MSDOS.SYS为例: 文件首簇号0x23F,可知:

逻辑扇区号 = 0x23F+31 = 606
因此,MSDOS.SYS文件的存储起始位置为:逻辑扇区号 * 512 = 0x4BC00
文件首簇号23F指向的位置为:0x200+(0x23F*3/2)=0x200+862.5=0x203+859.5。
因为858能被3整除,因此,簇号23F指向的位置为0x203+858=0x55D后面的1.5个位置。
0x55D位置的数据为FFFFFF=0xFFFFFF,因此簇号23F指向的内容为高12bit的0xFFF。
即MSDOS.SYS的第一簇为文件的最后一簇。

FAT12文件系统FDT读取类(简版)

目前的版本,仅支持对根目录的文件表进行读取。子目录下面的没研究……

#ifndef _MYFDT_H_
#define _MYFDT_H_

typedef unsigned char U8;
typedef unsigned short int U16;
typedef unsigned long int U32;

typedef U8 Type_FDTIndex;

typedef struct{
	U16 u16Year;
	U8 u8Month;
	U8 u8Day;
}MyDate_st;

typedef struct{
	U8 u8Hour;
	U8 u8Minute;
	U8 u8Second;
}MyTime_st;

class CMyFDT{

protected:

#define FDT_START_ADDR (0x2600U)
#define FDT_END_ADDR (0x41FFU)

#define FDT_INFO_LENGTH (32U)
#define FDT_INDEX_MAX ((Type_FDTIndex)((FDT_END_ADDR-FDT_START_ADDR+1U)/FDT_INFO_LENGTH))

	typedef struct{
		TCHAR tcFileName[9];
		TCHAR tcExtName[4];
		U8 u8Ability;
		U8 u8NoUse[11];
		U16 u16ModifyTime;
		U16 u16ModifyDate;
		U16 u16FisrtCluster;
		U32 u32FileLength;
	}MyFDTElement_st;

	MyFDTElement_st m_FDT[FDT_INDEX_MAX];
	Type_FDTIndex m_IndexCnt;

public:
	CMyFDT();
	BOOL LoadFDTInfo(TCHAR u8File_p[]);// 参数为磁盘镜像文件首地址
	Type_FDTIndex GetIndexCnt();
	TCHAR *GetFileName(Type_FDTIndex uIndex,TCHAR *u8FileName_p=NULL);
	TCHAR *GetExtName(Type_FDTIndex uIndex,TCHAR *u8ExtName_p=NULL);
	BOOL GetFileExist(Type_FDTIndex uIndex);
	U8 GetAbility(Type_FDTIndex uIndex);
	void GetModifyDate(Type_FDTIndex uIndex,MyDate_st *);
	void GetModifyTime(Type_FDTIndex uIndex,MyTime_st *);
	U16 GetFisrtCluster(Type_FDTIndex uIndex);
	U32 GetFileLength(Type_FDTIndex uIndex);
};

#endif /* _MYFDT_H_ */

#include "MyFDT.h"

TCHAR *TrimRight(TCHAR *tcBuff)
{
	U32 u32Len;

	u32Len = _z_Strlen(tcBuff);
	for(U32 i=u32Len;i>0;i--){
		if((U8)(tcBuff[i-1]) == ' '){
			tcBuff[i-1] = '/0';
		}
		else{
			break;
		}
	}

	return tcBuff;
}

CMyFDT::CMyFDT()
{
	m_IndexCnt = 0;
	memset(m_FDT,'/0',sizeof(m_FDT));
}

BOOL CMyFDT::LoadFDTInfo(TCHAR u8FilePt[])
{
	TCHAR *tcCrt_p;
	BOOL bRet;

	bRet = TRUE;
	tcCrt_p = u8FilePt + FDT_START_ADDR;
	while(tcCrt_p[0] != '/0'){
		TCHAR tcFileBuff[9];
		memset(tcFileBuff,'/0',sizeof(tcFileBuff));
		memcpy(tcFileBuff,&tcCrt_p[0],8);
		memcpy(m_FDT[m_IndexCnt].tcFileName,TrimRight(tcFileBuff),8);
		memset(tcFileBuff,'/0',sizeof(tcFileBuff));
		memcpy(tcFileBuff,&tcCrt_p[8],3);
		memcpy(m_FDT[m_IndexCnt].tcExtName,TrimRight(tcFileBuff),3);
		m_FDT[m_IndexCnt].u8Ability = (TBYTE)tcCrt_p[11];
		memcpy(m_FDT[m_IndexCnt].u8NoUse,&(tcCrt_p[12]),10);
		m_FDT[m_IndexCnt].u16ModifyTime = (U8)tcCrt_p[22] + ((U8)tcCrt_p[23]*0x100);
		m_FDT[m_IndexCnt].u16ModifyDate = (U8)tcCrt_p[24] + ((U8)tcCrt_p[25]*0x100);
		m_FDT[m_IndexCnt].u16FisrtCluster = (U8)tcCrt_p[26] + ((U8)tcCrt_p[27]*0x100);
		m_FDT[m_IndexCnt].u32FileLength = (U8)tcCrt_p[28] + ((U8)tcCrt_p[29]*0x100)+ ((U8)tcCrt_p[30]*0x10000)+ ((U8)tcCrt_p[31]*0x1000000);
		tcCrt_p += FDT_INFO_LENGTH;
		m_IndexCnt ++;
	}
	if(m_IndexCnt==0){
		bRet = FALSE;
	}

	return bRet;
}

Type_FDTIndex CMyFDT::GetIndexCnt()
{
	return m_IndexCnt;
}

TCHAR *CMyFDT::GetFileName(Type_FDTIndex uIndex,TCHAR *u8FileName_p)
{
	if(u8FileName_p!=NULL){
		strcpy(u8FileName_p,m_FDT[uIndex].tcFileName);
	}

	return m_FDT[uIndex].tcFileName;
}

TCHAR *CMyFDT::GetExtName(Type_FDTIndex uIndex,TCHAR *u8ExtName_p)
{
	if(u8ExtName_p!=NULL){
		_z_Strcpy(u8ExtName_p,(PTCHAR)m_FDT[uIndex].tcExtName);
	}

	return m_FDT[uIndex].tcExtName;
}

BOOL CMyFDT::GetFileExist(Type_FDTIndex uIndex)
{
	BOOL bRet = TRUE;
	if((U8)m_FDT[uIndex].tcFileName[0] == 0xE5){
		bRet = FALSE;
	}
	else if((U8)m_FDT[uIndex].tcFileName[0] == 0x00U){
		bRet = FALSE;
	}

	return bRet;
}

U8 CMyFDT::GetAbility(Type_FDTIndex uIndex)
{
	return m_FDT[uIndex].u8Ability;
}

void CMyFDT::GetModifyDate(Type_FDTIndex uIndex,MyDate_st *stDate_p)
{
	stDate_p->u16Year = ((m_FDT[uIndex].u16ModifyDate & 0xFE00) >> 9) + 1980;
	stDate_p->u8Month = (m_FDT[uIndex].u16ModifyDate & 0x01E0) >> 5;
	stDate_p->u8Day = (m_FDT[uIndex].u16ModifyDate & 0x001F);
}

void CMyFDT::GetModifyTime(Type_FDTIndex uIndex,MyTime_st *stTime_p)
{
	stTime_p->u8Hour = ((m_FDT[uIndex].u16ModifyTime & 0xF800) >> 11);
	stTime_p->u8Minute = (m_FDT[uIndex].u16ModifyTime & 0x07E0) >> 5;
	stTime_p->u8Second = (m_FDT[uIndex].u16ModifyTime & 0x001F);
}

U16 CMyFDT::GetFisrtCluster(Type_FDTIndex uIndex)
{
	return m_FDT[uIndex].u16FisrtCluster;
}

U32 CMyFDT::GetFileLength(Type_FDTIndex uIndex)
{
	return m_FDT[uIndex].u32FileLength;
}

原文发表于:csdn.net 2009-09-26 18:46 & 2009-09-27 11:18</a>