《存储入门》读书笔记

《存储入门》读书笔记

1、文件系统

文件系统定义了把文件存储于磁盘时所必须的数据结构及磁盘数据的管理方式。我们知道,磁盘是由很多个扇区(Sector)组成的,如果扇区之间不建立任何的关系,写入其中的文件就无法访问,因为无法知道文件从哪个扇区开始,文件占多少个扇区,文件有什么属性。为了访问磁盘中的数据,就必需在扇区之间建立联系,也就是需要一种逻辑上的数据存储结构。建立这种逻辑结构就是文件系统要做的事情,在磁盘上建立文件系统的过程通常称为“格式化”。

以Windows平台下最常见的FAT文件系统为例。FAT文件系统有两个重要的组成部分:FAT表(File Allocation Table)和数据存储区。FAT表是FAT文件系统的名称来源,它定义了存储数据的簇(Cluster,由2的n次方个Sector组成,n值根据分区大小而定,需综合考虑数据存取效率和存储空间的利用率)之间的链接关系,这种链接关系是一个单向链表,指向0xFF表示结束。依据一个簇编号所用bit数的不同,可分为FAT12、FAT16和FAT32文件系统。数据区存储的数据包含文件目录项(Directory Entries)和文件数据。文件目录项存储的是一个文件或目录的属性信息,包括文件名称(把目录也看成是文件)、读写属性、文件大小、创建时间、起始簇编号等,一个目录下的每个子目录和文件都对应一个表项记录。文件目录项以固定32字节的长度存储,以树型结构管理,其中根目录的位置是确定的。也就是说,根据分区根目录可以找到下级子目录和文件的起始簇编号,根据下级子目录又可以找到更下级目录或文件的起始簇编号。可见,FAT表和文件目录项是为了文件的访问和管理而建立的。应用程序要访问一个文件时,根据文件路径(逻辑分区号+目录,如F:\software)和文件名称(如setup.exe)可从文件目录项中获得存储文件数据的起始簇号,之后从FAT表查询这个簇号对应的链表,就可以获得该文件对应的全部簇编号。从这些簇中读出全部数据,就得到一个完整的文件。以下是FAT32文 件系统结构图:
这里写图片描述

NTFS文件系统

一个NTFS系统是由引导扇区,主文件表MFT,和数据区组成;另外MFT有一部分重要备份在数据区。

这里写图片描述

(1) 引导扇区

若果D:\盘是NTFS文件系统,那么上面得到的第0个扇区数据 buf 偏移0x03开始的8个Bytes就是”NTFS “,表示这个扇区就是NTFS

的引导记录。这第0个扇区也就是$Boot扇区,这个扇区包含了该卷的 BPB 和扩展BPB参数,可以得到该卷的卷大小,磁头数,扇区大小,簇

大小等等参数;要解析一个NTFS卷的文件结构也是从这里的BPB参数开始的。

解析时有用到的是这个扇区的前 88 (0x58) 个Bytes,剩余的是引导代码和结束标志”55 AA”,前88个字节具体结构如下:
这里写图片描述

1 typedef struct NTFS_BPB{     // 在cmd 输入 fsutil fsinfo ntfsinfo d: 查询 NTFS 信息
 2     UCHAR jmpCmd[3];
 3     UCHAR s_ntfs[8];            // "NTFS    " 标志
 4 // 0x0B
 5     UCHAR bytesPerSec[2];        //  0x0200  扇区大小,512B
 6     UCHAR SecsPerClu;            //  0x08    每簇扇区数,4KB
 7     UCHAR rsvSecs[2];            //       保留扇区
 8     UCHAR noUse01[5];            //
 9 // 0x15
10     UCHAR driveDscrp;            //  0xF8     磁盘介质 -- 硬盘
11     UCHAR noUse02[2];            //
12 // 0x18
13     UCHAR SecsPerTrack[2];     //  0x003F  每道扇区数 63
14     UCHAR Headers[2];           //  0x00FF 磁头数
15     UCHAR secsHide[4];          //  0x3F  隐藏扇区
16     UCHAR noUse03[8];           //
17 // 0x28
18     UCHAR allSecsNum[8];        // 卷总扇区数, 高位在前, 低位在后
19 // 0x30
20     UCHAR MFT_startClu[8];      // MFT 起始簇
21     UCHAR MFTMirr_startClu[8]; // MTF 备份 MFTMirr 位置
22 //0x40
23     UCHAR cluPerMFT[4];     // 每记录簇数 0xF6
24     UCHAR cluPerIdx[4];     // 每索引簇数
25 //0x48
26     UCHAR SerialNum[8];     // 卷序列号
27     UCHAR checkSum[8];     // 校验和
28 }Ntfs_Bpb,*pNtfs_Bpb;

