【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)了解 FAT32 文件系统的具体工作原理 fat32

大家好,欢迎来到IT知识分享网。

 1、前言

        本篇文章主要是介绍FAT格式分区数据在硬盘中是如何存储的,FAT分区格式是Microsoft最早支持的分区格式,依据FAT 表中每个簇链的所占位数(有关概念,后面会讲到)分为FAT12FAT16FAT32 三种格式”变种”,但其基本存储方式是相似的。我们在嵌入式系统中使用的最多是FAT32,所以后面主要介绍的是FAT32。

2、FAT文件系统结构

        FAT文件系统结构图如下所示:

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

2.1 主引导扇区(MBR)

        主引导扇区:硬盘的第一个扇区,由主引导记录(MBR)+ 主分区表(DPT)+ 引导扇区标记(Boot Record ID / Signature)组成,该区域是完成系统BIOS向操作系统交接的重要入口。该扇区在进行硬盘分区时产生。

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

        主引导扇区组成

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

        其中的MBR具体内容我们暂时不需要关心,重点要关心硬盘分区表DPT的数据,即上图中红色划线部分(重点关注蓝色和绿色方框数据),其各个字节表示的作用如下:

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

        对于常见硬盘来说,我们主要关注相对扇区数和总扇区数的值,结合原始数据和分区表含义可以得到重点数据:

1、相对扇区数:保留区1 N扇区 = 0x800 = 2048扇区,也可以得到DBR的地址 = 2048*512 = 0x10 0000 Bytes。

 2、总扇区数:对于只有一个分区的U盘来说,该数据表示分区卷的总容量(不包含相对扇区数)

2.2 操作系统引导扇区(DBR)

        操作系统引导扇区DBR,也称为引导扇区。包含BIOS参数块,该参数块存储有关卷布局和文件系统结构的信息,以及加载windows的引导代码(暂时不需要关心引导代码)。

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

        下面的示例演示了FAT32卷上引导扇区的十六进制数据:

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

下面两个表说明了FAT32卷的BPB和拓展BPB的布局,示例值对应FAT32卷上引导扇区的数据。

FAT32分区的BPB字段
字节位移

字段长度

(字节)

对应取值 名称和定义
0x0B 2 0x0200 扇区字节数(Bytes Per Sector) 硬件扇区的大小。
本字段合法的十进制值有 512、1024、2048 和 4096。对大多数磁盘来说,本字段的值为
512
0x0D 1 0x10 每簇扇区数(Sectors Per Cluster),一簇中的扇区数。
一个卷默认的簇大小取决于该卷的大小。本字段的合法十进制值有 1、2、4、8、16、32、64 和 128。
0x0E 2 0x0C80

保留扇区数(Reserved Sector) 第一个 FAT 开始之前的扇区数,包括引导扇区。

(相当于保留区2)

0x10 1 0x02 FAT 数(Number of FAT) 该分区上 FAT 表的个数。本字段的值一般为 2
0x11 2 0x0000 根目录项数(Root Entries) 只有 FAT12/FAT16 使用此字段。对 FAT32 分区而言,本字段必须设置为 0
0x13 2 0x0000 小扇区数(Small Sector) (只有 FAT12/FAT16 使用此字段)对 FAT32 分区而言,本字段必须设置为 0
0x15 1 0xF8 媒体描述符( Media Descriptor) 提供有关媒体被使用的信息。值 0xF8 表示硬盘,0xF0 表示高密度的 3.5寸软盘。
0x16 2 0x0000 每 FAT 扇区数(Sectors Per FAT) 只被 FAT12/FAT16 所使用,对 FAT32 分区而言,本字段必须设置为 0
0x18 2 0x003F 每道扇区数(Sectors Per Track) 包含使用 INT 13h 的磁盘的“每道扇区数”几何结构值。
该分区被多个磁头的柱面分成了多个磁道
0x1A 2 0x00FF 磁头数(Number of Head) 本字段包含使用 INT 13h 的磁盘的“磁头数”几何结构值。
0x1C 4 0x00000800

隐藏扇区数(Hidden Sector) 该分区上引导扇区之前的扇区数。在引导序列计算到根目录的数据区的绝对位移的
过程中使用了该值。本字段一般只对那些在中断 13h 上可见的媒体有意义。在没有分区的媒体上它必须总是为 0

(相当于保留区1)

