词汇

文件 - $LogFile (2)

前一页 后一页

概述

属性

类型 描述 名称
0x10 标准信息文件 ($STANDARD_INFORMATION)  
0x30 文件名文件 ($FILE_NAME) $LogFile
0x80 数据文件 ($DATA) [未命名]

文件结构

未命名数据流

对日志文件了解很少

注意

其他信息

日志区域是由一个4KB的日志记录序列组成的,每个日志记录结构如下:

    偏移(长度)        内容
    0(4)             幻数 'RCRD'
    1E(12)           修正或固定
    

按照推测,日志记录包含一序列不同大小的记录,它们的结构不清楚。文件2是$LogFile,它包含处理事务的 记录以保证在系统瘫痪的时候数据的完整性。如37页提到的,它由2个重新启动区的拷贝和无限的日志区组成。

如果要把一个文件写到一个存储单元上,你必须修正这个文件本身以添加此文件系统的一些表格(例如文件 数据)。在此,你要经过两个操作步骤(修正文件自身,修正文件数据)。

如果此项任务完成,可以确认文件被写到存储单元上,并且文件系统处于定义的状态。

如果不能完成此项任务(例如如果系统瘫痪或日常的系统故障),则文件系统处于未定义状态。把它恢复到 定义(规定)状态的唯一途径(此操作称为“击退”)是把它放进一个特殊文件里,日志文件,那么就成功完成了 对此项任务的操作。

在系统故障后第一次进入磁盘时,系统读取日志文件并“击退”最近一项任务开端的所有操作。

    日志文件结构:
    两个重新启动区分布在最初的两页(重新启动页),如果卷没有被布置过,它们是一致的。
    
    然后是日志记录。它以一个记录标题开头,接着是日志文件大小。当卷被第一次格式化时不
    是所有的页面都包含日志记录,而是卷龄,所有的记录都会在用。当日志文件填充满时,处
    于开始位置的记录就会被清除(大概是通过修改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)不是,所以它们被用以
    代替日志文件中的偏移量来识别日志记录。   
    
    任何有关元数据的修改(比如更新文件系统打开的时间标签)将导致日志文件动作,继而会导致重
    新启动区变化。这些有害比特一般是隐藏的:如果最后的日志记录表明没有未完的任务那么文件系
    统就是干净的。    

Online 中文在线 Validate HTML Validate CSS $Id: logfile.html,v 1.11 2001/07/11 16:31:45 flatcap Exp $