(2) 关于簇

  在一个分区中引导记录扇区所在的簇编号为0,往后的簇编号1,2,3等等一直到卷尾,这就是一个分区的逻辑簇号(LCN);计算

逻辑扇区号:LCN * 簇大小,簇的大小在BPB参数中找到,一般为8个扇区4KB;以此可以由 MFT 起始簇 MFT_startClu 计算

出第一个 MFT 项(记录)的位置。

  VCN,虚拟簇号,给一个文件从它的首簇开始编号,为0,依次递增一直到文件的尾簇,在物理上不一定连续。

(3) 主文件表 (Master File Table, MFT)

  MFT 是由一条条 MFT 项(记录)所组成的,而且每项大小是固定的(一般为1KB),MFT保留了前16项用于特殊文件记录,称为元数据,

元数据在磁盘上是物理连续的,编号为0~15;如果$MFT的偏移为0x0C0000000, 那么下一项的偏移就是0x0C0000400,在下一项就是

0x0C0000800等等;
这里写图片描述
  

  MFT记录了整个卷的所有文件 (包括MFT本身、数据文件、文件夹等等) 信息,包括空间占用,文件基本属性,文件位置索引,创建时

间用户权限,加密信息等等,每一个文件在 MFT 中都有一个或多个 MFT 项记录文件属性信息,这里的属性包括数据,如果这个文件很小

在 MFT 项中就可以放下,那么这条属性就定义为常驻属性,常驻标志位记为1,如果是非常驻,则有一个索引指向另一条记录(称为一个运行)。

(3) 第一条 MFT 项: $MFT

  MFT 的第一项记录$MFT描述的是主分区表MFT本身,它的编号为0,MFT项的头部都是如下结构:

1 typedef struct MFT_HEADER{
 2     UCHAR    mark[4];             // "FILE" 标志 
 3     UCHAR    UsnOffset[2];        // 更新序列号偏移     30 00
 4     UCHAR    usnSize[2];          // 更新序列数组大小+1   03 00
 5     UCHAR    LSN[8];              // 日志文件序列号(每次记录修改后改变)  58 8E 0F 34 00 00 00 00
 6 // 0x10
 7     UCHAR    SN[2];               // 序列号 随主文件表记录重用次数而增加
 8     UCHAR    linkNum[2];          // 硬连接数 (多少目录指向该文件) 01 00
 9     UCHAR    firstAttr[2];        // 第一个属性的偏移  38 00
10     UCHAR    flags[2];            // 0已删除 1正常文件 2已删除目录 3目录正使用
11 // 0x18
12     UCHAR    MftUseLen[4];        // 记录有效长度    A8 01 00 00
13     UCHAR    maxLen[4];            // 记录占用长度   00 04 00 00
14 // 0x20
15     UCHAR    baseRecordNum[8];     // 索引基本记录, 如果是基本记录则为0
16     UCHAR    nextAttrId[2];        // 下一属性Id  07 00
17     UCHAR    border[2];            //
18     UCHAR    xpRecordNum[4];       // 用于xp, 记录号
19 // 0x30
20     UCHAR    USN[8];          // 更新序列号(2B) 和 更新序列数组
21 }Mft_Header, *pMft_Header;