0x20 4 0x01CE7800 总扇区数(Large Sector) 本字段表示FAT32分区(不包含保留区1)中总的扇区数
0x24 4 0x000039C0 每 FAT 扇区数(Sectors Per FAT) (只被 FAT32 使用)该分区每个 FAT 所占的扇区数。计算机利用这个数和 FAT
数以及保留扇区数(本表中所描述的)来决定根目录从哪里开始。该计算机还可以从目录中的项数决定该分区的
用户数据区从哪里开始

0x28 2 0x0000

扩展标志(Extended Flag) (只被 FAT32 使用)该两个字节结构中各位的值为:
位 0-3:活动 FAT 数(从 0 开始计数,而不是 1).只有在不使用镜像时才有效
位 4-6:保留

位 7:0值意味着在运行时FAT被映射到所有的FAT,1值表示只有一个 FAT是活动的
位 8-15:保留

0x2A 2 0x0000 文件系统版本(File ystem Version) 只供 FAT32 使用,高字节是主要的修订号,而低字节是次要的修订号。
本字段支持将来对该 FAT32 媒体类型进行扩展。
0x2C 4 0x00000002 根目录簇号(Root Cluster Number) (只供 FAT32 使用) 根目录第一簇在FAT表的簇号。
本字段的值一般为 2,但不总是如此
0x30 2 0x0001

 文件系统信息扇区号(File System Information Sector Number) (只供 FAT32 使用)FAT32 分区的保留区中的文件系统信息(File System Information, FSINFO)结构的扇区号。其值一般为 1。在备份引导扇区(Backup
Boot Sector)中保留了该 FSINFO 结构的一个副本,但是这个副本不保持更新

0x32 2 0x0006 备份引导扇区(Backup Boot Sector) 非“0”表示存储引导扇区副本的扇区号。该字段的值通常为6。
0x34 12 12 个字节均为 0x00 保留(Reserved) (只供 FAT32 使用)供以后扩充使用的保留空间。本字段的值总为 0
FAT32分区的拓展BPB字段
字节位移

字段长度

(字节)

对应取值 名称和定义
0x40 1 0x80 物理驱动器号( Physical Drive Number) 与 BIOS 物理驱动器号有关。软盘驱动器被标识为 0x00,物理硬盘被标识为 0x80,而与物理磁盘驱动器无关。一般地,在发出一个 INT13hBIOS 调用之前设置该值,具体指定所访问的设备。只有当该设备是一个引导设备时,这个值才有意义
0x41 1 0x00 保留(Reserved) FAT32 分区总是将本字段的值设置为 0
0x42 1 0x29 扩展引导标签(Extended Boot Signature) 本字段必须要有能被 Windows 2000 所识别的值 0x28 或 0x29
0x43 4 0xB2DC3889 分区序号(Volume Serial Number) 在格式化磁盘时所产生的一个随机序号,它有助于区分磁盘
0x47 11 “NO NAME    “(ASCII编码) 卷标(Volume Label) 本字段只能使用一次,它被用来保存卷标号。现在,卷标被作为一个特殊文件保存在根目录中
0x52 8 “FAT32   “(ASCII编码) 系统 ID(System ID) FAT32文件系统中一般取为”FAT32″

BPB对我们比较重要的数据已经用蓝色标记出来了,可以了解到:

  • 扇区字节数和每簇扇区数

        硬件扇区的大小为512Bytes,每个簇占用扇区数为16个扇区。

  • 总扇区数

        该数据只表示分区卷所占用的扇区数,即 保留区2 + 文件分区表 + 数据区,不包含保留区1,所以要计算U盘总容量需要加上隐藏扇区(即保留区1)的大小,即:

      总容量=总扇区数+隐藏扇区:( 0x01CE7800+0x800 ) * 512 = 15,518,924,800 Bytes。

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

  • FAT开始地址

       我们可以通过保留扇区数+ 隐藏扇区找到FAT表的起始位置:(0xC80+0x800 ) * 512 = 0x Bytes。

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

  • 根目录开始地址

        根目录开始地址 = (隐藏扇区 + 保留扇区 +  每FAT扇区数 * FAT数 )* 扇区字节数

                                  =  ( 0x800 + 0xC80 + 0x39C0 * 2)* 512 Bytes = 0x Bytes

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

2.3 FSINFO信息扇区

        FAT32在保留区2中中增加了一个FSINFO信息扇区,用以记录文件系统中空闲簇的数量以及下一个可用簇的簇号等信息,以供操作系统作为参考。FSINFO信息扇区一般位于文件系统的1号扇区。(此处是逻辑上,而非物理上的1号扇区!!),

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

