主引导程序的扩展

 

主引导程序如何加载存储介质中的其他程序?

引入FAT12文件系统

 

 

 

 实验:

 

 创建虚拟软盘

 

将虚拟软盘插入到FreeDos里面,并且盘符是b盘

 

 

进入Freedos

 

 

对B盘进行格式化,B盘就是虚拟软驱  data.img就拥有了FAT12文件系统

 

 

 将虚拟软盘挂载到Linux里面

 

卸载

 

 此时查看虚拟软盘就能看到两个文件

 

 查看一下

 

查看data.img    FAT12文件系统等价于文件格式

 -------------------------------------------------------------------------------------------------------------------------------------------------------

--------------------------------------------------------------------------------------------------------------------------------------------------------

下一步:Boot 查找目标文件(Loader),并读取文件的内容

  

 

 

 

 

 

 --实验:读取data.img中的文件系统信息

 

 

 定义结构体

 

0x200对应的十进制是512

 

 

 

 

 

 

 输出了16进制的55aa

 

 

主引导程序的代码量不能超过512字节

---------------------------------------------------------------------------------------------------------------------------------

 

 

 一个扇区占512字节

 

 实验-读取FAT12文件系统的根目录信息

//创建 RootEntry 结构体类型
struct RootEntry
{
    char DIR_Name[11];
    uchar DIR_Attr;
    uchar reserve[10];
    ushort DIR_WrtTime;
    ushort DIR_WrtDate;
    ushort DIR_FstClus;
    uint DIR_FileSize;
}

 读取文件项

RootEntry FindRootEntry(Fat12Header& rf, QString p, int i)
{
    RootEntry ret = {{0}};

    QFile file(p);

    if( file.open(QIODevice::ReadOnly) && (0 <= i) && (i < rf.BPB_RootEntCnt) )
    {
        QDataStream in(&file);

        file.seek(19 * rf.BPB_BytsPerSec + i * sizeof(RootEntry));

        in.readRawData(reinterpret_cast<char*>(&ret), sizeof(ret));
    }

    file.close();

    return ret;
}

打印根目录项

void PrintRootEntry(Fat12Header& rf, QString p)
{
    for(int i=0; i<rf.BPB_RootEntCnt; i++)
    {
        RootEntry re = FindRootEntry(rf, p, i);

        if( re.DIR_Name[0] != '\0' )//检验读取得到的目录项是否合法
        {
            qDebug() << i << ":";
            qDebug() << "DIR_Name: " << hex << re.DIR_Name;
            qDebug() << "DIR_Attr: " << hex << re.DIR_Attr;
            qDebug() << "DIR_WrtDate: " << hex << re.DIR_WrtDate;
            qDebug() << "DIR_WrtTime: " << hex << re.DIR_WrtTime;
            qDebug() << "DIR_FstClus: " << hex << re.DIR_FstClus;
            qDebug() << "DIR_FileSize: " << hex << re.DIR_FileSize;
        }
    }
}

 

 

2. 根据文件名查找根目录下对应的目录文件项

RootEntry FindRootEntry(Fat12Header& rf, QString p, QString fn)
{
    RootEntry ret = {{0}};

    for(int i=0; i<rf.BPB_RootEntCnt; i++)
    {
        RootEntry re = FindRootEntry(rf, p, i);

        if( re.DIR_Name[0] != '\0' )
        {
            int d = fn.lastIndexOf(".");    //做一个字符串分割的工作  
            QString name = QString(re.DIR_Name).trimmed();   //去掉前后的空格

            if( d >= 0 )
            {
                QString n = fn.mid(0, d);   //开头
                QString p = fn.mid(d + 1);  //结尾

                if( name.startsWith(n) && name.endsWith(p) )
                {
                    ret = re;
                    break;
                }
            }
            else
            {
                if( fn == name )
                {
                    ret = re;
                    break;
                }
            }
        }
    }

    return ret;
}

--------------------------------——————————————————————————————————————————————————————————————————————————————————————————

 

有了文件数据的起始位置,有了数据的大小,读取数据就变得不困难

 

 

1簇=512字节(FAT12)

我们的文件往往都是大于512个字节,一根文件需要若干个簇才能存取所有内容

FAT表中的先后关系

- 以簇(扇区)为单位存储文件数据(这里一簇等于一扇区大小)

- 每个表项(vec[i])表示文件数据的实际位置(簇)

(1)DIR_FstClus表示文件第0簇(扇区)的位置

(2)vec[DIR_FstClus]表示文件第1簇(扇区)的位置

(3)vec[vec[DIR_FstClus]]表示文件第2簇(扇区)的位置..
借助于FAT表项

即使数据簇离散的存储在介质里,也不影响文件数据的连续性(由FAT表项来保证)

 

 

FAT12数据逻辑组织示意图

链表

 

 

实验:加载FAT12中的文件数据

 

 

 

不同于从0开始的,数据区的偏移地址是从2开始的

 

 

 实验:读取指定文件内容

QVector<ushort> ReadFat(Fat12Header& rf, QString p)
{
    QFile file(p);
    int size = rf.BPB_BytsPerSec * 9;  //计算FAT表的大小
    uchar* fat = new uchar[size];          //用于存储直接从文件系统里读出来的FAT表
    QVector<ushort> ret(size * 2 / 3, 0xFFFF);    

    if( file.open(QIODevice::ReadOnly) )
    {
        QDataStream in(&file);

        file.seek(rf.BPB_BytsPerSec * 1);

        in.readRawData(reinterpret_cast<char*>(fat), size);

        for(int i=0, j=0; i<size; i+=3, j+=2)     //三个字节表示两个FAT表项
        {
            ret[j] = static_cast<ushort>((fat[i+1] & 0x0F) << 8) | fat[i];
            ret[j+1] = static_cast<ushort>(fat[i+2] << 4) | ((fat[i+1] >> 4) & 0x0F);
        }
    }

    file.close();

    delete[] fat;

    return ret;
}

转自https://blog.csdn.net/qq_39654127/article/details/88429461?spm=1001.2014.3001.5501

 

QByteArray ReadFileContent(Fat12Header& rf, QString p, QString fn)
{
    QByteArray ret;
    RootEntry re = FindRootEntry(rf, p, fn);

    if( re.DIR_Name[0] != '\0' )
    {
        QVector<ushort> vec = ReadFat(rf, p);
        QFile file(p);

        if( file.open(QIODevice::ReadOnly) )
        {
            char buf[512] = {0};  //一簇
            QDataStream in(&file);
            int count = 0;

            ret.resize(re.DIR_FileSize);//设置返回值数组对象的大小-目标文件的大小

            for(int i=0, j=re.DIR_FstClus; j<0xFF7; i+=512, j=vec[j])  //vec记录的是数据簇的地址
            {
                file.seek(rf.BPB_BytsPerSec * (33 + j - 2));

                in.readRawData(buf, sizeof(buf));

                for(uint k=0; k<sizeof(buf); k++)
                {
                    if( count < ret.size() )  //确保读到的是有效的文件
                    {
                        ret[i+k] = buf[k];
                        count++;
                    }
                }
            }
        }

        file.close();
    }

    return ret;
}

此时就读到了文件里的内容

 

 

 

posted @ 2021-06-30 01:05  wsq1219  阅读(59)  评论(0编辑  收藏  举报