这里写图片描述
上面的头部结构体在扇区的数据偏移 0x00 ~0x38;

在0x38之后的4大块颜色数据是4条属性,描述名称,时间,索引等等信息,最后以”FF FF FF FF”结束。它们分别以0x10,0x30,

0x80, 0xB0作为标志;这里的四种属性所描述的的信息类型可以由下表查得,对照数据和结构体可以把这4条属性解析出来。
这里写图片描述
   

 1 //------------------  属性头通用结构 ----
 2 typedef struct NTFSAttribute //所有偏移量均为相对于属性类型 Type 的偏移量
 3 {
 4     UCHAR Type[4];           // 属性类型 0x10, 0x20, 0x30, 0x40,...,0xF0,0x100
 5     UCHAR Length[4];         // 属性的长度 
 6     UCHAR NonResidentFiag;   // 是否是非常驻属性,l 为非常驻属性,0 为常驻属性 00
 7     UCHAR NameLength;        // 属性名称长度,如果无属性名称,该值为 00
 8     UCHAR ContentOffset[2];  // 属性内容的偏移量  18 00
 9     UCHAR CompressedFiag[2]; // 该文件记录表示的文件数据是否被压缩过 00 00
10     UCHAR Identify[2];       // 识别标志  00 00
11 //--- 0ffset: 0x10 ---
12 //--------  常驻属性和非常驻属性的公共部分 ----
13     union CCommon
14     {
15     //---- 如果该属性为 常驻 属性时使用该结构 ----
16         struct CResident
17         {
18             UCHAR StreamLength[4];        // 属性值的长度, 即属性具体内容的长度。"48 00 00 00"
19             UCHAR StreamOffset[2];        // 属性值起始偏移量  "18 00"
20             UCHAR IndexFiag[2];           // 属性是否被索引项所索引,索引项是一个索引(如目录)的基本组成  00 00
21         };
22     //------- 如果该属性为 非常驻 属性时使用该结构 ----
23         struct CNonResident
24         {
25             UCHAR StartVCN[8];            // 起始的 VCN 值(虚拟簇号:在一个文件中的内部簇编号,0起)
26             UCHAR LastVCN[8];             // 最后的 VCN 值
27             UCHAR RunListOffset[2];       // 运行列表的偏移量
28             UCHAR CompressEngineIndex[2]; // 压缩引擎的索引值,指压缩时使用的具体引擎。
29             UCHAR Reserved[4];
30             UCHAR StreamAiiocSize[8];     // 为属性值分配的空间 ,单位为B,压缩文件分配值小于实际值
31             UCHAR StreamRealSize[8];      // 属性值实际使用的空间,单位为B
32             UCHAR StreamCompressedSize[8]; // 属性值经过压缩后的大小, 如未压缩, 其值为实际值
33         };
34     };
35 };
由这个结构体可以知道,属性头的长度取决于是否有属性名,属性名长度是多少;是否常驻,如果常驻,属性内容长度是多少,如果非常驻,运行列表有多长。

(0x08)日志文件序列号,它又叫文件参考号、文件引用号,一共 8Byte,前6个字节是文件称为文件号;后2个字节是文件顺序号,文件顺序号随重用而增加。

  10H 类型:10H属性$STANDART_INFORMATION,描述的是文件的创建、访问、修改时间,传统属性,以及版本信息等等。

 1 struct Value0x10
 2 {
 3     UCHAR fileCreateTime[8];    // 文件创建时间 
 4     UCHAR fileChangeTime[8];    // 文件修改时间 
 5     UCHAR MFTChangeTime[8];     // MFT修改时间 
 6     UCHAR fileLatVisited[8];    // 文件最后访问时间 
 7     UCHAR tranAtrribute[4];     // 文件传统属性
 8     UCHAR otherInfo[28];        // 版本,所有者,配额,安全等等信息(详细略)
 9     UCHAR updataNum[8];         // 文件更新序列号 
10 }; 