内容划分如下:

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

 2.4 FAT32根目录(Root Folder)

        为了更好的理解FAT表,我们需要先讲一下根目录。

        根文件夹描述根分区中的文件和文件夹。目录所在的扇区,都是以32Byte为一个单位划分的,每个单位称为一个目录项。根目录由若干个目录项组成。目录项有两种格式:短文件格式长文件格式

2.4.1 短文件格式

        1、对于短文件名,系统将文件名分成两部分进行存储,即主文件名+扩展名。0x0~0x7字节记录文件的主文件名,0x8~0xA记录文件的扩展名,取文件名中的ASCII码值。不记录主文件名与扩展名之间的"."主文件名不足 8 个字符以空白符(20H)填充,扩展名不足 3 个字符同样以空白符(20H)填充。0x00 偏移处的取值若为 00H,表明目录项为空;若为E5H,表明目录项曾被使用,但对应的文件或文件夹已被删除。(这也是误删除后恢复的理论依据)。文件名中的第一个字符若为“.”“..”表示这个簇记录的是一个子目录的目录项。“.”代表当前目录“..”代表上级目录

        2、0xB的属性字段:可以看作系统将 0xB的一个字节分成 8 位,用其中的一位代表某种属性的有或无。如 00000101 就表示这是个文件,属性是只读、系统。

        3、0x0E~0x0F文件创建时间字段

        Bit 0~4:为文件创建时间字段秒/2的值;
        Bit 5~10:为文件创建时间字段分钟的值;
        Bit 11~15:为文件创建时间字段小时的值;

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

        4、0x10~0x11文件创建日期字段

        Bit 0~4:为文件创建日期字段日期数的值;
        Bit 5~8:为文件创建日期字段月份的值;
        Bit 9~15:为文件创建时间字段年号-1980的值

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

        5、普通子目录的寻址过程也是通过其父目录中的目录项来指定的,与数据文件(指非目录文件)不同的是目录项偏移 0xB的第 4 位置 1,而数据文件0

        具体FAT32短文件格式表格如下:

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

2.4.2 长文件格式

        FAT32 的一个重要的特点是完全支持长文件名。长文件名依然是记录在目录项中的。为了低版本的 OS 或程序能正确读取长文件名文件,系统自动为所有长文件名文件创建了一个对应的短文件名,使 对应数据既可以用长文件名寻址,也可以用短文件名寻址。不支持长文件名的 OS 或程序会忽略它认为不合法的长文件名字段,而支持长文件名的 OS 或程序则会以长文件名为显式项来记录和编辑,并隐藏起短文件名。
        当创建一个长文件名文件时,系统会自动加上对应的短文件名,其一般有的原则:

  1. 取长文件名的前 6 个字符加上"~1"形成短文件名,扩展名不变。
  2. 如果已存在这个文件名,则符号"~"后的数字递增,直到 5
  3. 如果文件名中~后面的数字达到 5,则短文件名只使用长文件名的前两个字母。通过数学操纵长文件名的剩余字母生成短文件名的后四个字母,然后加后缀~1直到最后。
  4. 如果存在老 OS 或程序无法读取的字符,换以"_"。

        长文件名的实现有赖于目录项偏移为 0xB 的属性字节,当此字节的属性为:只读、隐藏、系统、卷标,即其值为 0FH 时,DOS 和 WIN32 会认为其不合法而忽略其存在。系统将长文件名以 13 个字符为单位进行切割,每一组占据一个目录项。所以可能一个文件需要多个目录项,这时长文件名的 各个目录项按倒序排列在目录表中,以防与其他文件名混淆。长文件名中的字符采用 unicode 形式编码,每个字符占据 2 字节的空间。

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

 注意:系统在存储长文件名时,总是先按倒序填充长文件名目录项,然后紧跟其对应的短文件名。从以上的表格可以看出,长文件名中并不存储对应文件的文件开始簇、文件大小、各种时间和日期属性。文件的这些属性还是存放在短文件名目录项中,一个长文件名总是和其相应的短文件名一 一对应,短文件名没有了长文件名还可以读,但长文件名如果没有对应的短文件名,不管什么系统都将忽略其存在。所以短文件名是至关重要的。

 2.4.3 实例解析

        由于根目录和子目录在目录项上有一点区别,所以在此处对其分开讲解。

