android usb挂载分析---FAT文件系统原理详细介绍

2023-10-30

FAT 文件起源于 70 年代末 80 年代初,用于微软的 MS-DOS 操作系统。它开始被设计成一个简单的文件系统用于小于 500K 的软件盘。后来被功能被大大增强用于支持越来越大的媒质。现在的文件系统有 FAT12 FAT16 FAT32 三种子类。
FAT12 是最早的一版,主要用于软盘,它对簇的编址采用 12bit 宽度的数,所以称为 FAT12 12bit 的地址可以寻址 4096 个簇,事实上在 FAT12 中只能寻址 4078 个簇(在 Linux 下可寻址 4084 个簇),有一些簇号是不能用的,在后面会给出具体的说明。磁盘的扇区是用 16bit 的数进行计算的,所以磁盘的容量就被局限在 32M 空间之内。
FAT16 中,采用了 16bit 宽的簇地址, 32bit 宽扇区地址。虽然 32bit 的扇区地址可以寻址 2^32*512 ,约 2 TB 的容量, 但于由规定每簇最大的容量不超过 1024*32 ,所以 FAT16 文件系统的容量也就限制到了 2^16*1024*32 ,大约 2.1GB 的空量,并且实际还达不到这个值。
FAT32 文件系统使用了 32bit 宽的簇地址,所以称为 FAT32 。但在微软件的文件系统中只使用了低 28 位,最大容量为 2^28*1024*32, 8.7TB 的空量。有的人认为 32bit 全用,最大容量为 2^32*1024*32 ,这种说法是不正确的。
虽然 FAT32 具有容纳近乎 8.7TB 的容量,但实际应用中通常不使用超过 32GB FAT32 分区。 WIN2000 及之上的 OS 已经不直接支持对超过 32GB 的分区格式化成 FAT32 ,但 WIN98 依然可以格式化大到 127GB FAT32 分区,但不推荐这样做。
下面是一个 FAT 分区的构成概况

引导扇区
其他保留扇区(可选)
FAT 1
FAT 2
根目录区
(仅 FAT12/16
数据区
(用于文件和目录)

需要说明的是:
1 .引导扇区和其他保留扇区一起称为保留扇区,而其他保留扇区是可选的,当没有时候,引导扇区后紧跟的就是 FAT 1
2 .根目录区是仅 FAT12/16 才有, FAT32 的目录项位于数据区。由于 FAT12/16 的根目录区是一个固定的区域,所以它的根目录的项数是有限制的,意即不能在根录建立超过这个定数的目录项数。
(一)引导扇区与 BPB
BPB BIOS Parametre Block )是 FAT 文件系统中第一个重要的数据结构,它位于该 FAT 分区的第一个扇区,同时也属于 FAT 文件系统基本区域的保留区,
 
        在下面的描述中。凡名称以 BPB_ 开头的都是 BPB 的一部分,凡名称与 BS_ 开头的项都是启动扇区的一部分,而不是属于 BPB 的内容,以下是启动扇区的结构

 