这里写图片描述

  下面的偏移都是相对于属性首字节,其值加上0x38 就是实际偏移(图中的offset)。

0x00 4B: (0x10) 类型标志

0x04 4B: (0x60) 整条10H属性的长度

0x08 1B: (0x00) 非常驻

0x09 1B: (0x00) 无属性名称

0x0A 2B: (0x18) 属性内容偏移位置

0x18 8B: (ED 46 39 6B 6B 93 CF 01) 8个字节是文件创建时间,紧随其后的3x8个字节分别是文件最后修改时间,MFT修改

时间,文件最后访问时间。64位数值是相对于1601-01-01零点整的千万分之一秒数。可以用FileTimeToSystemTime()转换成

我们通常见到的形式。

0x38 8B: (06 00 00 00 00 00 00 00)传统属性,这里是系统隐含文件,位描述:
这里写图片描述

后面还有0x28个字节是版本和管理信息等等。

20H类型 $ATTRIBUTE_LIST

当一个文件需要多个MFT项来记录,20H是用来描述属性的属性列表;当非常驻属性依然不够空间,则需要属性列表。20H类属性也有

可能为常驻或非常驻,可以应用上面的通用属性头。以此结构体得到属性值的偏移地址,进而得到属性内容。

//------- 这个结构只是数据内容部分,不包括属性头 NTFSAttribute ----
 //------- 由属性头的属性值偏移量确定属性值的起始位置 ---
 1 struct Value0x20{
 2     UCHAR type[4];           // 类型
 3     UCHAR recordType[2];     // 记录类型
 4     UCHAR nameLen[2];        // 属性名长度
 5     UCHAR nameOffset;        // 属性名偏移
 6     UCHAR startVCN[8];       // 起始 VCN
 7     UCHAR baseRecordNum[8];  // 基本文件记录索引号
 8     UCHAR attributeId[2];    // 属性 id
 9     //---- 属性名(Unicode) 长度取决于 nameLen 的值 ---
10 };

  30H 类型 $FILE_NAME

  30H 类型属性描述的是文件或文件夹的名字和创建基本信息,属性头不在赘述,属性值的结构如下:

 1 struct Value0x30
 2 {
 3     UCHAR parentFileNum[8];     // 父目录的文件参考号,前6B
 4     UCHAR createTime[8];        // 文件创建时间
 5     UCHAR changeTime[8];        // 文件修改时间
 6     UCHAR MFTchangeTime[8];     // MFT 修改时间 
 7     UCHAR lastVisitTime[8]      // 最后一次访问时间 
 8     UCHAR AllocSize[8];         // 文件分配大小 
 9     UCHAR realSize[8];          // 实际大小 
10     UCHAR fileFlag[4];          // 文件标志,系统 隐藏 压缩等等 
11     UCHAR EAflags[4]            // EA扩展属性和重解析点
12     UCHAR nameLength;           // 文件名长 
13     UCHAR nameSpace;            // 文件命名空间 
14     //----- Name (Unicode编码) 长度为 2 * nameLength ---- 
15 }

  NTFS通过为一个文件创建多个30H属性实现POSIX (Portable Operating System Interface, 可移植操作系统接口) 式硬连接,

每个30H属性都有自己的详细资料和父目录;一个硬连接删除时,就从MFT中删除这个文件名,最后一个硬连接被删除时,这个文件就算是

真正被删除了。

 文件参考号:包括前 6B 的文件记录号,后 2B 的文件引用计数;当文件记录号为0x05时,是根目录。

 命名空间:0 — POSIX, 1 – Win32, 2 — DOS, 3 — Win32 & DOS

  40H 属性 $OBJECT_ID

 MTFS统一给所有 MFT 记录分配的一个标识 — 对象ID,即结构体第一个16B,可能只有一个全局对象ID,后面的3个ID可能没有。

