swlings 发表于 2019-3-14 14:11

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]
查看完整版本: NTFS文件系统之浅析$LogFile文件