offset byte
长度( byte
描述
BS_jmpBoot
0x00
3
跳转指令,指向启动代码
BS_OEMName
0x03
8
建议值为“ MSWIN4.1”。有些厂商的FAT 驱动可能会检测此项,所以设为“ MSWIN4.1”可以尽量避免兼容性的问题
BPB_BytsPerSec
0x0b
2
每扇区的字节数,取值只能是以下几种: 512 1024 2048 或是 4096 。设为 512 会取得最好的兼容性,目前有很多 FAT 代码都是硬性规定每扇区的字节数为 512 ,而不是实际的检测此值。但微软的操作系统能够很好支持 1024 2048 或是 4096
BPB_SecPerClus
0x0d
1
每簇的扇区数,其值必须中 2 的整数次方(该整数必须 >=0 ),同时还要保证每簇的字节数不能超过 32K ,也就是 1024*32 字节
BPB_RsvdSecCnt
0x0e
2
保留扇区的数目,此域不能为 0 FAT12/FAT16 必须为 1 FAT32 的典型值取为 32 ,,微软的系统支持任何非 0
BPB_BumFATs
0x10
1
分区中 FAT 表的份数,,任何 FAT 格式都建议为 2
BPB_RootEntCnt
0x11
2
对于 FAT12 FAT16 此域包含根目录中目录的个数(每项长度为 32bytes ),对于 FAT32 ,此项必须为 0 。对于 FAT12 FAT16 ,此数乘以 32 必为 BPB_BytesPerSec 的偶数倍,为了达到更好的兼容性, FAT12 FAT16 都应该取值为 512
BPB_ToSec16
0x13
2
早期版本中 16bit 的总扇区,这里总扇区数包括 FAT 卷上四个基本分区的全部扇区,此域可以为 0 ,若此域为 0 ,那么 BPB_ToSec32 必须为 0 ,对于 FAT32 ,此域必为 0 。对于 FAT12/FAT16 ,此域填写总扇区数,如果该值小于 0x10000 的话, BPB_ToSec32 必须为 0
BPB_Media
0x15
1
对于“固定”(不可移动)存储介质而言, 0xF8 是标准值,对于可移动存储介质,经常使用的数值是 0xF0 ,此域合法的取值可以取 0xF0,0xF8,0xF9,0xFA,0xFC,0xFD,0xFE,0xFF 。另外要提醒的是,无沦此域写入什么数值,同时也必须在 FAT[0] 的低字节写入相同的值,这是因为早期的 MSDOS 1.x 使用该字节来判定是何种存储介质
BPB_FATz16
0x16
2
FAT12/FAT16 一个 FAT 表所占的扇区数,对于 FAT32 来说此域必须为 0 ,在 BPB_FATZ32 中有指定 FAT 表的大小
BPB_SecPerTrk
0x18
2
每磁道的扇区数,用于 BIOS 中断 0x13 ,此域只对于有“特殊形状”(由磁头和柱面每分割为若干磁道)的存储介质有效,同时必须可以调用 BIOS 0x13 中断得到此数值
BPB_NumHeads
0x1A
2
磁头数,用于 BIOS 0x13 中断,类似于上面的 BPB_ SecPerTrk ,只对特殊的介质才有效,此域包含一个至少为 1 的数值,比如 1,4M 的软盘此域为 2
BPB_HidSec
0x1C
4
在此 FAT 分区之前所隐藏的扇区数,必须使得调用 BIOS 0x13 中断可以得到此数值,对于那些没有分区的存储介质,此域必须为 0 ,具体使用什么值由操作系统决定
BPB_ToSec32
0x20
4
该卷总扇区数( 32bit ),这里的扇区总数包括 FAT 卷四个个基本分的全部扇区,此域可以为 0 ,若此域为 0 BPB_ToSec16 必须为非 0 ,对 FAT32 ,此域必须是非 0 。对于 FAT12/FAT16 如果总扇区数大于或等于 0x10000 的话,此域就是扇区总数,同时 BPB_ToSec16 的值为 0

FAT32 BPB 的内容和 FAT12/16 的内容在地址 36 以前是完全一样的,从偏移量 36 开始,他们的内容有所区别,具体的内容要看 FAT 类型为 FAT12/16 还是 FAT32 ,这点保证了在启动扇区中包含一个完整的 FAT12/16 FAT32 BPB 的内容,这么做是为了达到最好的兼容性,同时也为了保证所有的 FAT 文件系统驱动程序能正确的识别和驱动不同的 FAT 格式,并让他们良好地工作,因为他们包含了现有的全部内容
offset 36 开始 FAT12/FAT16 的内容开始区别于 FAT32 ,下面分两个表格列出,下表为 FAT12/FAT16 的内容

名称
offset byte
长度( byte
描述
BS_drvNum
0x24
1
用于 BIOS 中断 0x13 得到磁盘驱动器参数,( 0x00 为软盘, 0x80 为硬盘)。此域实际上由操作系统决定
BS_Reseved1
0x25
1
保留(供 NT 使用),格式化 FAT 卷时必须设为 0
BS_VolID
0x26
1
扩展引导标记( 0x29 )用于指明此后的 3 个域可用
BS_BootSig
0x27
4
卷标序列号,此域以 BS_VolLab 一起可以用来检测磁盘是否正确, FAT 文件系统可以用此判断连接的可移动磁盘是否正确,引域往往是由时间和日期组成的一个 32 位的值
BS_VolLab
0x2B
11
磁盘卷标,此域必须与根目录中 11 字节长的卷标一致。
FAT 文件系统必须保证在根目录的卷标文件列改或是创建的同时,此域的内容能得到时的更新,当 FAT 卷没有卷标时,此域的内容为“ NO NAME
BS_FilSysType
0x36
8
以下的几种之一:“ FAT12 ”,“ FAT16 ”,“ FAT32
不少人错误的认为 FAT 文件系统的类型由此域来确认,他细点你就能发现此域并不是 BPB 的一部分,只是一个字符串而已,微软的操作系统并不使用此此域来确定 FAT 文件的类型,;因为它常常被写错或是根本就不存在。

 
下表为 FAT32 的内容

名称
offset byte
长度( byte
描述
BPB_FATSz32
0x24
4
一个 FAT 表所占的扇区数,此域为 FAT32 特有,同时 BPB_FATSz16 必须为 0
BPB_Flags
0x28
2
此域 FAT32 特有。
Bits0-3: 不小于 0 FAT active FAT )数目,只有在镜像( mirrorig )禁止时才有效。
Bits 4-6:  保留
Bits 7  0 表示 FAT 实时镜像到所有的 FAT 表中
        1  表示只有一个活动的 FAT 表。这个表就是 Bits0-3 所指定的那个
Bits8-15 保留
BPB_FSVer
0x2A
2
此域为 FAT32 特有,
高位为 FAT32 的主版本号,低位为次版本号,这个版本号是为了以后更高级的 FAT 版本考虑,假设当前的操作系统只能支持的 FAT32 版本号为 0.0 。那么该操作系统检测到此域不为 0 时,它便会忽略 FAT 卷,因为它的版本号比系统能支持的版式本要高
BPB_RootClus
0x2C
4
根目录所在第一个簇的簇号,通常该数值为 2 ,但不是必须为 2
磁盘工具在改变根目录位置时,必须想办法让磁盘上第一个非坏簇作为根目录的第一个簇(比如第 2 簇,除非它已经被标记为坏簇),这样的话,如果此域正好为 0 的话磁盘检测工具也能轻松的找到根目录所在簇的位置
BPB_FSIfo
0x30
2
保留区中 FAT32 FSINFO 结构所占的扇区数,通常为 1
Backup Boot  中会有一个 FSINFO 的备份,但该备份只是更新其中的指针,也就是说无论是主引导记录还是备份引导记录都是指向同一个 FSINFO 结构
BPB__BkBootSec
0x32
2
如果不为 0 ,表示在保留区中引导记录的备数据所占的扇区数,通常为 6 。同时不建议使用 6 以外的其他数值
BPB_Reserved
0x34
12
用于以后 FAT 扩展使用,对 FAT32 。此域用 0 填充
BS_DrvNum
0x40
1
FAT12/16 的定义相同,只不过两者位于启动扇区不同的位置而已
BS_Reserved1
0x41
1
FAT12/16 的定义相同,只不过两者位于启动扇区不同的位置而已
BS_BootSig
0x42
1
FAT12/16 的定义相同,只不过两者位于启动扇区不同的位置而已
BS_VolID
0x43
4
FAT12/16 的定义相同,只不过两者位于启动扇区不同的位置而已
BS_FilSysType
0x47
11
FAT12/16 的定义相同,只不过两者位于启动扇区不同的位置而已
BS_FilSysType
0x52
8
通常设置为“ FAT32 ”,请参照 FAT12/16 此部分的陈述。

关于 FAT 启动扇区还有一点重要的说明,我们假设里面的内容是按字节排序的,那么扇区 [510] 的内容一定 0x55 ,扇区 [511] 的内容一定是 0xAA
很多 FAT 资数文档会把 0xAA55 说成是“启动扇区最后两字节的内容”,这样的陈述是正确的 仅仅是如果 —BPB_BytsPerSec 的值为 512 的话。若 BPB_BytsSec 的值大于 512 ,该标记的位置并没有改变(虽然在启动扇区的最后两个字节写 0xAA55 并没有问题)
关于 BPB_ToSec16/32 这里再作一点补充:假设一现在我们有一块磁盘或一个分区,它的扇区数为 DskSz ,如果 BPB_aToSec(BPB_ToSec16 或是 BPB_ToSec32 基中不为 0 的那个 ) 的值小于或等于 DskSz 并不会使该 FAT 卷在使用中出现什么错误,实际上 BPB_ToSec16/32 的值不要比 DskSz 小得离谱就不会有什么错误
这样做将造成磁盘空间的浪费,程序本身并不会认为该 FAT 卷存在什么错误,但是,如果 BPB_ToSec16/32 的值比 DskSz 大将会使 FAT 卷遭到严重的损坏,因为它超出了存储介质或是磁盘分区的边界。当 BPB_ToSec16/32 的值比 DskSz 大时,一些数据将不幸地被丢失
   
FAT文件系统数据结构C语言表示
FAT文件系统相关数据结构
struct fat_boot_sector {
    uint8_t    ignored[3];    /* 0x00 Boot strap short or near jump */
    int8_t    system_id[8];    /* 0x03 Name - can be used to special case
                   partition manager volumes */
    uint8_t    sector_size[2];    /* 0x0B bytes per logical sector */
    uint8_t    sectors_per_cluster;    /* 0x0D sectors/cluster */
    uint16_t    reserved;    /* 0x0E reserved sectors */
    uint8_t    fats;        /* 0x10 number of FATs */
    uint8_t    dir_entries[2];    /* 0x11 root directory entries */
    uint8_t    sectors[2];    /* 0x13 number of sectors */
    uint8_t    media;        /* 0x15 media code (unused) */
    uint16_t    fat_length;    /* 0x16 sectors/FAT */
    uint16_t    secs_track;    /* 0x18 sectors per track */
    uint16_t    heads;        /* 0x1A number of heads */
    uint32_t    hidden;        /* 0x1C hidden sectors (unused) */
    uint32_t    total_sect;    /* 0x20 number of sectors (if sectors == 0) */

    /* The following fields are only used by FAT32 */
    uint32_t    fat32_length;    /* 0x24=36 sectors/FAT */
    uint16_t    flags;        /* 0x28 bit 8: fat mirroring, low 4: active fat */
    uint8_t    version[2];    /* 0x2A major, minor filesystem version */
    uint32_t    root_cluster;    /* 0x2C first cluster in root directory */
    uint16_t    info_sector;    /* 0x30 filesystem info sector */
    uint16_t    backup_boot;    /* 0x32 backup boot sector */
    uint8_t    BPB_Reserved[12];    /* 0x34 Unused */
    uint8_t    BS_DrvNum;        /* 0x40 */
    uint8_t    BS_Reserved1;        /* 0x41 */
    uint8_t    BS_BootSig;        /* 0x42 */
    uint8_t    BS_VolID[4];        /* 0x43 */
    uint8_t    BS_VolLab[11];        /* 0x47 */
    uint8_t    BS_FilSysType[8];    /* 0x52=82*/

    /* */
    uint8_t    nothing[420];    /* 0x5A */
    uint16_t    marker;
} __attribute__ ((__packed__));

struct msdos_dir_entry {
    int8_t    name[8],ext[3];        /* 00 name and extension */
    uint8_t    attr;            /* 0B attribute bits */
    uint8_t    lcase;        /* 0C Case for base and extension */
    uint8_t            ctime_ms;    /* 0D Creation time, milliseconds */
    uint16_t    ctime;        /* 0E Creation time */
    uint16_t    cdate;        /* 10 Creation date */
    uint16_t    adate;        /* 12 Last access date */
    uint16_t        starthi;    /* 14 High 16 bits of cluster in FAT32 */
    uint16_t    time;           /* 16 time, date and first cluster */
        uint16_t        date;        /* 18 */
        uint16_t        start;        /* 1A */
    uint32_t    size;        /* 1C file size (in bytes) */
};

/* Up to 13 characters of the name */
struct msdos_dir_slot {
    uint8_t    id;            /* 00 sequence number for slot */
    uint8_t    name0_4[10];        /* 01 first 5 characters in name */
    uint8_t    attr;        /* 0B attribute byte */
    uint8_t    reserved;        /* 0C always 0 */
    uint8_t    alias_checksum;    /* 0D checksum for 8.3 alias */
    uint8_t    name5_10[12];    /* 0E 6 more characters in name */
    uint16_t   start;        /* 1A starting cluster number, 0 in long slots */
    uint8_t    name11_12[4];    /* 1C last 2 characters in name */
};
具体可以参考下面的资料:http://download.csdn.net/detail/new_abc/4184969

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

android usb挂载分析---FAT文件系统原理详细介绍 的相关文章

  • 排序:计数排序

    一 概念 计数排序是非比较排序 是对哈希直接定址法的变形应用 二 思想 利用数组统计相同数据出现的次数 例如整型数据m出现n次 就在数组m位置记录数据为n 最后从头遍历数组打印数据即可 通俗来讲就是 数组下标即为数据 下标所指位置的值即为数
  • 数据结构——排序

    前言 哈喽小伙伴们好久不见 也是顺利的考完试迎来了寒假 众所周知 不怕同学是学霸 就怕学霸放寒假 假期身为弯道超车的最佳时间 我们定然是不能懒散的度过 今天我们就一起来学习数据结构初阶的终章 七大排序 本文所有的排序演示都为升序排序 目录
  • 在 PyQt 中显示图像(以字节为单位)

    我需要知道如何在 GUI 中以字节为单位显示图像 我正在使用 content 从 google 静态地图 API 获取图像 我得到的图像以字节为单位 如下所示 import requests a requests get https map
  • 高精度运算合集,加减乘除,快速幂,详细代码,OJ链接

    文章目录 零 前言 一 加法 高精度加法步骤 P1601 A B 二 减法 高精度减法步骤
  • 如何以最有效的方式将图像转换为字符串?

    我想将图像文件转换为字符串 以下作品 MemoryStream ms new MemoryStream Image1 Save ms ImageFormat Jpeg byte picture ms ToArray string formm
  • C#:无法从 ulong 转换为 byte

    奇怪的是我可以在 C 中做到这一点 但在 C 中却不行 为了清楚起见 我将在 C 中粘贴这两个函数 然后在 C 中粘贴 并使用注释 error 标记 C 代码中有问题的行 这两个函数的作用是对参数进行编码 然后将其添加到名为 byte1se
  • Java 中的有符号字节类型和按位运算符?

    引用自甲骨文网站 http docs oracle com javase tutorial java nutsandbolts datatypes html byte 字节数据类型是8位带符号的二进制补码整数 最小值为 128 最大值为12
  • 在 C/C++ 中读/写半字节(无位字段)

    有没有一种简单的方法可以在不使用位字段的情况下读取 写入字节中的半字节 我总是需要读取两个半字节 但需要单独写入每个半字节 Thanks 使用面膜 char byte byte byte 0xF0 nibble1 0xF write low
  • Java Byte.parseByte() 错误

    我的代码中有一个小错误 我一生都无法弄清楚 我有一个字符串数组 它们是二进制数据的表示 从十六进制转换后 例如 一个索引是 1011 另一个索引是 11100 我遍历数组并用 0 填充每个索引 以便每个索引都是八个字节 当我尝试将这些表示形
  • c 获取整数的第n个字节

    我知道你可以通过使用获得第一个字节 int x number 1 lt lt 8 1 or int x number 0xFF 但我不知道如何获取整数的第 n 个字节 例如 1234 为 32 位整数 00000000 00000000 0
  • 字符串到二进制,反之亦然:扩展 ASCII

    我想通过将字符串放入字节数组中将其转换为二进制 String getBytes 然后存储每个字节的二进制字符串 Integer toBinaryString bytearray 在 String 中 然后我想通过转换回普通字符串Byte p
  • 如果 xmlcharrefreplace 和 backslashreplace 不起作用,我应该如何解码字节(使用 ASCII)而不丢失任何“垃圾”字节?

    我有一个网络资源 它返回给我的数据 根据规范 应该是 ASCII 编码的字符串 但在极少数情况下 我会收到垃圾数据 例如返回一种资源b xd3PS 90AC 而另一个资源 对于相同的键返回b PS 90AC 第一个值包含非 ASCII 字符
  • 使用 Java 将十六进制转储的字符串表示形式转换为字节数组?

    我正在寻找一种将表示十六进制值的长字符串 来自转储 转换为字节数组的方法 我无法比发帖者更好地表达它同样的问题在这里 http www experts exchange com Programming Programming Languag
  • Java NIO ByteBuffer,翻转后写入

    我是 Java ByteBuffers 的新手 想知道翻转后写入 ByteBuffer 的正确方法是什么 在我的用例中 我将一个输出缓冲区写入套接字 outBuffer flip Non blocking SocketChannel int
  • 缓冲区的字节大小(Javascript / Node)[重复]

    这个问题在这里已经有答案了 如何在 JavaScript 中获取缓冲图像的大小 以字节为单位 我不允许信任客户端的文件大小 并且需要在后端进行验证作为上传验证的一部分 我的设置如下 1 我在客户端上传一个文件并将其从 React 组件发送到
  • 使用十六进制数初始化无符号字节数组

    我知道无符号字节缺失于Java那么如何使用整数初始化字节数组0 到 255 十六进制 final byte assoc resp msg int new byte 0xe3 0x00 APDU CHOICE Type AareApdu 0x
  • 如何知道一个字符有多少字节?

    我想知道如何找出一个字符有多少字节 如果你想知道 PHP 字符串中的一个字母有多少个 UTF 8 字节 那么 print strlen mb substr string 0 1 utf 8 strlen 返回原始字节长度 而mb subst
  • 为什么java没有byte类型后缀? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 使用字节将字母数字代码解码为键值对象

    我有一个来自 CS GO 游戏的 十字准线代码 CSGO O4Jsi V36wY rTMGK 9w7qF jQ8WB 我可以使用此函数解码一些值 import BigNumber from bignumber js Intentionall
  • 如何将 BYTE 数组转换为 char 数组以使用套接字 C++ 发送

    我有一些问题 我编写客户端服务器应用程序 其中使用 win 套接字发送和接收信息 在我的项目中需要发送BYTE数组到客户端 并在客户端上将此 char 数组转换为BYTE 我该如何创建它 请帮助我 因为send 函数只能发送char 谢谢

随机推荐