词汇 |
类型 | 描述 | 名称 |
---|---|---|
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)不是,所以它们被用以 代替日志文件中的偏移量来识别日志记录。 任何有关元数据的修改(比如更新文件系统打开的时间标签)将导致日志文件动作,继而会导致重 新启动区变化。这些有害比特一般是隐藏的:如果最后的日志记录表明没有未完的任务那么文件系 统就是干净的。