1 struct Value0x40
2 {
3     UCHAR GObjectId[16];            // 全局对象ID 给文件的唯一ID号 
4     UCHAR GOriginalVolumeId[16];    // 全局原始卷ID 永不改变 
5     UCHAR GOriginalObjectId[16];    // 全局原始对象ID 派给本MFT记录的第一个对象ID 
6     UCHAR GDomain[16];              // 全局域ID (未使用)
7 };

  50H 属性 $SECURITY_DESCRIPTOR ( 安全描述符) 略。

  60H 属性 $VOLUME_NAME 卷名属性

1 struct Value0x60
2 {
3     //---- 通用属性头 --
4     UCHAR VolumeName[N];    //(Unicode) N 最大为 127 外加一个结束符'\0'
5 };

  70H 属性 $VOLUME_INFORMATION 卷版本、状态

 1 struct Value0x70
 2 {    //----- 通用属性头 --- 
 3     UCHAR noUsed1[8];        // 00
 4     UCHAR mainVersion;       // 主版本号 1--winNT, 3--Win2000/XP
 5     UCHAR SecVersion;        // 次版本号 当主为3, 0--win2000, 1--WinXP/7
 6     UCHAR flag[2];           // 标志 
 7     UCHAR noUsed2[4];        // 00 
 8 };
 9 /* flag:
10 *  0x0001  坏区标志 下次重启时chkdsk/f进行修复
11 *  0x0002  调整日志文件大小 
12 *  0x0004  更新装载 
13 *  0x0008  装载到 NT4 
14 *  0x0010  删除进行中的USN 
15 *  0x0020  修复对象 Ids 
16 *  0x8000  用 chkdsk 修正卷 
17 */ 

  80H 属性 $DATA 容纳文件数据(未命名数据流),文件的大小一般指是未命名数据流的大小,没有长度限制,当它为常驻时,数据

长度最小。它的结构为属性头加上数据流,如果数据流太大,则标记为非常驻,以运行的方式索引到外部。例如找一个MP3文件,从它的MFT

项中0x80属性中可以看到它一定是非常驻,它的运行所指向的一系列簇就是音乐文件数据流;

一个80H属性实例:

  这里写图片描述

0x00~0x37 是属性头;运行列表偏移是紫色和橙色区域,0x40开始,可以得到运行列表 32 40 34 00 00 0C 32 80 31 07 54 16 ;分析如下:

 首先0x32,低4位是2,表示紧随其后的2Byte 0x3440作为运行簇大小,高4位是3,表示簇大小之后的3个Byte 0x0C0000 是起始簇,这

是一个运行结束;接下来的0x32同理得簇起始号0x165407,运行大小为0x3180簇;一个运行的结束后跟0x00 为列表结束,之后填充无效字符。

 90H 属性 $INDEX_ROOT 索引根。实现NTFS的B+树索引的根节点,总是常驻。索引根属性由属性头、索引根和索引项组成。属性头是通用

属性头的常驻部分。结构体如下(可能有些偏差):

