NTFS文件系统之浅析$LogFile文件
本帖最后由 swlings 于 2019-3-18 11:57 编辑NTFS是一种日志事务型文件系统,其工作原理就不多说了,感兴趣的可以参考《深入解析windows操作系统》第四版的第12章,这篇重点在于解析$LogFile这个文件的数据结构。言归正传,那么为什么是“浅析”呢?因为不够深。。。咳咳咳,无意开车。。。
NTFS的日志记录分为两个组成部分,其中包含NTFS自身以及LFS日志文件系统。如果说NTFS是日志的作者,那么LFS就是执笔人,一个生产,一个记录。
$LogFile的主要功能就是做事务管理,用于保证NTFS的可恢复性,类似于数据库的事务管理。
$LogFile文件的大小一般为64M,但不固定,分区较小的情况下可能小于64M,在不同版本中$LogFile的组成略有不同,早期版本是2+n的形式,较新的是2+32+n的形式。
第一个2表示的是文件的前2页,也叫重启动区域,第2个区域是最后一次更新的备份区域,用于最后一次更新发生错误时用于恢复的。
最后一块区域是循环日志区域,该区域是环形循环写入,类似于ringbuffer,用SequenceNumber记录循环次数。
日志记录空间分配用页计数,类似于文件系统的簇,页的大小一般为4096Bytes .
先来说说RestartPage,RestartPage占用了日志文件的第一页和第二页,其中第二页是第一页的备份(实际好像并不一样)。
暂时我只分析第一页,结构如下图:
下面是部分源码,但这个是1.0版本(日志版本),在数据结构上和现在的2.0版本还是有些区别的。
//
//Log Restart Page Header.This structure is at the head of the restart
//areas in a log file.
//
typedef struct _LFS_RESTART_PAGE_HEADER {
//
//Cache multisector protection header.
//
MULTI_SECTOR_HEADER MultiSectorHeader;
//
//This is the last Lsn found by checkdisk for this volume.
//
LSN ChkDskLsn;
//
//System page size.This is the page size of the system which
//initialized the log file.Unless the log file has been gracefully
//shutdown (there are no clients with restart areas), it is a fatal
//error to attempt to write to a log file on a system with a differen
//page size.
//
ULONG SystemPageSize;
//
//Log Page Size.This is the log page size used for this log file.
//The entire Lfs restart area must fit on a single log page.
//
ULONG LogPageSize;
//
//Lfs restart area offset.This is the offset from the start of this
//structure to the Lfs restart area.
//
USHORT RestartOffset;
//
//The indicates major and minor versions.Note that the pre-release versions
//have -1 in both positions.Major version 0 indicates the transition
//from Beta to USA support.
//
// Major Version
//
// -1 Beta Version
// 0 Transition
// 1 Update sequence support.
//
SHORT MinorVersion;
SHORT MajorVersion;
//
//Update Sequence Array.Used to protect the page block.
//
UPDATE_SEQUENCE_ARRAY UpdateSequenceArray;
} LFS_RESTART_PAGE_HEADER, *PLFS_RESTART_PAGE_HEADER;
我们从RestartPageHeader开始解释其中的结构以及各个成员变量的意义。
前面4个字节是标识 RSTR
紧接着就是更新序列数组的偏移和大小,占用4个字节,更新序列数组是用来确定每页的数据写入是否完整。
接着是ChkDskLsn,占用8个字节,这个是磁盘自检的时候才会用到。
接着是系统分页大小和日志分页大小,各占4个字节,值都是4096。
接着就是数据区的偏移量了,占用4个字节。
后面跟着日志系统的版本号,占用4个字节,高2个字节表示主版本号,低2个字节表示次版本号。
版本号后面跟着的就是更新序列数组了,其中前两个字节表示该页修改的次数,后面2 * 8个字节分别是该页的每个512字节的最后两个字节,而每个512字节的最后两个字节被最开始的两个字节(修改次数)替换,所以解析的时候需要还原回去。
//
//Lfs Restart Area.Two copies of these will exist at the beginning of the
//log file.
//
typedef struct _LFS_RESTART_AREA {
//
//Current Lsn.This is periodic snapshot of the current logical end of
//log file to facilitate restart.
//
LSN CurrentLsn;
//
//Number of Clients.This is the maximum number of clients supported
//for this log file.
//
USHORT LogClients;
//
//The following are indexes into the client record arrays.The client
//records are linked into two lists.A free list of client records and
//an in-use list of records.
//
USHORT ClientFreeList;
USHORT ClientInUseList;
//
//Flag field.
//
// RESTART_SINGLE_PAGE_IO All log pages written 1 by 1
//
USHORT Flags;
//
//The following is the number of bits to use for the sequence number.
//
ULONG SeqNumberBits;
//
//Length of this restart area.
//
USHORT RestartAreaLength;
//
//Offset from the start of this structure to the client array.
//Ignored in versions prior to 1.1
//
USHORT ClientArrayOffset;
//
//Usable log file size.We will stop sharing the value in the page header.
//
LONGLONG FileSize;
//
//DataLength of last Lsn.This doesn't include the length of
//the Lfs header.
//
ULONG LastLsnDataLength;
//
//The following apply to log pages.This is the log page data offset and
//the length of the log record header.Ignored in versions prior to 1.1
//
USHORT RecordHeaderLength;
USHORT LogPageDataOffset;
//
//Client data.
//
LFS_CLIENT_RECORD LogClientArray;
} LFS_RESTART_AREA, *PLFS_RESTART_AREA;
//
//Log Client Record.A log client record exists for each client user of
//the log file.One of these is in each Lfs restart area.
//
#define LFS_NO_CLIENT 0xffff
#define LFS_CLIENT_NAME_MAX 64
typedef struct _LFS_CLIENT_RECORD {
//
//Oldest Lsn.This is the oldest Lsn that this client requires to
//be in the log file.
//
LSN OldestLsn;
//
//Client Restart Lsn.This is the Lsn of the latest client restart
//area written to the disk.A reserved Lsn will indicate that no
//restart area exists for this client.
//
LSN ClientRestartLsn;
//
//
//Previous/Next client area.These are the indexes into an array of
//Log Client Records for the previous and next client records.
//
USHORT PrevClient;
USHORT NextClient;
//
//Sequence Number.Incremented whenever this record is reused.This
//will happen whenever a client opens (reopens) the log file and has
//no current restart area.
USHORT SeqNumber;
//
//Alignment field.
//
USHORT AlignWord;
//
//Align the entire record.
//
ULONG AlignDWord;
//
//The following fields are used to describe the client name.A client
//name consists of at most 32 Unicode character (64 bytes).The Log
//file service will treat client names as case sensitive.
//
ULONG ClientNameLength;
WCHAR ClientName;
} LFS_CLIENT_RECORD, *PLFS_CLIENT_RECORD;
(太多了。。。未完待续)
页:
[1]