精华内容
下载资源
问答
  • fat12
    2021-10-16 20:43:41

    fat12 软盘.md

    fat12

    FAT12是DOS时代就开始使用的文件系统(File System),直到现在仍然在软盘上使用,FAT12软盘的被格式化后为:有两个磁头,每个磁头80个柱面(磁道),每个柱面有18个扇区,每个扇区512个字节空间。所以标准软盘的总空间为:

    2 * 80 * 18 * 512B = 1474560B = 1440K = 1.44M
    2: 两个磁头(磁盘两面嘛)
    80: 80个磁道(柱面)
    18: 每个磁道被分为 18 个扇区
    512: 每个扇区 512B(byte)
    

    下面是FAT12的结构图:
    在这里插入图片描述

    引导扇区 MBR

    操作系统之所以认识 FAT12 格式的磁盘,其秘密就在于逻辑 0 扇区这 512B 上。如果这 512 字节的最后两个字节的内容分别是 55 和 AA(0xAA55 低字节在前,高字节在后)的话,BIOS 在启动时会将这个扇区读取到0:7C00h-0:7DFFh处,然后跳转到 0:7C00h 处继续执行指令,操作系统即用此来达到引导系统的目的,而这个磁盘就称为引导磁盘。

    操作系统标识 FAT12 文件系统是因为在逻辑 0 扇区(即引导扇区)处还存储着一个特定的数据结构,此结构有固定的格式,在操作系统将此磁盘格式化时自动生成,具体数据结构如下表所示:

    名称开始字节长度内容参考值
    BS_jmpBOOT03一个短跳转指令jmp short LABEL_START
    nop
    BS_OEMName38厂商名‘ZGH’
    BPB_BytesPerSec112每扇区字节数(Bytes/Sector)0x200
    BPB_SecPerClus131每簇扇区数(Sector/Cluster)0x1
    BPB_ResvdSecCnt142Boot记录占用多少扇区ox1
    BPB_NumFATs161共有多少FAT表0x2
    BPB_RootEntCnt172根目录区文件最大数0xE0
    BPB_TotSec16192扇区总数0xB40
    BPB_Media211介质描述符0xF0
    BPB_FATSz16222每个FAT表所占扇区数0x9
    BPB_SecPerTrk242每磁道扇区数(Sector/track)0x12
    BPB_NumHeads262磁头数(面数)0x2
    BPB_HiddSec284隐藏扇区数0
    BPB_TotSec32324如果BPB_TotSec16=0,则由这里给出扇区数0
    BS_DrvNum361INT 13H的驱动器号0
    BS_Reserved1371保留,未使用0
    BS_BootSig381扩展引导标记(29h),用于指明此后的三个域可用0x29
    BS_VolID394卷序列号0
    BS_VolLab4311卷标‘ZGH’
    BS_FileSysType548文件系统类型‘FAT12’
    引导代码及其他内容62448引导代码及其他数据引导代码(剩余空间用0填充)
    结束标志0xAA555102第510字节为0x55,第511字节为0xAA0xAA55

    下面我们介绍其中的一些变量的含义:

    • BS_jmpBoot:是跳转指令,偏移0处的跳转指令必须是合法的可执行的基于x86的CPU指令,如:jmp start,这样可以生成3字节长的指令,(加关键字short的短跳转指令的长度是2字节),指向操作系统引导代码部分。Windows和MS-DOS生成的FAT12启动扇区中的跳转指令是短跳转,如:jmp short LABEL_START,然后加一个 nop 的空指令来保持 3 字节的长度。
    • BPB_BytsPerSec:每扇区的字节数,类型是双字节长,标准分区上的每扇区字节数一般是512B, FAT12的格式下设置为512(0x200h)。
    • BPB_SecPerClus:每簇扇区数,偏移13处,类型是字节,簇是数据存储的最小单位,在FAT12格式下一般为1,即每簇只有1个扇区(512字节)。
    • BPB_RsvdSecCnt:Boot记录占用多少扇区,即在 FAT1 之前的引导扇区,一般情况下,引导扇区占用1个扇区
    • BPB_NumFATs:共有多少个 FAT 表,默认情况下此字段的值为 2,也就是有两个FAT表,FAT1 和 FAT2 的内容相同,当FAT1 表出错的时候可以使用 FAT2 来恢复文件分配表。
    • BPB_RootEntCnt:根目录文件数最大值,默认为 224,每个目录条目占用 32B 的空间,因此根目录的大小为:224*32/512=14,即占用14个扇区。
    • BPB_TotSec16:扇区总数 = 0xB40 = 2880
    • BPB_FATSz16:每个FAT占用的扇区数 = 0x9 = 9,即 FAT1 占用1—9逻辑扇区,FAT2占用 10—18 逻辑扇区。
    • BPB_SecPerTrk:每磁道扇区数 = 0x12 =18,即标准FAT12文件系统中,每个磁道的扇区数就是为18。
    • BPB_NumHeads:磁头数 = 0x2 =2,该磁盘包括2个磁头,也就是面数是2。
    • BPB_Media: 介质描述,比如:介质描述
      • 0xF8 单面、每面80磁道、每磁道9扇区
      • 0xF9 双面、每面80磁道、每磁道9扇区
      • 0xFA 单面、每面80磁道、每磁道8扇区
      • 0xFB 双面、每面80磁道、每磁道8扇区
      • 0xFC 单面、每面40磁道、每磁道9扇区
      • 0xFD 双面、每面40磁道、每磁道9扇区
      • 0xFE 单面、每面40磁道、每磁道8扇区
      • 0xFF 双面、每面40磁道、每磁道8扇区
      • 0xF0 双面、每面80磁道、每磁道18扇区?
      • 同样的介质描述必须在重复复制到每份FAT的第一个字节。有些操作系统(MSX-DOS 1.0版)全部忽略启动扇区参数,而仅仅使用FAT的第一个字节的介质描述确定文件系统参数。

    FAT 表

    FAT1和FAT2是两个完全相同的FAT表,每个 FAT 占用9个扇区。其中 FAT1 占用 1—9 扇区,FAT2 占用 10—18 扇区。FAT12 表示每个 FAT项占 12bit。

    根目录区

    根目录区的开始扇区号是19,它是由若干个目录条目(Directory Entry)组成,条目最多有BPB_RootEntCnt个,由于根目录区的大小是依赖于 **BPB_RootEntCnt **的,所以长度不固定。

    在本 FAT12 中,因为 BPB_RootEntCnt=0xE0=14*16+0=244,即条目最多为 244 个,又因为每个条目占用 32 个字节,故244*32/512=14,即该根目录区占 14 个扇区,即 19—32。

    根目录区中的每个条目占用32字节,它的格式如下图:
    在这里插入图片描述

    这里主要定义了文件的名字,属性,最后写入的时间和日期,文件的开始簇数以及文件大小。

    名词介绍

    1. fat

    文件分配表FAT(File Allocation Table)用来描述文件系统内存储单元的分配状态及文件内容的前后链接关系的表格(也可以笼统的说成是记录文件所在位置的表格)。它对于FAT文件系统来讲是至关重要的一个组成部分,并且它对于硬盘的使用也非常重要,假若丢失文件分配表,那么硬盘上的数据就无法定位,也就不能使用了。

    FAT文件系统有 FAT12、FAT16、FAT32。其所包含的这三种类型皆是由FAT表中每个FAT表项所占长度来分类的,也就是说,FAT12的FAT表中的每个FAT表项占用12位,FAT16中的FAT表每个FAT表项占用16位,FAT32的FAT表中的每个FAT表项占用32位。

    表项:代表一个数据区中的簇。FAT项的值代表的是文件的下一个簇号,但如果值大于或等于 0xFF8,则表示当前簇已经是文件的最后一个簇了。如果值为 0xFF7,表示它是一个坏簇。

    1. 扇区

    扇区,是指磁盘上划分的区域。磁盘上的每个磁道被等分为若干个弧段,这些弧段便是磁盘的扇区,硬盘的读写以扇区为基本单位。

    数据存储在硬盘的时候都是以簇为单位,所以无论文件大小是多少,除非正好是簇大小的倍数,否则文件所占用的最后一个簇或多或少都会产生一些剩余的空间,且这些空间又不能给其它文件使用,即使这个文件只有0字节,也不允许两个文件或两个以上的文件共用一个簇,不然会造成数据混乱。

    1. 主分区、扩展分区、逻辑分区

    • 主分区:一个硬盘的主分区也就是包含操作系统启动所必需的文件和数据的硬盘分区,要在硬盘上安装操作系统,则该硬盘必须得有一个主分区。主分区中不能再划分其他类型的分区,因此每个主分区都相当于一个逻辑磁盘(在这一点上主分区和逻辑分区很相似,但主分区是直接在硬盘上划分的,逻辑分区则必须建立于扩展分区中)。
    • 扩展分区:是除主分区外的分区,但它不能直接使用,必须再将它划分为若干个逻辑分区才行。
    • 逻辑分区:就是我们平常在操作系统中所看到的D、E、F等盘。

    一个硬盘可以有 1 到 3 个主分区和 1 个扩展分区,也可以只有主分区而没有扩展分区,但主分区必须至少有 1 个,扩展分区则最多只有 1 个,且主分区+扩展分区总共不能超过4个。逻辑分区可以有若干个。

    分出主分区后,其余的部分可以分成扩展分区,一般是剩下的部分全部分成扩展分区,也可以不全分,剩下的部分就浪费了。

    扩展分区不能直接使用,必须分成若干逻辑分区。所有的逻辑分区都是扩展分区的一部分。

    • 硬盘的容量=主分区的容量+扩展分区的容量;
    • 扩展分区的容量=各个逻辑分区的容量之和。

    部分内容转自:https://blog.csdn.net/yi412/article/details/87875691

    更多相关内容
  • 用C/C++和nasm编写一个FAT12镜像查看?具,读取一个.img格式的文件并响应用户输入。
  • FAT12:用C语言实现FAT 12系统仿真的实现
  • 电子-FAT12文件格式快速入门.zip,单片机/嵌入式STM32-F0/F1/F2
  • 详解FAT12文件系统

    万次阅读 多人点赞 2019-03-16 11:04:23
    1、详解FAT12文件系统 2、实验 1、向虚拟软盘写入文件 2、读取软盘文件系统信息 3、在根目录中查找目标文件 4、读取目标文件到内存 3、小结 1、FAT12文件系统 文件系统 -存储介质上组织文件数据的方法...

    目录

    1、详解FAT12文件系统

    2、实验

    1、向虚拟软盘写入文件

    2、读取软盘文件系统信息

    3、在根目录中查找目标文件

    4、读取目标文件到内存

    3、小结


    1、FAT12文件系统

    文件系统

        - 存储介质上组织文件数据的方法(数据组织的方式

    文件系统示例

        - FAT12是DOS时代的早期文件系统

        - FAT12结构非常简单,一直沿用于软盘

        - FAT12的基本组织单位

               字节(Byte):基本数据单位

               扇区(Sector):磁盘中的最小数据单元

               簇(Cluster):一个或多个扇区

    深入FAT12文件系统

              FAT12文件系统由引导区,FAT表,根目录项表和文件数据区组成。

    FAT12的主引导区

                主引导区存储的比较重要的信息是文件系统的类型,文件系统逻辑扇区总数,

                每簇包含的扇区数等。主引导区最后以0x55AA两个字节作为结束,共占用一个扇区。

    二进制分析:(data.img由后文生成)

    根目录区的大小和位置

                                                           可以看到根目录区起始于第19扇区

    根目录区的目录项

            根目录区由目录项构成,每一个目录项代表根目录中的一个文件索引。

    //创建 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;
    };

    FAT表 - FAT12的数据组织核心

        - FAT1和FAT2是相互备份的关系 ,数据内容完全一致

        - FAT表是一个关系图,记录了文件数据的先后关系

        - 每一个FAT表项占用12比特

        - FAT表的前2个表项规定不使用

     

    FAT表中的先后关系

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

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

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

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

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

     

    FAT12数据物理组织示意

    FAT12数据逻辑组织示意


    2、实验

    模拟Boot 查找目标文件(Loader),并读取文件的内容!- 突破Boot512字节限制的解决方案

    解决方案(★)

        - 使用FAT12对软盘(data.img)进行格式化

        - 编写可执行程序(Loader),并将其拷贝到软盘中

        - 主引导程序(Boot)在文件系统中查找Loader

        - 将Loader复制到内存中,并跳转到入口处执行


    1、向虚拟软盘写入文件

    实验:往虚拟软盘中写入文件

        - 原材料:FreeDos,Bochs,bximage

        - 步骤:

                 ① 创建虚拟软盘data.img

                 ② 在FreeDos中进行格式化(FAT12)

                 ③ 将data.img挂载到Linux中,并写入文件

    1、先创建一个虚拟软盘 data.img

    2、修改bochsrc 配置文件,freedos.img 作为启动软盘(A盘),将软盘data.img作为B盘插入

    ###############################################################
    # Configuration file for Bochs
    ###############################################################
    
    # how much memory the emulated machine will have
    megs: 32
    
    # filename of ROM images
    romimage: file=/usr/local/share/bochs/BIOS-bochs-latest
    vgaromimage: file=/usr/share/vgabios/vgabios.bin
    
    # what disk images will be used
    floppya: 1_44=freedos.img, status=inserted
    floppyb: 1_44=data.img, status=inserted
    
    # choose the boot disk.
    boot: floppy
    
    # where do we send log messages?
    # log: bochsout.txt
    
    # disable the mouse
    mouse: enabled=0
    
    # enable key mapping, using US layout as default.
    keyboard_mapping: enabled=1, map=/usr/local/share/bochs/keymaps/x11-pc-us.map

    启动bochs

    3、将data.img挂载到Linux中,并写入loader文件

                                         成功向FAT12格式的软盘写入文件


    2、读取软盘文件系统信息

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

    步骤:

            创建Fat12Header结构体类型

            使用文件流读取前512字节的内容

            解析并打印相关的信息

    #include <QtCore/QCoreApplication>
    #include <QFile>
    #include <QDataStream>
    #include <QDebug>
    
    #pragma pack(push)
    #pragma pack(1)
    
    struct Fat12Header
    {
        char BS_OEMName[8];    // OEM字符串,必须为8个字符,不足以空格填空
        ushort BPB_BytsPerSec; // 每扇区字节数
        uchar BPB_SecPerClus;  // 每簇占用的扇区数
        ushort BPB_RsvdSecCnt; // Boot占用的扇区数
        uchar BPB_NumFATs;     // FAT表的记录数
        ushort BPB_RootEntCnt; // 最大根目录文件数
        ushort BPB_TotSec16;   // 每个FAT占用扇区数
        uchar BPB_Media;       // 媒体描述符
        ushort BPB_FATSz16;    // 每个FAT占用扇区数
        ushort BPB_SecPerTrk;  // 每个磁道扇区数
        ushort BPB_NumHeads;   // 磁头数
        uint BPB_HiddSec;      // 隐藏扇区数
        uint BPB_TotSec32;     // 如果BPB_TotSec16是0,则在这里记录
        uchar BS_DrvNum;       // 中断13的驱动器号
        uchar BS_Reserved1;    // 未使用
        uchar BS_BootSig;      // 扩展引导标志
        uint BS_VolID;         // 卷序列号
        char BS_VolLab[11];    // 卷标,必须是11个字符,不足以空格填充
        char BS_FileSysType[8];// 文件系统类型,必须是8个字符,不足填充空格
    };
    
    #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();
    }
    
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
    
        Fat12Header f12;
    
        PrintHeader(f12, "E:\\data.img");
        
        return a.exec();
    }
    

                                      200H = 512

    实验结论

    1.FreeDos中的format程序在格式化软盘的时候自动在第0扇区生成了一个主引导程序,这个主引导程序只打印一个字符串

    2.文件格式和文件系统都是用于定义数据如何存放的规则,只要遵循这个规则就能够成功读写目标数据(参考PE文件结构


    3、在根目录中查找目标文件

    如何在FAT12根目录中查找是否存在目标文件?

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

    #include <QtCore/QCoreApplication>
    #include <QFile>
    #include <QDataStream>
    #include <QDebug>
    #include <QVector>
    #include <QByteArray>
    #include <stdio.h>
    
    #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();
    }
    
    // 返回第i个目录项
    RootEntry FindRootEntry(Fat12Header& rf, QString p, int i)
    {
        RootEntry ret = {{0}};
    
        QFile file(p);
    
        // BPB_RootEntCnt:目录项个数
        if( file.open(QIODevice::ReadOnly) && (0 <= i) && (i < rf.BPB_RootEntCnt) )
        {
            QDataStream in(&file);
    
            // 定位到第i个目录项
            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;
                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;
            }
        }
    }
    
    
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
    
        QString img = "E:\\data.img";
    
        Fat12Header f12;
    
        qDebug() << "Read Header:";
    
        PrintHeader(f12, img);
    
        qDebug() << endl;
    
        qDebug() << "Print Root Entry:";
    
        PrintRootEntry(f12, img);
    
        qDebug() << endl;
    
        RootEntry r = FindRootEntry(f12, img, "LOADER.TXT");
    
        qDebug() << "DIR_Name: " << hex << r.DIR_Name;
        qDebug() << "DIR_Attr: " << hex << r.DIR_Attr;
        qDebug() << "DIR_WrtDate: " << hex << r.DIR_WrtDate;
        qDebug() << "DIR_WrtTime: " << hex << r.DIR_WrtTime;
        qDebug() << "DIR_FstClus: " << hex << r.DIR_FstClus;
        qDebug() << "DIR_FileSize: " << hex << r.DIR_FileSize;
    
        return a.exec();
    }
    

     

                对于多出来的目录项不必理会

    文件以簇为单位存储,Fat12文件系统1簇等于1扇区,那么一个文件大于512字节如何存储?


    4、读取目标文件到内存

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

        - 步骤:

        (1)在根目录区查找目标文件对应的项

        (2)获取目标文件的起始簇号和文件大小

        (3)根据FAT表中记录的逻辑先后关系读取数据

    小贴士

        - FAT表中的每个表项只占用12比特(1.5字节

        - FAT表一共记录了BPB_BytsPerSec * 9 * 2 / 3个表项 (9个扇区 * 512 /1.5)

        - 可以使用一个short表示一个表项的值

        - 如果表项值大于等于0xFF8,则说明已经到达最后一个簇

        - 如果表项值等于0xFF7,则说明当前簇已经损坏

     

        - 数据区起始簇(扇区)号为33,地址为0x4200(33 * 512)

        - 数据区起始地址所对应的编号为2(不为0)(有了起始地址,这里可以用偏移地址)

        - 因此,DIR_FstClus对应的地址为:0×4200+(DIR_FstClus-2)*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) )
        {
            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;
                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;
            }
        }
    }
    
    // 返回FAT表所有表项
    QVector<ushort> ReadFat(Fat12Header& rf, QString p)
    {
        QFile file(p);
    
        // FAT表大小
        int size = rf.BPB_BytsPerSec * 9;
    
    
        uchar* fat = new uchar[size];
    
    
        QVector<ushort> ret(size * 2 / 3, 0xFFFF); // FAT表项个数和默认值
    
        if( file.open(QIODevice::ReadOnly) )
        {
            QDataStream in(&file);
    
            // 定位到FAT表的起始位置(主引导区后面的扇区)
            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 = "E:\\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, "LOADER.TXT"));
    
        qDebug() << content;
    
        return a.exec();
    }
    

     

    3、小结

    加载新程序需要依赖于文件系统

    FAT12是一种早期用于软盘的简单文件系统

    FAT12文件系统的重要信息存储于0扇区

    FAT12根目录区记录了文件的起始簇号和长度

    通过查找根目录区能够确定是否存在目标文件

    FAT12文件数据的组织使用了单链表的思想

         - 文件数据离散的分布于存储介质中

         - 文件数据通过FAT项进行关联

     

    展开全文
  • FAT12文件系统

    千次阅读 2019-03-31 13:27:56
    FAT12文件系统 转载自 https://blog.csdn.net/begginghard/article/details/7284834 感谢 一、 FAT12 FAT12是DOS时代就开始使用的文件系统(File System),直到现在仍然在软盘上使用,FAT12软盘...

    FAT12文件系统

    转载自 https://blog.csdn.net/begginghard/article/details/7284834 感谢

    一、 FAT12

    FAT12是DOS时代就开始使用的文件系统(File System),直到现在仍然在软盘上使用,FAT12软盘的被格式化后为:有两个磁头,每个磁头80个柱面(磁道),每个柱面有18个扇区,每个扇区512个字节空间。所以标准软盘的总空间为:

    2 * 80 *18 * 512=1474560B=1440K=1.44M

    下面是FAT12的结构图:


    1、引导扇区

    操作系统之所以认识FAT12格式的磁盘,其秘密就在于逻辑0扇区这512B上。如果这512字节的最后两个字节的内容分别是55和AA(0xAA55低字节在前,高字节在后)的话,BIOS在启动时会将这个扇区读取到0:7C00h-0:7DFFh处,然后跳转到0:7C00h处继续执行指令,操作系统即用此来达到引导系统的目的,而这个磁盘就称为引导磁盘。

    操作系统标识FAT12文件系统是因为在逻辑0扇区(即引导扇区)处还存储着一个特定的数据结构,此结构有固定的格式,在操作系统将此磁盘格式化时自动生成,具体数据结构如下表所示:

     

    名称

    开始字节

    长度

    内容

    参考值

    BS_jmpBOOT

    0

    3

    一个短跳转指令

    jmp short LABEL_START

    nop

    BS_OEMName

    3

    8

    厂商名

    'ZGH'

    BPB_BytesPerSec

    11

    2

    每扇区字节数(Bytes/Sector)

    0x200

    BPB_SecPerClus

    13

    1

    每簇扇区数(Sector/Cluster)

    0x1

    BPB_ResvdSecCnt

    14

    2

    Boot记录占用多少扇区

    ox1

    BPB_NumFATs

    16

    1

    共有多少FAT表

    0x2

    BPB_RootEntCnt

    17

    2

    根目录区文件最大数

    0xE0

    BPB_TotSec16

    19

    2

    扇区总数

    0xB40

    BPB_Media

    21

    1

    介质描述符

    0xF0

    BPB_FATSz16

    22

    2

    每个FAT表所占扇区数

    0x9

    BPB_SecPerTrk

    24

    2

    每磁道扇区数(Sector/track)

    0x12

    BPB_NumHeads

    26

    2

    磁头数(面数)

    0x2

    BPB_HiddSec

    28

    4

    隐藏扇区数

    0

    BPB_TotSec32

    32

    4

    如果BPB_TotSec16=0,则由这里给出扇区数

    0

    BS_DrvNum

    36

    1

    INT 13H的驱动器号

    0

    BS_Reserved1

    37

    1

    保留,未使用

    0

    BS_BootSig

    38

    1

    扩展引导标记(29h)

    0x29

    BS_VolID

    39

    4

    卷序列号

    0

    BS_VolLab

    43

    11

    卷标

    'ZGH'

    BS_FileSysType

    54

    8

    文件系统类型

    'FAT12'

    引导代码及其他内容

    62

    448

    引导代码及其他数据

    引导代码(剩余空间用0填充)

    结束标志0xAA55

    510

    2

    第510字节为0x55,第511字节为0xAA

    0xAA55


    下面我们介绍其中的一些变量的含义:

    BS_jmpBoot:是跳转指令,偏移0处的跳转指令必须是合法的可执行的基于x86的CPU指令,如:jmp start,这样可以生成3字节长的指令,(加关键字short的短跳转指令的长度是2字节),指向操作系统引导代码部分。Windows和MS-DOS生成的FAT12启动扇区中的跳转指令是短跳转,如:jmp short LABEL_START,然后加一个nop的空指令来保持3字节的长度。

    BPB_BytsPerSec:每扇区的字节数,类型是双字节长,标准分区上的每扇区字节数一般是512B, FAT12的格式下设置为512(0x200h)。

    BPB_SecPerClus:每簇扇区数,偏移13处,类型是字节,簇是数据存储的最小单位,在FAT12格式下一般为1,即每簇只有1个扇区(512字节)。

    BPB_RsvdSecCnt:Boot记录占用多少扇区,即在FAT1之前的 引导扇区,一般情况下,引导扇区占用1个扇区。

    BPB_NumFATs:共有多少个FAT表,默认情况下此字段的值为2,也就是有两个FAT表,FAT1和FAT2的内容相同,当FAT1表出错的时候可以使用FAT2来恢复文件分配表。

    BPB_RootEntCnt:根目录文件数最大值,默认为224,每个目录条目占用32B的空间,因此根目录的大小为:224*32/512=14,即占用14个扇区。

    BPB_TotSec16:扇区总数=0xB40=2880

    BPB_FATSz16:每个FAT占用的扇区数=0x9=9,即FAT1占用1—9逻辑扇区,FAT2占用10—18逻辑扇区。

    BPB_SecPerTrk:每磁道扇区数=0x12=18,即标准FAT12文件系统中,每个磁道的扇区数就是为18。

    BPB_NumHeads:磁头数=0x2=2,该磁盘包括2个磁头,也就是面数是2。

    2、FAT表

             FAT1和FAT2是两个完全相同的FAT表,每个FAT占用9个扇区。其中FAT1占用1—9扇区,FAT2占用10—18扇区。具体详细介绍看下面4。

    3、根目录区

    根目录区的开始扇区号是19,它是由若干个目录条目(Directory Entry)组成,条目最多有BPB_RootEntCnt个,由于根目录区的大小是依赖于BPB_RootEntCnt的,所以长度不固定。

             在本FAT12中,因为BPB_RootEntCnt=0xE0=14*16+0=244,即条目最多为244个,又因为每个条目占用32个字节,故244*32/512=14,即该根目录区占14个扇区,即19—32。

             根目录区中的每个条目占用32字节,它的格式如下图:


    这里主要定义了文件的名字,属性,最后写入的时间和日期,文件的开始簇数以及文件大小。

    下面我们通过实例来认识这些内容,

    1、 首先创建一个虚拟软盘,在这里我们使用WinImage,具体下载地址在我的下载资源中。

    打开WinImage:

    选择文件—》新建


    新建一个虚拟软盘之后,需要向里面添加文件,我们需要提前写好下面几个文件

    RIVER.TXT,内容为riverriverriver

    FLOWER.TXT,内容为flowerflower………flower,至少要100个flower,使得数据空间大于512个字节,这样该文件将占用两个连续的扇区。

    TREE.TXT,内容为treetreetree

    再添加一个HOUSE目录,然后在目录\HOUSE下添加两个文本文件:

    CAT.TXT,内容为catcatcat

    DOG.TXT,内容为dogdogdog

    选择映像—》加入,依次加入RIVER.TXT,FLOWER.TXT,TREE.TXT三个文件


    映像—》创建文件夹  HOUSE


    添加HOUSE目录


    双击house,进入house的文件夹内,然后添加CAT.TXT,DOG.TXT两个文件



    添加文件完成,然后保存,其中注意事项,保存类型为:虚拟软盘映像(*.vfd),我不知道这个类型与IMG有什么区别,但是我知道这个类型得到的结果是对的。呵呵!文件名为FLOOPY,这样我们就创建了一个虚拟软盘FLOOPY.vfd


    然后使用UltraEdit打开FLOOPY.vfd,由于根目录区是从第19扇区开始的,每个扇区512个字节,所以其第一个字节位于偏移19*512=9278=0x2600处,好的,现在就让我们去定位到0x2600处看看到底Directory Entry为何物?


    RIVER.TXT的各项值:


    在这里,我们只需要关心RIVER.TXT的DIR_FstClus,即文件的开始簇号,由于本FAT12中的BPB_SecPerClus=1,故一个簇为一个扇区,DIR_FstClus=2,意味着该文件的在数据区的起始扇区号为2。在这里需要注意的是,数据区的第一个簇的簇号是2,而不是0或者1,故该文件的数据开始于数据区的第一个簇,也就是第一个扇区。

    那么数据区的第一个扇区在哪里呢?

    首先计算根目录区所占有的扇区数:

    RootDirSectors =((BPB_RootEntCnt*32)+(BPB_BytsPerSec-1))/BPB_BytsPerSec。

    之所以分子要加上(BPB_BytsPerSec-1),是为了保证此公式在根目录区无法填满整数扇区时仍然成立。

    在本例中,因为BPB_RootEntCnt=224,计算得到根目录区所占有的扇区为14个。所以

    数据区开始的扇区号=根目录区开始的扇区号+14=19+14=33。

    现在就让我们跳入到第33扇区的偏移量是512*33=16896=0x00004200,让我们看看这里的内容:


    果然是riverriverriver。

    4、FAT表

    在这里,由于RIVER.TXT小于512字节,所以我们不需要FAT表就在数据区中找到了RIVER.TXT的内容,但是对于大于512字节的文件来说,就没有这么简单了,需要使用FAT表来寻找到该文件占用的所有数据区扇区。

    下面让我们跳入FAT1的内容,FAT1的开始扇区号是1,故偏移为1*512=512=0x200。


    一堆看不懂的符号,好像很多F。其实并不复杂,它有点像是一个位图,其中,每12位成为一个FAT项(FAT Entry),代表一个数据区中的簇。第0个和第1个FAT项始终不使用,第2个FAT项开始表示数据区的每一个簇,也就是说,第2个FAT项表示数据区第一个簇,依次类推。前文说过,数据区的第一个簇的簇号是2,和这里相呼应。

    要注意,由于每一个FAT项占12位,包含一个字节和另一个字节的一般,所以觉得特别别扭。具体情况是这样的,假设连续3个字节分别是如图所示:


    通常,FAT项的值代表的是文件的下一个簇号,但如果值大于或等于0xFF8,则表示当前簇已经是文件的最后一个簇了。如果值为0xFF7,表示它是一个坏簇。

    文件RIVER.TXT的开始簇号为2,对应的FAT表中的值为0xFFF,表示这个簇已经是最后一个。

    文件FLOWER.TXT的开始簇号为3,对应的FAT表中的值为0x004,表示文件还没有结束,下一个簇号是0x004,然后我们再看FAT表中第4个簇相对应的FAT值为0xFFF,则表示该是最后一个簇,则文件FLOWER.TXT占用第3、4簇。

    如果想使文件内容分存在不连续的扇区内,有一个方法可以做到,就是先将该文件加入到软盘驱动中,然后在进行添加相同的文件,进行覆盖。当然该文件的大小必须大于512个字节。

    《自己动手写操作系统》读后感                    http://blog.csdn.net/zgh1988/article/details/7059936

    全面剖析《自己动手写操作系统》第一章       http://blog.csdn.net/zgh1988/article/details/7060032

    全面剖析《自己动手写操作系统》第二章       http://blog.csdn.net/zgh1988/article/details/7062065

    全面剖析《自己动手写操作系统》第三章1     http://blog.csdn.net/zgh1988/article/details/7098981

    全面剖析《自己动手写操作系统》--“实模式--保护模式--实模式”       http://write.blog.csdn.net/postedit/7256254

    全面剖析《自己动手写操作系统》--堆栈段的工作方式   http://blog.csdn.net/zgh1988/article/details/7256254

    全面剖析《自己动手写操作系统》---特权级 以及 不同特权级代码段之间的跳转规则     http://blog.csdn.net/zgh1988/article/details/7262901

    全面剖析《自己动手写操作系统》--分页机制     http://blog.csdn.net/zgh1988/article/details/7270748

    全面剖析《自己动手写操作系统》--中断机制    http://blog.csdn.net/zgh1988/article/details/7276259












    调试记录

    简单说一下,直接tree 一下,我手动模拟的

    \------river.txt    (<512byte)
     ------flower.txt (1024byte)
     ------tree.txt     (<512byte)
     ------HOUSE
             --------cat.txt (<512byte)
             --------dog.txt (<512byte)
             #思考一下   ..   or .
             #上一个目录 和当前目录 在这里应该分配目录项吗???
    

    这里只说2个地方:
    一个地方是 flower.txt 这个要用2个簇 所以会涉及到 fat 链表知识,具体来讲就是先找到 对应目录项的 0x1a偏移处的簇信息,看了 03 ,好了可以查看 14 * 512+19 * 512+(03-02)* 512 = 0x4400h ,一定能找到我写的 aaaaaa...内容 ,然后我们还要去 fat[03]处去看一下,下一个簇号(针对数据区从2开始编号的,所以才会有上面的03-02去帮助我们找位置)可以发现 这个位置的12bit 写的是 04 ,说明剩下的内容在 数据区04区,其实和上面是连着的,有时候并不是连续的,这里只是刚好而已。这一部分也要对应一个 fat[04],去看一下,看到了 FFF,说明flower.txt结束了

    另外一个地方是 HOUSE,可以看到去对用的簇是 06 ,但是去 fat[06]看一下发现的是 FFF,但是这个不重要,应该去数据区 06 区,下面的第三幅图,一看便知,自己搞了一套 子目录信息 记录,里面可以看到 子文件 在数据区的储存位置 07 08 什么的,计算一下都可以找到我们在文件所写的内容。

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    展开全文
  • FAT12文件系统原理

    2022-03-04 15:13:58
    介绍FAT12文件系统

    概述

    文件系统是操作系统用于明确存储设备或分区上的文件的方法和数据结构。FAT(File Allocation Table,文件配置表)是Microsoft发明的文件系统。初期的FAT就是现在所称的FAT12,后来还有FAT16,FAT32和NTFS,FAT也被Linux所支持。
    FAT12包含以下四个部分:引导扇区,FAT表,根目录区和数据区。下面分别介绍。
    FAT12文件系统结构

    引导扇区

    引导扇区包含引导程序和FAT12文件系统的整个组成结构信息,这些信息描述了FAT文件系统对磁盘扇区的管理情况。结构如下图所示。
    在这里插入图片描述
    第一个字段是一个跳转指令:

    jmp short Label_Start
    nop
    

    因为BS_jmpBoot后面不是可执行程序,所以需要跳过这一部分。

    FAT表

    FAT表一般有两个,FAT1是活动FAT,FAT2是备份FAT,FAT2存在的意义就是修复FAT1。所以这里只介绍FAT1。
    首先需要明确簇的概念。在磁盘中最小的单位是簇,它由几个扇区组成。也就是说,就算你放一个1字节的文件,也需要占据一个簇。
    注意此处所说的簇是数据区的组织方式。从前面的表中可以看出:
    BPB_BytePerSec(每扇区字节数)为512
    BPB_SecPerClus(每簇扇区数)为1
    因此在FAT12中每个簇就是512个字节。
    另一方面,如果文件比较大,需要占据多个簇时,文件不一定在连续的簇内,这时就需要一种方法寻找到完整的文件,这个功能由FAT表完成。
    FAT表中,表项位宽和FAT类型有关,FAT12对应的表项位宽就是12。
    表项0和1的值是无关紧要的。其他表项每个对应数据区的一个簇,而表里保存的数据是下一个簇的簇号,这样,就形成了一个链表一样的结构了。具体的,表项保存的数据有以下的取值:

    • 000h:可用簇
    • 002h-FEFh:已用簇,标识下一个簇的簇号
    • FF0h-FF6h:保留簇
    • FF7h:坏簇
    • FF8h-FFFh:文件最后一个簇

    根目录区和数据区

    根目录的开始扇区号是19,它由最多BPB_RootEntCnt个目录项。这些目录项可能存储了指向文件和目录的信息。目录项是一个32B的结构体。它的结构如下:
    在这里插入图片描述
    数据区不仅可以保存目录项信息,也可以保存文件内的数据。对于树状的目录结构,树的层级结构可以通过目录的目录项简历起来,从根目录开始,经过目录项的逐层嵌套,形成了树状结构。

    参考文献:
    1.《一个64位操作系统的设计与实现》
    2.FAT12文件系统介绍
    3.fat文件系统

    展开全文
  • 【此后无良辰】实验13 FAT12文件系统

    千次阅读 多人点赞 2021-08-03 10:35:29
    实验目的 了解FAT文件系统的磁盘存储结构;学会文件各项空间属性的计算方法;掌握文件系统用户命令的开发方法。...在FAT12文件系统中,该域必须为 1。表示第一个扇区是保留扇区,即引导扇区。 Fats:FAT 表
  • FAT12文件系统介绍

    千次阅读 2020-03-31 21:37:21
    FAT12文件系统是指:在磁盘上规定一种特定的存储格式,这种存储格式高效方便,功能强大,因此形成了统一的规定。 基础知识 具体来说FAT12文件系统为1.44M的软盘设计。1.44M的软盘有2880个扇区,一个扇区有512个字节...
  • 制作FAT12镜像1

    2022-08-03 14:05:45
    注意:在操作挂载后的img镜像时,若使用命令行进行操作,需要使用root权限运行所有操作(例如mkdir, touch等)首先,在WSL下使用以下命令创建FAT
  • 本代码实现了FAT12的读取,实现了ls命令,ls -l命令和cat命令,可以实现读取超过512字节的文件。输出文件夹带颜色,通过makefile进行编译。主体代码在main.cpp中,my_print.asm中是打印功能的汇编代码。 gcc+nasm的...
  • FAT12文件系统镜像查看工具linux下的实现(nasm、g++联合编译)简介构思简介附加链接最终实现截图代码Makefile代码my_print.asm代码main.cpp代码 简介 FAT12的这次project实现在linux上用nasm和C++联合编译。 本文...
  • FAT12引导程序:FAT12引导程序(软盘2880K)
  • FAT12文件系统基本格式

    千次阅读 2019-02-22 11:52:37
    标识软盘是不是FAT12并不是没有根据的,在这512字节中,还有一个设备头用于标识这个软盘(设备),例子如下: ;=========================================================================== ; 程序执行的第一...
  • FAT12文件系统简介

    2013-01-30 15:10:47
    详细介绍了FAT12文件系统的启动扇区,FAT区和根目录区。尤其对FAT表的解读很独到
  • FAT12、FAT16、FAT32与NTFS的区别与利弊,讲解详细。
  • 实验十三 扫描 FAT12 文件系统管理的软盘 一、*实验目的* l 通过查看 FAT12 文件系统的扫描数据,并调试扫描的过程,理解 FAT12 文件系统管理软盘的方式。 l 通过改进 FAT12 文件系统的扫描功能,加深对 FAT12 文件...
  • NEC单片机_78F00547控制CH375芯片程序(CH375_FAT12_FAT16_FAT32_查找文件读出内容并且改写文件)
  • 详细介绍了FAT文件系统(包括FAT12,FAT16,FAT32),不知是哪位牛人写的电子书详细介绍了FAT文件系统(包括FAT12,FAT16,FAT32),不知是哪位牛人写的电子书详细介绍了FAT文件系统(包括FAT12,FAT16,FAT32),不知是哪位牛人写...
  • FAT文件系统中文文档(FAT12、FAT16、FAT32) 很详细的介绍了FAT文件系统,这是一份翻译文档。 文件格式:PDF(非扫描版)
  • 软磁盘的文件系统是FAT12,0~1个扇区是引导扇区,1~9和10~18是两个相同的FAT表,后面是根目录区(每个条目占32字节)和数据区。 其中FAT表每项占12位,代表一个簇,第0,1个FAT项始终不使用。第二项开始表示数据...
  • 文件系统 , FAT12 FAT16 FAT32讲解
  • 从引导扇区中获取BPB数据结构,由此计算出FAT表、根目录区以及数据区的起始位置 在根目录区中找到要遍历或寻找文件的对应文件 / 文件夹 根据在根目录区找到的entry中的FstClus项(即详细信息在数据区中的第一个簇的...
  • 对于FAT12,目前仅支持只读访问,并且在FAT32文件系统上,尚不支持FSInfo结构,该结构包含用于快速计算可用空间并轻松访问信息的可用群集信息,例如FAT中的下一个可用群集,因此它将在写入后通过fsck操作报告。...
  • 与ata结合的fat12 fat16 fat32的文件系统实现,代码完整!-FAT12,FAT16,FAT32 file system with ATA
  • 【文件系统】FAT12文件系统简介

    千次阅读 2015-10-10 20:33:43
    1.FAT12文件系统扇区分配 FAT12文件系统由引导区、FAT表、根目录项表和文件数据区组成,其中引导区程序占用扇区[0],FAT表1占用扇区[1]~[9],FAT表2占用扇区[10]~[18],根目录项表存储于扇区[19]~[32],用户存储的...
  • nasm&c++ 读取FAT12文件系统

    千次阅读 2019-11-13 20:12:28
    FAT12文件系统 基本结构 FAT文件系统把存储介质看成一位的数组,基本单位是簇。 一个簇包含一个扇区,大小为512B 存储介质划分为3个区域:boot,FAT,directory and data area 引导扇区...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 143,866
精华内容 57,546
关键字:

fat12

友情链接: MTPA3.zip