1 struct indexHeader 
 2 {
 3     UCHAR type[4];             //  属性类型 
 4     UCHAR checkRule[4];        // 校对规则 
 5     UCHAR allocSize[4];        // 索引项分配大小 
 6     UCHAR CluPerIdx;           // 每索引记录的簇数
 7     UCHAR noUse01[3];          // 填充 
 8 
 9     UCHAR firstIdxOffset[4];    // 第一个索引项偏移 
10     UCHAR idxTotalSize[4];      // 索引项总大小 
11     UCHAR indxAllocSize[4];     // 索引项分配大小 
12     UCHAR flag;                 // 标志
13     UCHAR noUse02[3];
14 };
15 // 一般小目录在90属性中有常驻目录项,目录项的结构与INDX缓存中的目录项一样
16 struct indexItem
17 {    
18     UCHAR MFTnum[8]                 // 文件的 MFT 记录号,前6B是MFT编号,用于定位此文件记录
19     UCHAR ItemLen:[2];              // 索引项大小
20     UCHAR IndexIdentifier:[2];      // 索引标志 R
21     UCHAR isNode[2];                // 1---此索引包含一个子节点,0---此为最后一项 
22     UCHAR noUse03[2];               // 填充
23     UCHAR FMFTnum[8];               // 父目录 MFT文件参考号 0x05表示根目录 
24     UCHAR CreateTime[8];            //文件创建时间
25     UCHAR fileModifyTime[8];        //文件修改时间
26     UCHAR MFTModifyTime[8];         //文件记录最后修改时间
27     UCHAR LastVisitTime[8];         //文件最后访问时间
28     UCHAR FileAllocSize[8];         //文件分配大小 (B)
29     UCHAR FileRealSize[8];          //文件实际大小 (B)
30     UCHAR FileIdentifier[8];        //文件标志
31     UCHAR FileNameLen;              //文件名长度
32     UCHAR FileNameSpace;           //文件名命名空间
33 //---- 0x52 --- 
34     //FileName;                     // 文件名 (末尾填满 8 字节)
35     UCHAR nextItemVCN[8];           // 下一项的 VCN (有子节点才有)
36 };

 A0H 属性 $INDEX_ALLOCATION 索引分配属性,也是索引,由属性头和运行列表组成,一般指向一个或多个目录文件(INDX文件,即4K缓存);

 A0H属性和90H属性共同描述了磁盘文件和目录的 MFT 记录的位置。第5项MFT的A0H属性记录根目录的位置。

 B0H 属性 BITMAP使() MFT和索引中;在Bitmap文件中,每一个 Bit 代表分区的一个簇,置1代表其已使用;

第0个字节的第0位表示分区第0簇,之后依次递增。

 C0H 属性 $REPARSE_POINT 重解析点。使应用程序为文件或目录关联一个应用程序数据块,详细略。

 D0H $EA_INFORMATION 扩充信息属性。为在NTFS下实现HPFS的OS/2子系统信息,及WinNT服务器的OS/2客户端应用而设置的,一般为非常驻;

 E0H $EA 扩充属性 也是为了实现NTFS下的 HPFS,一般为非常驻;

 100H $LOGGED_UTILITY_STREAM,EFS加密属性,存储用于实现EFS加密有关的信息,合法用户列表,解密密钥等等

(4) 解析一个磁盘分区的文件目录的顺序:

  引导扇区( Boot)>0( MFT) —-> 根目录记录(第5项,90H,A0H) —-> 根目录(INDX)

1 struct indxHeader    // A0H外部缓存文件结构,最大长度一般为4K
 2 {
 3     UCHAR mark[4];        //  标志 "INDX"
 4     UCHAR usnOffset[2];   // 更新序列偏移
 5     UCHAR usnSize[2];     // 更新序列数组大小S
 6     UCHAR LSN[8];         // 日志文件序列号
 7     UCHAR indxVCN[8];     // 本索引缓存在分配索引中的VCN
 8     UCHAR itemOffset[4];  // 第一项索引的偏移(从这里开始计算)
 9     UCAHR itemSize[4];    // 索引项实际大小(B)
10     UCHAR itemAlloc[4];   // 索引项分配大小(B)(不包括头部) 略小于4K
11     UCHAR isNode;         // 是结点置1,表示有子节点
12     UCHAR noUse[3];        
13     //UCHAR USN[2S];      // 更新序列号和数组
14 };

  在文件头之后就是目录项了,项的结构就是在上面90H的介绍里定义的indexItem,每一个项代表一个文件或目录的MFT项,通过

项的 MFT 记录号可以计算出MFT项的磁盘地址,它等于$MFT 的偏移地址 + 编号*0x400,以此可以找到该索引项对应的文件或子目录

的MFT项。

(5) 搜索一个已删除的文件或目录的MFT项

 上面说了,一个文件的MFT项的地址等于$MFT的地址+MFT编号*0x400,如果目录中的对应项删除了,那么可以从MFT的首部开始检索,

因为MFT一般是连续的,而一个MFT项的大小又是固定的,一项项读取,找到各自的0x30属性,解析出文件名,进行比较 (MFT中有一些

空白区域需要跳过)。