根目录

        我们对U盘进行格式化后,在根目录下新建文件结构。     

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

        在winhex查看:

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

        可以看到,两者有一点区别,在winhex多了一部分文件夹和文件:新建文件夹和新建文本文档。不必担心,这是由于电脑在创建如”001.txt“文件时,会先创建”新建文件文本文档.txt“,然后如果在你修改文件名时,操作系统会把原来的文件删除,然后才创建新的文件

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

        下面通过实例:文件夹:System Volume Information来解析里面的数据,如下:

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

        通过上面实例表格可了解到重要信息总结如下:

        文件名称和属性

                文件名System Volume Information

                属性目录、系统、隐藏

        文件创建时间

                文件创建时间为0x73B8,按照前面介绍的公式解析时间为14:29:48,解析过程如下:

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

        文件创建日期

                文件创建日期为0x5908,按照前面介绍的公式解析时间为2024/08/08,解析过程如下:

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

        文件起始簇号

                文件起始簇号的值为0x00000003,说明该文件的起始地址为:

                文件地址 =  根目录地址 + (文件起始簇号 -根目录簇号)* 每簇扇区数 * 扇区字节数

                                = 0x + (3 – 2)*16 * 512 = 0x Byte

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

子目录

        根目录文件夹和子目录文件夹在目录项组成上有一点区别,所以需要单独拿出来讲一讲,我们继续以前面讲的System Volume Information为例,我们可以看到该文件夹中目录项组成如下:

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

         可以明显的看到,相比于根目录,子目录中多了当前目录和上一级目录的目录项,其他组成基本一致。我们可以通过各目录项的起始簇号跳转到对应文件位置。

        注意:如果上一级目录是根目录时,其文件起始簇有点特殊,值为0x00000000。我们以test_dir_文件夹里面新建文件夹hello文件夹和hello.txt为例:

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

        我们可以明显看到,该示例中文件夹簇号链:根目录(0x00000000)-》test_dir_(0x00000006)-》hello文件夹(0x0000001C)

文件

        最后我们来讲一讲文件目录项,以根目录下的001.txt为例:

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

        可以看到文件的起始簇号为0x00000008,按照之前的计算公式可以得到文件地址为0x110C000,跳转到该地址可以看到文件内容:

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

 

 2.5 FAT表

        FAT表记录了磁盘数据文件的存储链表,对于数据的读取而言是极其重要的,以至于Microsoft为其开发的FAT文件系统中的FAT表创建了一份备份,就是我们看到的FAT2。FAT2 与FAT1 的内容通常是即时同步的,也就是说如果通过正常的系统读写对FAT1 做了更改,那么FAT2 也同样被更新。

        FAT表工作的原理:当存储一个大的文件时,会以为单位拆分成多个簇存放在磁盘,它们的存放的簇号并不一定是连续的,所以这里用到了FAT表,将该文件所用到的簇号串联起来。

        例如截图如下,绿色的部分为存储文件的数据,FAT表查询顺序如下:

        1、从根目录(Root folder)找到该文件的起始簇号 12,并且读取簇号 12地址的文件数据。

        2、从FAT表中,找到簇号12存放的下一个簇号为13,并且读取簇号 13地址的文件数据。以此类推到簇号65。

        3、从FAT表中,找到簇号65存放的下一个簇号为87,并且读取簇号 87地址的文件数据。下一次FAT表查询直接从簇号65跳转到簇号 87

        4、经过上面的连续查询FAT,直到读取FF标记,代表文件读取完成。

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

        我们通过之前获取到的地址0x查看FAT表数据,如下:

        

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

        内容解析:

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

        接下来我们以 根目录文件:stm32l4xx_hal_spi.c为例来介绍FAT表的使用:

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

        文件起始簇号:

                文件起始簇号为0x0000000C,说明该文件的起始地址为:

                文件地址 =  根目录地址 + (文件起始簇号 -根目录簇号)* 每簇扇区数 * 扇区字节数

                                = 0x + (12 – 2)*16 * 512 = 0x Byte

                可以看到在该位置处果然找到了文件内容。

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

       文件大小:

                文件大小为0x24D95(150,933),在winhex中可以查看到文件大小确实是

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

 注意:系统读取磁盘的单位以簇为单位,存放数据不满一簇时也将占用这整个簇(其他文件也无法使用该簇多余的空间),如下:

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

        文件内容为12字节,但是不满1簇,系统读取时还是读一簇的数据(16*512 = 8192 Byte)。

         读取完文件起始簇号存放的文件数据后,就查询下一个簇号存放数据。 FAT表以簇为单位,标识分区中空间的使用情况(每个标识占4字节)。FAT前2簇为保留簇(簇0和簇1),不分配给文件使用,其内容含义如下所示:

  • FAT16:F8 FF FF FF
  • FAT32:F8 FF FF 0F FF FF FF FF

        一个FAT表项值表明了文件占用的一个簇号并指明下一簇号的位置,说明读取完簇号0x0C(12)后读下一个簇号0x0D(13),结合FAT表数据可以知道,文件的簇号链接为:

12 -> 13 -> 14 ->15 -> 16 ->17 ->18 -> 19 ->20 ->21 ->22 ->23 ->24 ->25 ->26 -> 27 -> 28 -> 29 -> 30

         FAT表按顺序依次记录了该盘各簇的使用情况,是一种位示图法。每簇的使用情况用32位二进制填写,未被分配的簇相应位置写;坏簇相应位置填入特定值;已分配的簇相应位置填入非零值,具体为:如果该簇是文件的最后一簇,填入的值为FFFFFF0FH(即0x0FFFFFFF),如果该簇不是文件的最后一簇,填入的值为该文件占用的下一个簇的簇号,这样,正好将文件占用的各簇构成一个簇链,保存在FAT表中。0000000H、00000001H两簇号不使用,其对应的两个DWORD位置(FAT表开头的8个字节)用来存放该盘介质类型编号。

        FAT表的大小就由该逻辑盘数据区共有多少簇所决定,取整数个扇区。

        当文件系统被创建,也就是进行格式化操作时,分配给FAT区域的空间将会被清空,在FAT1与FAT20号表项1号表项写入特定值。由于创建文件系统的同时也会创建根目录,也就是为根目录分配了一个簇空间,通常为2号簇,所以2号簇所对应的2号FAT表项也会被写入一个结束标记,如上图所示。

        如果某个簇存在坏扇区,则整个簇会用FAT表项值0xFFFFFF7标记为坏簇,不再使用,这个坏簇标记就记录在它所对应的FAT表项中。

        在文件系统中新建文件时,如果新建的文件只占用一个簇,为其分配的簇对应的FAT表项将会写入结束标记。如果新建的文件不只占用一个簇,则在其所占用的每个簇对应的FAT表项中写入为其分配的下一簇的簇号,在最后一个簇对应的FAT表象中写入结束标记。

        新建目录时,只为其分配一个簇的空间,对应的FAT表项中写入结束标记。当目录增大超出一个簇的大小时,将会在空闲空间中继续为其分配一个簇,并在FAT表中为其建立FAT表链以描述它所占用的簇情况。

        对文件或目录进行操作时,他们所对应的FAT表项将会被清空,设置为0以表示其所对应的簇处于未分配状态。

3、winhex的使用手册

        我们在分析FAT32文件系统时,需要用到winhex工具查看磁盘上的原始数据,操作流程如下:

        3.1 WinHex工具下载安装

              下载链接:https://www.x-ways.net/winhex/index-m.html

               安装完成后的工具图标如下所示:

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

        3.2 打开WinHex工具

                该软件需要以”管理员身份运行“。

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

        3.3 打开磁盘

                选择Tools —> Open Disk打开磁盘

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

        3.4 选择需要打开的磁盘

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

        3.5 查看磁盘数据

              选择分区1,然后鼠标键右击选择模板,可以查看DBR数据

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

        3.6 查看FAT32 DBR数据

              FAT32 DBR数据详细分析可以查看前面的解析,也可以用winhex软件查看(点击模板后后会自动弹出)。

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

        3.7 查看FAT32分区数据

                鼠标双击分区1,进入FAT32根目录,然后点击根目录文件夹(注意此时的offset是相对偏移,不是绝对偏移)。

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

        3.8 绝对位置查看数据

                为了更好的学习FAT32,推荐使用绝对地址导航来查看数据。先退出分区界面,然后点击导航-》跳转到偏移量,然后设置如下:

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

 4、 参考资料

        本文全部内容都来自下面两篇优秀文章,结合了自我理解后对其进行了整合。

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

【FatFs】FAT32文件系统协议原理讲解(以U盘为例)

        

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/131129.html

(0)
上一篇 2025-08-10 14:20
下一篇 2025-08-10 14:33

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信