主引导程序的扩展(下)

本文详细解读了 Fat12 文件系统中关键结构,包括根目录区、文件项、扇区和FAT表的使用。展示了如何读取和解析 Fat12 头部信息,以及利用 RootEntry 查找文件。通过实例展示了如何定位和获取文件内容,适合深入理解磁盘文件系统工作原理。
摘要由CSDN通过智能技术生成

在这里插入图片描述
在这里插入图片描述
BPB_RootEntCnt:根目录区拥有多少个文件项
sizeof(RootEntry):每个文件项大小(字节:32)
BPB_BytsPerSec:一个扇区占512字节
在这里插入图片描述
在这里插入图片描述

#include <QtCore/QCoreApplication>
#include <QFile>
#include <QDataStream>
#include <QDebug>
#include <QVector>
#include <QByteArray>

#pragma pack(push)
#pragma pack(1)

struct Fat12Header
{
    char BS_OEMName[8];
    ushort BPB_BytsPerSec;
    uchar BPB_SecPerClus;
    ushort BPB_RsvdSecCnt;
    uchar BPB_NumFATs;
    ushort BPB_RootEntCnt;
    ushort BPB_TotSec16;
    uchar BPB_Media;
    ushort BPB_FATSz16;
    ushort BPB_SecPerTrk;
    ushort BPB_NumHeads;
    uint BPB_HiddSec;
    uint BPB_TotSec32;
    uchar BS_DrvNum;
    uchar BS_Reserved1;
    uchar BS_BootSig;
    uint BS_VolID;
    char BS_VolLab[11];
    char BS_FileSysType[8];
};

struct RootEntry
{
    char DIR_Name[11];
    uchar DIR_Attr;
    uchar reserve[10];
    ushort DIR_WrtTime;
    ushort DIR_WrtDate;
    ushort DIR_FstClus;
    uint DIR_FileSize;
};

#pragma pack(pop)

void PrintHeader(Fat12Header& rf, QString p)
{
    QFile file(p);

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

        file.seek(3);

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

        rf.BS_OEMName[7] = 0;
        rf.BS_VolLab[10] = 0;
        rf.BS_FileSysType[7] = 0;

        qDebug() << "BS_OEMName: " << rf.BS_OEMName;
        qDebug() << "BPB_BytsPerSec: " << hex << rf.BPB_BytsPerSec;
        qDebug() << "BPB_SecPerClus: " << hex << rf.BPB_SecPerClus;
        qDebug() << "BPB_RsvdSecCnt: " << hex << rf.BPB_RsvdSecCnt;
        qDebug() << "BPB_NumFATs: " << hex << rf.BPB_NumFATs;
        qDebug() << "BPB_RootEntCnt: " << hex << rf.BPB_RootEntCnt;
        qDebug() << "BPB_TotSec16: " << hex << rf.BPB_TotSec16;
        qDebug() << "BPB_Media: " << hex << rf.BPB_Media;
        qDebug() << "BPB_FATSz16: " << hex << rf.BPB_FATSz16;
        qDebug() << "BPB_SecPerTrk: " << hex << rf.BPB_SecPerTrk;
        qDebug() << "BPB_NumHeads: " << hex << rf.BPB_NumHeads;
        qDebug() << "BPB_HiddSec: " << hex << rf.BPB_HiddSec;
        qDebug() << "BPB_TotSec32: " << hex << rf.BPB_TotSec32;
        qDebug() << "BS_DrvNum: " << hex << rf.BS_DrvNum;
        qDebug() << "BS_Reserved1: " << hex << rf.BS_Reserved1;
        qDebug() << "BS_BootSig: " << hex << rf.BS_BootSig;
        qDebug() << "BS_VolID: " << hex << rf.BS_VolID;
        qDebug() << "BS_VolLab: " << rf.BS_VolLab;
        qDebug() << "BS_FileSysType: " << rf.BS_FileSysType;

        file.seek(510);

        uchar b510 = 0;
        uchar b511 = 0;

        in.readRawData(reinterpret_cast<char*>(&b510), sizeof(b510));
        in.readRawData(reinterpret_cast<char*>(&b511), sizeof(b511));

        qDebug() << "Byte 510: " << hex << b510;
        qDebug() << "Byte 511: " << hex << b511;
    }

    file.close();
}

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) )//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;
}

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;
}

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;//hex:16进制打印
            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;
        }
    }
}

QVector<ushort> ReadFat(Fat12Header& rf, QString p)
{
    QFile file(p);
    int size = rf.BPB_BytsPerSec * 9;
    uchar* fat = new uchar[size];
    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)
        {
            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;
}

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])
            {
                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;
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QString img = "/home/delphi/data.img";
    Fat12Header f12;

    qDebug() << "Read Header:";

    PrintHeader(f12, img);

    qDebug() << endl;

    qDebug() << "Print Root Entry:";

    PrintRootEntry(f12, img);

    qDebug() << endl;

    qDebug() << "Print File Content:";

    QString content = QString(ReadFileContent(f12, img, "DELPHI.DT"));

    qDebug() << content;

    return a.exec();
}


其中一部分的打印结果如下:
在这里插入图片描述
可以看出上次写入的两个文件test.txt和loader.bin都还在
通过DIR_Name就可以查找想要的文件了

在这里插入图片描述
存储文件的所有簇,不一定连续,很有可能是离散分布在存储介质中

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
长得很像链表(无表头)
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
33扇区地址计算:
在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值