diff --git a/include/ntfs/logfile.h b/include/ntfs/logfile.h index 11686539..ba72bc8a 100644 --- a/include/ntfs/logfile.h +++ b/include/ntfs/logfile.h @@ -26,23 +26,12 @@ #include "endians.h" #include "layout.h" -typedef enum { - magic_RSTR = const_cpu_to_le32(0x52545352), /* "RSTR", restart area */ - magic_RCRD = const_cpu_to_le32(0x44524352), /* "RCRD", log record */ -} LOG_FILE_RECORD_TYPES; - -/* - * Specialised magic comparison macros. - */ -#define ntfs_is_rstr_record(x) ( ntfs_is_magic (x, RSTR) ) -#define ntfs_is_rstr_recordp(p) ( ntfs_is_magicp(p, RSTR) ) -#define ntfs_is_rcrd_record(x) ( ntfs_is_magic (x, RCRD) ) -#define ntfs_is_rcrd_recordp(p) ( ntfs_is_magicp(p, RCRD) ) - /* * Log file organization: - * Two restart areas present in the first two pages (restart pages). When - * the volume is unmounted they should be identical. + * + * Two restart areas present in the first two pages (restart pages, one restart + * area in each page). When the volume is unmounted they should be identical. + * * These are followed by log records organized in pages headed by a record * header going up to log file size. Not all pages contain log records when a * volume is first formatted, but as the volume ages, all records will be used. @@ -50,6 +39,12 @@ typedef enum { * modifying the oldest_lsn to a higher value presumably) and writing begins * at the beginning of the file. Effectively, the log file is viewed as a * circular entity. + * + * NOTE: Windows NT, 2000, and XP all use log file version 1.1 but they accept + * versions <= 1.x, including -1.-1. (Yes, these are minus ones in there!) We + * probably only want to support 1.1 as this seems to be the current version + * and we don't know how that differs from the older versions -1.-1, 0.x, and + * 1.0 */ /* @@ -58,118 +53,118 @@ typedef enum { typedef struct { /* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */ NTFS_RECORD_TYPES magic;/* The magic is "RSTR". */ - u16 usa_ofs; /* See NTFS_RECORD definition above. */ - u16 usa_count; /* See NTFS_RECORD definition above. */ + u16 usa_ofs; /* See NTFS_RECORD definition in layout.h. + When creating, set this to be immediately + after this header structure (without any + alignment). */ + u16 usa_count; /* See NTFS_RECORD definition in layout.h. */ - LSN chkdsk_lsn; /* The check disk log file sequence number for - this restart page. Only used when the - magic is changed to "CHKD". = 0 */ - u32 system_page_size; /* Byte size of system pages, has to be >= 512 - and a power of 2. Use this to calculate the - required size of the usa and add this to the - ntfs.usa_offset value. Then verify that the - result is less than the value of the - restart_offset. = 0x1000 */ - u32 log_page_size; /* Byte size of log file records, has to be - >= 512 and a power of 2. = 0x1000 */ - u16 restart_offset; /* Byte offset from the start of the record to - the restart record. Value has to be aligned - to 8-byte boundary. = 0x30 */ - s16 minor_ver; /* Log file minor version. Only check if major - version is 1. (=1 but >=1 is treated the - same and <=0 is also ok) */ - u16 major_ver; /* Log file major version (=1 but =0 is ok) */ + LSN chkdsk_lsn; /* The last log file sequence number found by + chkdsk. Only used when the magic is changed + to "CHKD". Otherwise this is zero. */ + u32 system_page_size; /* Byte size of system pages when the log file + was created, has to be >= 512 and a power of + 2. Use this to calculate the required size + of the usa (usa_count) and add it to usa_ofs. + Then verify that the result is less than the + value of the restart_offset. */ + u32 log_page_size; /* Byte size of log file records, has to be >= + 512 and a power of 2. Usually is 4096 (or + is it just set to system_page_size?). */ + u16 restart_offset; /* Byte offset from the start of this header to + the RESTART_AREA. Value has to be aligned + to 8-byte boundary. When creating, set this + to be after the usa. */ + s16 minor_ver; /* Log file minor version. Only check if major + version is 1. */ + s16 major_ver; /* Log file major version. We only support + version 1.1. */ } __attribute__ ((__packed__)) RESTART_PAGE_HEADER; /* - * Log file restart area record. The offset of this record is found by adding + * Log file restart area record. The offset of this record is found by adding * the offset of the RESTART_PAGE_HEADER to the restart_offset value found in - * it. + * it. See notes at restart_offset above. */ typedef struct { - LSN current_lsn; /* Log file record. = 0x700000, 0x700808 */ - u16 log_clients; /* Number of log client records following - the restart_area. = 1 */ - s16 client_free_list; /* How many clients are free(?). If != 0xffff, + LSN current_lsn; /* The current LSN inside the log when the + restart area was last written. This happens + often but what is the interval? Is it just + fixed time or is it every time a check point + is written or somethine else? */ + u16 log_clients; /* Number of log client records in the array of + log client records which follows this + restart area. Must be 1. */ + u16 client_free_list; /* How many log client records are free in the + array of log client records. If != 0xffff, check that log_clients > client_free_list. = 0xffff */ - s16 client_in_use_list;/* How many clients are in use(?). If != 0xffff - check that log_clients > client_in_use_list. - = 0 */ - u16 flags; /* ??? = 0 */ - u32 seq_number_bits; /* ??? = 0x2c or 0x2d */ - u16 restart_area_length;/* Length of the restart area. Following + u16 client_in_use_list; /* How many log client records are in use in + the array of log client records. If != + 0xffff check that log_clients > + client_in_use_list. = 0 */ + u16 flags; /* Flags modifying LFS behaviour. = 0 */ + u32 seq_number_bits; /* How many bits to use for the sequence + number. I have seen 0x2c and 0x2d. */ + u16 restart_area_length;/* Length of the restart area. Following checks required if version matches. - Otherwise, skip them. restart_offset + + Otherwise, skip them. restart_offset + restart_area_length has to be <= - system_page_size. Also, restart_area_length + system_page_size. Also, restart_area_length has to be >= client_array_offset + - (log_clients * 0xa0). = 0xd0 */ + (log_clients * 0xa0). = 0xd0 */ u16 client_array_offset;/* Offset from the start of this record to - the first client record if versions are - matched. The offset is otherwise assumed to - be (sizeof(RESTART_AREA) + 7) & ~7, i.e. - rounded up to first 8-byte boundary. Either - way, the offset to the client array has to be - aligned to an 8-byte boundary. Also, - restart_offset + offset to the client array - have to be <= 510. Also, the offset to the - client array + (log_clients * 0xa0) have to - be <= SystemPageSize. = 0x30 */ - s64 file_size; /* Byte size of the log file. If the + the first log client record if versions are + matched. When creating, set this to be + after this restart area structure, aligned + to 8-bytes boundary. If the versions do not + match, the offset is otherwise assumed to be + (sizeof(RESTART_AREA) + 7) & ~7, i.e. + rounded up to first 8-byte boundary. Either + way, client_array_offset has to be aligned + to an 8-byte boundary. Also, restart_offset + + client_array_offset has to be <= 510. + Finally, client_array_offset + (log_clients + * 0xa0) has to be <= system_page_size. */ + s64 file_size; /* Byte size of the log file. If the restart_offset + the offset of the file_size - are > 510 then corruption has occured. This + are > 510 then corruption has occured. This is the very first check when starting with the restart_area as if it fails it means that some of the above values will be corrupted by the multi sector transfer - protection! If the structure is deprotected + protection! If the structure is deprotected then these checks are futile of course. Calculate the file_size bits and check that seq_number_bits == 0x43 - file_size bits. = 0x400000 */ u32 last_lsn_data_length;/* ??? = 0, 0x40 */ - u16 record_length; /* Byte size of this record. If the version + u16 record_length; /* Byte size of log records. If the version matches then check that the value of record_length is a multiple of 8, i.e. (record_length + 7) & ~7 == record_length. = 0x30 */ u16 log_page_data_offset;/* ??? = 0x40 */ - /* - * There are eight bytes here at offset 0x58, which contain a value, - * which we don't know what it means. It looks like it could be a - * 64-bit number or a 32-bit plus something else (the second 32-bits - * are zero so can't tell). Have to try to zero it and see if Windows - * copes with this. - */ + u32 unknown; /* ??? = 0 */ + u32 reserved; /* Reserved/alignment to 8-byte boundary. */ } __attribute__ ((__packed__)) RESTART_AREA; /* - * Log file restart client. The offset of this record is found by adding - * the offset of the RESTART_AREA to the client_array_offset value found in it. + * Log client record. The offset of this record is found by adding the offset + * of the RESTART_AREA to the client_array_offset value found in it. */ typedef struct { - LSN oldest_lsn; /* Oldest log file sequence number for this - client record. */ - LSN client_restart_lsn; /* Log file sequence number at which to - restart the volume, i.e. the current - position within the logfile. */ - s16 prev_client; /* ??? = 0xffff */ - s16 next_client; /* ??? = 0xffff */ - u64 seq_number; /* ??? = 1, size uncertain, Regis calls this - "volume clear flag" and gives a size of one - byte. */ - u32 client_name_length; /* ??? length of client name in bytes. = 8, - size uncertain, offset uncertain */ - uchar_t client_name[0]; /* ??? Name of the client in unicode. = NTFS */ - /* - * Or it could be the client name is fixed size like in attr def struct - * and the 8 means something else. Favouring this is that the - * RESTART_CLIENT struct is assumed to be fixed size of 0xa0 bytes, - * just like the attr def struct! There might be parallels to be drawn - * between the two. - */ -} __attribute__ ((__packed__)) RESTART_CLIENT; + LSN oldest_lsn; /* Oldest LSN needed by this client. */ + LSN client_restart_lsn; /* LSN at which this client needs to restart + the volume, i.e. the current position within + the log file. */ + u16 prev_client; /* ??? = 0xffff */ + u16 next_client; /* ??? = 0xffff */ + u16 seq_number; /* ??? = 1 */ + u8 reserved[6]; /* Reserved/alignment. */ + u32 client_name_length; /* Length of client name in bytes. = 8 */ + uchar_t client_name[64];/* Name of the client in Unicode. = NTFS */ +} __attribute__ ((__packed__)) LOG_CLIENT_RECORD; /* * Log page record page header. Each log page begins with this header and is @@ -180,26 +175,30 @@ typedef struct { typedef struct { /* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */ NTFS_RECORD_TYPES magic;/* Usually the magic is "RCRD". */ - u16 usa_ofs; /* See NTFS_RECORD definition above. */ - u16 usa_count; /* See NTFS_RECORD definition above. */ + u16 usa_ofs; /* See NTFS_RECORD definition in layout.h. + When creating, set this to be immediately + after this header structure (without any + alignment). */ + u16 usa_count; /* See NTFS_RECORD definition in layout.h. */ union { LSN last_lsn; - u32 file_offset; + s64 file_offset; } __attribute__ ((__packed__)) copy; u32 flags; u16 page_count; u16 page_position; union { struct { - u64 next_record_offset; + u16 next_record_offset; + u8 reserved[6]; LSN last_end_lsn; } __attribute__ ((__packed__)) packed; } __attribute__ ((__packed__)) header; } __attribute__ ((__packed__)) RECORD_PAGE_HEADER; /* - * Possible flags for log records. + * Possible 16-bit flags for log records. (Or is it log record pages?) */ typedef enum { LOG_RECORD_MULTI_PAGE = const_cpu_to_le16(0x0001), /* ??? */ @@ -209,7 +208,15 @@ typedef enum { } __attribute__ ((__packed__)) LOG_RECORD_FLAGS; /* - * Log record header. Each log record seems to have a constant size of 0x70 + * The log client id structure identifying a log client. + */ +typedef struct { + u16 seq_number; + u16 client_index; +} __attribute__ ((__packed__)) LOG_CLIENT_ID; + +/* + * Log record header. Each log record seems to have a constant size of 0x70 * bytes. */ typedef struct { @@ -217,13 +224,10 @@ typedef struct { LSN client_previous_lsn; LSN client_undo_next_lsn; u32 client_data_length; - struct { - u16 seq_number; - u16 client_index; - } __attribute__ ((__packed__)) client_id; + LOG_CLIENT_ID client_id; u32 record_type; u32 transaction_id; - LOG_RECORD_FLAGS flags; + u16 flags; u16 reserved_or_alignment[3]; /* Now are at ofs 0x30 into struct. */ u16 redo_operation;