| 词汇 |
| 类型 | 描述 | 名称 |
|---|---|---|
| 0x10 | 标准信息文件 ($STANDARD_INFORMATION) | |
| 0x30 | 文件名文件 ($FILE_NAME) | $LogFile |
| 0x80 | 数据文件 ($DATA) | [未命名] |
对日志文件了解很少
日志区域是由一个4KB的日志记录序列组成的,每个日志记录结构如下:
偏移(长度) 内容
0(4) 幻数 'RCRD'
1E(12) 修正或固定
按照推测,日志记录包含一序列不同大小的记录,它们的结构不清楚。文件2是$LogFile,它包含处理事务的 记录以保证在系统瘫痪的时候数据的完整性。如37页提到的,它由2个重新启动区的拷贝和无限的日志区组成。
如果要把一个文件写到一个存储单元上,你必须修正这个文件本身以添加此文件系统的一些表格(例如文件 数据)。在此,你要经过两个操作步骤(修正文件自身,修正文件数据)。
如果此项任务完成,可以确认文件被写到存储单元上,并且文件系统处于定义的状态。
如果不能完成此项任务(例如如果系统瘫痪或日常的系统故障),则文件系统处于未定义状态。把它恢复到 定义(规定)状态的唯一途径(此操作称为“击退”)是把它放进一个特殊文件里,日志文件,那么就成功完成了 对此项任务的操作。
在系统故障后第一次进入磁盘时,系统读取日志文件并“击退”最近一项任务开端的所有操作。
注意:此项操作不是由WINDOWS NT的chkdsk执行的,而是由系统执行的:此项标准可靠的操作功能是NTFS的特点。
日志文件结构:
两个重新启动区分布在最初的两页(重新启动页),如果卷没有被布置过,它们是一致的。
然后是日志记录。它以一个记录标题开头,接着是日志文件大小。当卷被第一次格式化时不
是所有的页面都包含日志记录,而是卷龄,所有的记录都会在用。当日志文件填充满时,处
于开始位置的记录就会被清除(大概是通过修改the oldest_lsn),并且在文件开端开始写
入。从而,此日志文件看起来象是一个循环体。
日志文件的重新启动页标题(开始重新启动区)
struct {
NTFS_RECORD; 特征码是“RSTR”
__u64 chkdsk_lsn; 对于此重新启动页的检测磁盘的日志文序列号 。
只有当特征码转到"CHKD". = 0时才用到它。
__u32 system_page_size; 统页的比特大小,必须 >= 512,而且是2的n次幂。
可以用它来计算需要用的空间大小,并把它加到
NTFS的ntfs.usa_offset里。然后验证结果
小于restart_offset. = 0x1000。
__u32 log_page_size; 志文件记录的大小,必须>= 512,并且是2的n次幂。
= 0x1000
__u16 restart_offset; 从记录开始到重新启动记录的偏移比特。
此值必须被排列为8比特边界 = 0x30
__s16 minor_ver; 日志文件的低版本,如果低版本是1,只能检测。
(>=1同样对待,<=0也行)
__u16 major_ver; 日志文件的主流版本(=1但是=0是好的)
} RESTART_PAGE_HEADER;
日志文件重新启动区记录。把RESTART_PAGE_HEADER的偏移(位置)和restart偏移(位置)相加即可得
到此记录的偏移值(位置)。
struct {
__u64 current_lsn; 日志文件记录。= 0x700000, 0x700808
__u16 log_clients; 紧跟在重新启动区后面的日志客户记录号=1
__u16 client_free_list; 多少客户是空闲的(?)如果 != 0xffff,
检查log_clients > client_free_list.
= 0xffff
__u16 client_in_use_list; 多少客户在用(?)如果 != 0xffff
检查log_clients > client_in_use_list.
= 0
__u16 flags; ??? = 0
__u32 seq_number_bits; ??? = 0x2c or 0x2d
__u16 restart_area_length; 重新启动区的长度。如果版本匹配需要进一步检查。
否则就略过。restart_offset +restart_area_length
必须 <= system_page_size. 而且restart_area_length
必须 >= client_array_offset +(log_clients * 0xa0)
= 0xd0
__u16 client_array_offset; 在版本匹配的情况下从此记录开始到第一个客户记录的
偏移量。否则此偏移量假定为(sizeof(RESTART_AREA) + 7) & ~7
例如,上舍入第一个8比特边界。
用任一种方法到客户队列的偏移量都必须排列为一个8比
特边界。同样,重新启动页的偏移量+到客户队列的偏移量
必须<= 510. 到客户队列的偏移量+(log_clients * 0xa0)
必须<= SystemPageSize
= 0x30
__u64 file_size; 日志文件的比特大小。如果
重新启动的偏移量+文件大小的偏移量>510
就会出错。当以重新启动区开始的时候这是最初的一个检
查,看起来好像是失败了,其实这仅仅意味着上述一些数
值将被多部转移保护所破坏。
如果这个结构被解除保护那么这些检查将是无效过程。
计算此文件大小的位数并检查
seq_number_bits == 0x43 - file_size bits
= 0x400000
__u32 last_lsn_data_length; ??? = 0, 0x40
__u16 record_length; 此记录的字节大小。如果版本匹配,
此记录长度的值是8的倍数,例如:
(record_length + 7) & ~7 == record_length.
= 0x30
__u16 log_page_data_offset; ??? = 0x40
} RESTART_AREA;
日志文件客户记录。起始于0x58即使有上述意外发生它也会在0x60开始. /-:
struct {
__u64 oldest_lsn; 此客户记录的最古老日志文件的序列号
= 0xbd16951d
__u64 client_restart_lsn; ??? = 0x700000, 0x700827, 0x700d07
__u16 prev_client; ??? = 0x808, 0xd07, 0xd5d
__u16 next_client; ??? = 0x70
__u16 seq_number; ??? = 0, 4 大小不确定。称为“卷清除标记”,大小为一个字节。
__u16 client_name; ??? = 空字串??? 大小不确定
} RESTART_CLIENT;
注意:上述客户记录是在0xffffffff之后的,可能指示重新启动区的结尾。
那么这有8字节=0,one __u32 = 8,然后是标准编码字串“NTFS”,然后调零直至页尾?
日志页记录页标题。每一个日志页以标题开始,然后是几个日志记录结构。
struct {
NTFS_RECORD; 幻数"RCRD".
union {
__u64 last_lsn;
__u32 file_offset;
} copy;
__u32 flags;
__u16 page_count;
__u16 page_position;
union {
struct {
__u64 next_record_offset;
__u64 last_end_lsn;
} packed;
} header;
} RECORD_PAGE_HEADER;
日志记录可能有的标记
enum {
LOG_RECORD_MULTI_PAGE = 1, ???
LOG_RECORD_SIZE_PLACE_HOLDER = 0xffff,
无法使用日志记录,gcc此标记为16比特
} LOG_RECORD_FLAGS;
日志记录头
struct {
__u64 this_lsn;
__u64 client_previous_lsn;
__u64 client_undo_next_lsn;
__u32 client_data_length;
struct {
__u16 seq_number;
__u16 client_index;
} client_id;
__u32 record_type;
__u32 transaction_id;
LOG_RECORD_FLAGS flags;
__u16 reserved_or_alignment[3];
现在在结构中的偏移量为0x30
__u16 redo_operation;
__u16 undo_operation;
__u16 redo_offset;
__u16 redo_length;
__u16 undo_offset;
__u16 undo_length;
__u16 target_attribute;
__u16 lcns_to_follow; Number of lcn_list entries following this entry.
__u16 record_offset;
__u16 attribute_offset;
__u32 alignment_or_reserved;
__u32 target_vcn;
__u32 alignment_or_reserved1;
struct { Only present if lcns_to_follow is not 0.
__u32 lcn;
__u32 alignment_or_reserved;
} lcn_list[0];
} LOG_RECORD;
重新启动区有一个指针到日志区,比如第一个和最后一个写入的日志记录以及最后一个写入的检查
点记录。如果重新启动区出现问题,恢复起来将十分困难--因此要有两个重新启动区的拷贝。
单独的日志记录用逻辑序列号(LSNs)识别.虽然日志区被层层包围,但(LSNs)不是,所以它们被用以
代替日志文件中的偏移量来识别日志记录。
任何有关元数据的修改(比如更新文件系统打开的时间标签)将导致日志文件动作,继而会导致重
新启动区变化。这些有害比特一般是隐藏的:如果最后的日志记录表明没有未完的任务那么文件系
统就是干净的。