0%

nasm&c++ 读取FAT12文件系统

FAT12文件系统

基本结构

  • FAT文件系统把存储介质看成一位的数组,基本单位是簇。

  • 一个簇包含一个扇区,大小为512B

  • 存储介质划分为3个区域:boot,FAT,directory and data area

  • 图片1

引导扇区BOOT

BS_jmpBOOT 0 3 一个短跳转指令 jmp short LABEL_STARTnop
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

FAT-File Allocation Table

  • FAT1和FAT2互为备份。

  • 每12位成为一个FAT项(FATEntry),代表一个簇。所以2个FAT项会占用3个字节

  • 数据区起始于簇2,why?

    -在1.44M软盘上,FAT前三个字节的值是固定的0xF0、0xFF、0xFF,用于表示这是一个应用在1.44M软盘上的FAT12文件系统。本来序号为0和1的FAT表项应该对应于簇0和簇1,但是由于这两个表项被设置成了固定值,簇0和簇1就没有存在的意义.

  • FAT项的值代表文件的下一个簇号

    • 值为0xFF7,表示坏簇
    • 值大于或等于0xFF8,表示当前簇是本文件的最后一个簇

根目录区

  • 根目录区由目录项组成,一个目录项占32个字节。

g++与nasm混合编程

  • 环境ubuntu64,安装g++,nasm

  • my_print.asm负责输出,1.cpp为主文件

  • 1.cpp中首先声明函数

    1
    extern "C" void my_print(char *, int, int);
  • my_print.asm定义函数,注意用global my_print声明函数名。

  • 命令

    1
    2
    3
    $ nasm -f elf32 my_print.asm
    $ g++ -o fat -m32 1.cpp my_print.o
    $ ./fat

如何读取FAT12文件?

Steps

  1. 读取Boot,得到必要的参数:

    • BPB_BytsPerSec 每扇区字节数
    • BPB_SecPerClus 每簇扇区数
    • BPB_RsvdSecCnt Boot记录占用的扇区数
    • BPB_NumFATs FAT表个数
    • BPB_RootEntCnt 根目录最大文件数
    • BPB_TotSec16 FAT扇区数,如果该值为0,则BPB_FATSz32为FAT扇区数
    • BPB_HiddSec
  2. 计算每簇的字节数,每个区域的初始位置的偏移量。

    • 每簇字节数=每簇扇区数*每扇区字节数。
    • fatBase=Boot记录占用的扇区数*每扇区字节数
    • fileRootBase=(Boot记录占用的扇区数+FAT表个数* FAT扇区数)*每扇区字节数
    • dataBase=(Boot记录占用的扇区数+FAT表个数* FAT扇区数+(根目录最大文件数* 32+每扇区字节数-1)/每扇区字节数)*每扇区字节数。

    数据区的偏移量又乘又除是不是吃饱了撑的0.0?可不可以等于fileRootBase+根目录最大文件数*32?不阔以!

    dataBase初始位置=FileRootBase最后一个簇的结束位置。如果根目录没有填满最后一个簇,数据区也是从下一个簇开始的,而不是默认于最后一个根目录的结束位置开始。

    (根目录最大文件数 32+每扇区字节数-1)/每扇区字节数* 可以得到根目录区占用的真正扇区数。

  3. 广搜遍历Fat12文件系统

    • 首先读取根目录区

    • 判断文件属性

      • 目录项的属性记录了该项是文件夹or文件
      • 用DIR_Attr&0x10判断,结果为0是文件,否则为文件夹。
    • 处理文件夹

      • 得到下一层目录的数据区初始位置,首先需要FAT号。文件夹的目录项中DIR_FstClus记录了文件夹FAT号(num),其内容即为所需FAT号。

        • FAT项大小为12位。

        • 从fatBase + num * 3 / 2读取2个字节(16位)。结合存储的小尾顺序和FAT项结构可以得到。num为偶去掉高4位,num为奇去掉低4位。

        • (num & 1) ? (bytes >> 4) : (bytes & ((1 << 12) - 1))为下一个FAT号

      • 用FAT号计算在数据区中的位置。

        • startByte = dataBase + (fat号- 2) ***** BytsPerClus;
    • 处理普通文件

      • 如果文件在数据区中需要多个簇,那么用上面的办法读取数据。
    • 广搜遍历

      • 分层遍历
      • 每一层的文件夹放进队列。
      • 队列为空则停止

用文件名查询特定文件

  1. 对于目录项中的文件名做处理,去除非法字符和空格。如果是普通文件,第一个空格为‘.’。
  2. 判断文件名是否相等,strcmp等等各种方法都可。

制作FAT镜像

  1. 创建新的软盘镜像

    1
    mkfs.fat -C a.img 1440
  2. 挂载点,可以创建一个新的目录

    1
    mkdir 文件名
  3. 将镜像挂载到挂载点

    1
    sudo mount a.img 文件名
  4. 挂载后,就可以通过操作./mount文件夹,来向a.img加入和查看文件。可使用系统自带的资源管理器类似 GUI工具,或者使用命令行操作。

我的呆码👉 click me

支持ls,cat 文件名,ls -l[lll] [文件名],ls [文件名] -l[lll] .

image-20200113204622190

在这里插入图片描述

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

reference

https://blog.csdn.net/qq_39654127/article/details/88429461#main-toc

https://blog.csdn.net/judyge/article/details/52373751

https://blog.csdn.net/yxc135/article/details/8769086