(6) 关于文件名

 一般在文件名的前一个字节是文件名的命名空间,不管是INDX文件中,还是0x30属性中。

  0x00 —- POSI ,最大的命名空间,大小写敏感,支持除 ‘\0’ 和 ‘/’ 所有Unicode字符,最大程度255个字符;

  0x01 —- Win32,是POSI的子集,不支持字符:* / < > | \ : ? ,不能用句点或空格结束;

  0x02 —- DOS , 是Win32的子集,字符必须比空格0x20大,文件名1~8个字符,然后句点分割接后缀扩展名1~3个字符;

  0x03 — DOS&Win32,必须兼容Win32和DOS命名方式

在INDX文件中,经常可以看到含有0x02和0x03或者0x01的两个不同命名空间、相同MFT编号的项,也就是说这两个目录项指向同一个记录,同样的

在这个文件的MFT项中也有两个0X30属性,其中一个是0x01或0x03,表示的是完整的文件名;另一个是0x02,DOS命名方式,它是一个短文件名,它在

我们命名的基础上,截断 ‘.’ 之前的超出6个字符的所有字符,只剩前6个,之后接上”~1” ,这样正好8个字符,当然后面的句点和扩展名保留。另外,它必须

满足DOS命名规则,必须大写,删除禁止使用的字符等等。如果文件名重复了,在 “~1” 基础上递增,”~2”,”~3”等等。检索比对时,我们自然要使用前者。

(7) 关于字符集

字符集是字符在计算机上的编码方式,可以看成一种协议,一种约定规则,我们处理一串二进制数所代表的字符时,必须清楚它用的是哪一种编码方式;

在windows系统中文件的命名是固定用两个字节表示一个字符,在MFT中可以发现英文文件名字符之间都填充一个 ‘\0’ ,这是宽字符集与变长字符集兼容,

在宽字符集中,小于128的字符数值上是等于ASCII码;我们的文件数据一般用的是变长字符集(GB2312等等);

为了比较输入的文件名和NTFS中的文件名,我们必须要先转换;

两个WinAPI 函数,用于宽字符和变长字符转换

/ 函数原型
int WideCharToMultiByte(
            UINT     CodePage,            // code page
            DWORD    dwFlags,            // performance and mapping flags
            LPCWSTR  lpWideCharStr,     // address of wide-character string
            int      cchWideChar,        // number of characters in string
            LPSTR    lpMultiByteStr,        // address of buffer for new string
            int      cchMultiByte,        // size of buffer
            LPCSTR   lpDefaultChar,        // address of default for unmappable 
                                          // characters
            LPBOOL   lpUsedDefaultChar    // address of flag set when default 
                                        // char. used
);
int MultiByteToWideChar(
            UINT   CodePage,         // code page
            DWORD  dwFlags,         // character-type options
            LPCSTR lpMultiByteStr, // address of string to map
            int    cchMultiByte,      // number of bytes in string
            LPWSTR lpWideCharStr,  // address of wide-character buffer
            int    cchWideChar        // size of buffer
);

//--- WCHAR 定义在tchar.h中 ----
void charTest()
{
    TCHAR    tc1[16] ;  //=  _T("后来");
    WCHAR    tc2[8] = {0x540E, 0x6765, 0, 0, 0, 0, 0, 0};
//    memset(tc2, 0, 20);
//  MultiByteToWideChar(CP_ACP, 0, tc1, 4, (LPWSTR)tc2, 4);
    WideCharToMultiByte(CP_ACP, 0 ,(WCHAR*)tc2, 2, tc1, sizeof(tc1), 0, 0);  

    cout<<"tc1 "<<tc1<<sizeof(tc1)<<" "<<strlen(tc1)<<endl;
    PrintHex(tc1);
    cout<<endl;
    cout<<"tc2 "<<sizeof(tc2)<<" "<<wcslen((LPWSTR)tc2)<<endl;
    PrintHex(tc2);
    cout<<endl;
}

