吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 7701|回复: 0
收起左侧

[其他转载] NTFS文件系统之浅析$LogFile文件

  [复制链接]
swlings 发表于 2019-3-14 14:11
本帖最后由 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的形式。
lfs-layout.png
第一个2表示的是文件的前2页,也叫重启动区域,第2个区域是最后一次更新的备份区域,用于最后一次更新发生错误时用于恢复的。
最后一块区域是循环日志区域,该区域是环形循环写入,类似于ringbuffer,用SequenceNumber记录循环次数。

日志记录空间分配用页计数,类似于文件系统的簇,页的大小一般为4096Bytes .

先来说说RestartPage,RestartPage占用了日志文件的第一页和第二页,其中第二页是第一页的备份(实际好像并不一样)。
暂时我只分析第一页,结构如下图:
RestartPage1.png


下面是部分源码,但这个是1.0版本(日志版本),在数据结构上和现在的2.0版本还是有些区别的。
[C++] 纯文本查看 复制代码
//
//  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字节的最后两个字节被最开始的两个字节(修改次数)替换,所以解析的时候需要还原回去。
[C++] 纯文本查看 复制代码
//
//  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[1];

} LFS_RESTART_AREA, *PLFS_RESTART_AREA;


[C++] 纯文本查看 复制代码
//
//  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_NAME_MAX];

} LFS_CLIENT_RECORD, *PLFS_CLIENT_RECORD;


(太多了。。。未完待续)

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-16 06:04

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表