ext2文件系统

inode:记录文件的属性,一个文件占用一个inode,同时记录此文件的数据所在的block号码。
block:实际记录文件的内容,若文件太大时,会占用多个block。
超级块(super block)会记录整个文件系统的的整体信息,包括inode与block的总量、使用量、剩余量,以及文件系统的格式与相关信息等。
File system Description(文件系统描述说明)

这个区段可以描述每个block group的开始与结束的号码,以及说明每个区段分别介于哪一个block号码之间。可以用dumpe2fs来查看。

 block bitmap(块对照表)

通过block bitmap可以知道哪些block是空的,因此我们的系统就能够很快速地找到可以使用的空间来处置文件。同样,如果你删除某些文件时,那么那些文件原本占用的block号码就得要释放出来,此时在block bitmap当中相对应到该block号码的标志就得要修改成为“未使用”。

inode bitmap(inode对照表)

与block bitmap相似。
这里写图片描述
  一般来说,文件系统是和操作系统紧密结合在一起的,不同的操作系统使用不同的文件系统,但有时为了兼容,不同操作系统也使用相同的文件系统。

分布式文件系统发展史

分布式存储在大数据、云计算、虚拟化场景都有用武之地,在大部分场景还至关重要。
对于一个IT从业人员,学习分布式存储相关基础知识必不可少。
今天给大家简要介绍*nix平台下分布式文件系统的发展历史。

1、单机文件系统
用于操作系统和应用程序的本地存储。
缺点:数据无法再服务器之间共享。
典型代表:Ext2、Ext3、Ex4、NTFS、FAT、FAT32、XFS、JFS…
IO模型:
这里写图片描述
2、网络文件系统(简称:NAS)
基于现有以太网架构,实现不同服务器之间传统文件系统数据共享。
缺点:两台服务器不能同时访问修改,性能有限。
典型代表:NFS、CIFS
IO模型:
这里写图片描述
3、集群文件系统
在共享存储基础上,通过集群锁,实现不同服务器能够共用一个传统文件系统。
缺点:性能一般,扩展性很有限(小于16台服务器)。
典型代表:GFS(Redhat)、GFS2(Redhat)、OCFS(Oracle)
IO模型:
这里写图片描述

GFS、GFS2模型如下:
这里写图片描述
默认上面三种文件系统模块都位于内核里面,NFS over Inifiband可以使用kernel bypass绕开内核。

4、分布式文件系统
在传统文件系统上,通过额外模块实现数据跨服务器分布,并且自身集成raid保护功能,可以保证多台服务器同时访问、修改同一个文件系统。性能优越,扩展性很好,成本低廉。
缺点:适用场景单一,部分类型存在单点故障风险。
典型代表:lustre(Oracle)、HDFS(ASF)、gluster(Redhat)
IO模型:
主要分两大类型:一种是元数据集中管理模型;另一种是元数据分散管理模型
lustre(Oracle)
这里写图片描述

HDFS(ASF)
这里写图片描述
lustre和HDFS是元数据集中管理典型代表。实际数据分布存放在数据服务器上,元数据服务器负责IO请求调配,空间分配;非常适用于大文件存储。
元数据服务器可能成为系统扩展的瓶颈。

gluster(Redhat)
这里写图片描述
gluster是元数据分散管理模型典型代表,元数据被分散放置到所有服务器上,不存在元数据单点故障。非常适用于小文件存储。

参考资料:
http://www.stalker.com/notes/SFS.html
https://access.redhat.com/knowledge/docs/en-US/Red_Hat_Enterprise_Linux/6/html/Global_File_System_2/index.html
http://wiki.lustre.org/index.php/Main_Page
https://access.redhat.com/knowledge/docs/en-US/Red_Hat_Storage/2.0/html-single/Administration_Guide/index.html#sect-Administration_Guide-intro_arch-Test_Section
http://www.gluster.org/

2、DAS NAS 和SAN 结构图

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值