/* * Declarations for processing log data * * Copyright (c) 2000-2005 Anton Altaparmakov * Copyright (c) 2014-2015 Jean-Pierre Andre */ /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program (in the main directory of the NTFS-3G * distribution in the file COPYING); if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * TODO * This file partially duplicates logfile.h (with modifications). * The generic declarations are to be moved to logfile.h, thus * implying adapting (at least) libntfs-3g/logfile.c and * ntfsprogs/ntfsdump_logfile.c, and the declarations specific to * ntfsrecover should be kept in this file. * (removing ntfsdump_logfile.c might also be considered). */ #define getle16(p,x) le16_to_cpu(*(const le16*)((const char*)(p) + (x))) #define getle32(p,x) le32_to_cpu(*(const le32*)((const char*)(p) + (x))) #define getle64(p,x) le64_to_cpu(*(const le64*)((const char*)(p) + (x))) #define feedle16(p,x) (*(const le16*)((const char*)(p) + (x))) #define feedle32(p,x) (*(const le32*)((const char*)(p) + (x))) #define feedle64(p,x) (*(const le64*)((const char*)(p) + (x))) /* * LOG_RECORD_TYPE : types of log records */ enum { LOG_STANDARD = const_cpu_to_le32(1), LOG_CHECKPOINT = const_cpu_to_le32(2), LOG_RECORD_TYPE_PLACE_HOLDER = 0xffffffffU } ; typedef le32 LOG_RECORD_TYPE; /* * ATTRIBUTE_FLAGS : flags describing the kind of NTFS record * is being updated. * These flags were introduced in Vista, only two flags are known? */ enum { ACTS_ON_MFT = const_cpu_to_le16(2), ACTS_ON_INDX = const_cpu_to_le16(8), ATTRIBUTE_FLAGS_PLACE_HOLDER = 0xffff, } ; typedef le16 ATTRIBUTE_FLAGS; enum ACTIONS { Noop, /* 0 */ CompensationlogRecord, /* 1 */ InitializeFileRecordSegment, /* 2 */ DeallocateFileRecordSegment, /* 3 */ WriteEndofFileRecordSegment, /* 4 */ CreateAttribute, /* 5 */ DeleteAttribute, /* 6 */ UpdateResidentValue, /* 7 */ UpdateNonResidentValue, /* 8 */ UpdateMappingPairs, /* 9 */ DeleteDirtyClusters, /* 10 */ SetNewAttributeSizes, /* 11 */ AddIndexEntryRoot, /* 12 */ DeleteIndexEntryRoot, /* 13 */ AddIndexEntryAllocation, /* 14 */ DeleteIndexEntryAllocation, /* 15 */ WriteEndOfIndexBuffer, /* 16 */ SetIndexEntryVcnRoot, /* 17 */ SetIndexEntryVcnAllocation, /* 18 */ UpdateFileNameRoot, /* 19 */ UpdateFileNameAllocation, /* 20 */ SetBitsInNonResidentBitMap, /* 21 */ ClearBitsInNonResidentBitMap, /* 22 */ HotFix, /* 23 */ EndTopLevelAction, /* 24 */ PrepareTransaction, /* 25 */ CommitTransaction, /* 26 */ ForgetTransaction, /* 27 */ OpenNonResidentAttribute, /* 28 */ OpenAttributeTableDump, /* 29 */ AttributeNamesDump, /* 30 */ DirtyPageTableDump, /* 31 */ TransactionTableDump, /* 32 */ UpdateRecordDataRoot, /* 33 */ UpdateRecordDataAllocation, /* 34 */ Win10Action35, /* 35 */ Win10Action36, /* 36 */ Win10Action37, /* 37 */ LastAction /* 38 */ } ; /** * enum LOG_RECORD_FLAGS - Possible 16-bit flags for log records. * * Some flags describe what kind of update is being logged. * * (Or is it log record pages?) */ typedef enum { LOG_RECORD_MULTI_PAGE = const_cpu_to_le16(0x0001), /* ??? */ /* The flags below were introduced in Windows 10 */ LOG_RECORD_DELETING = const_cpu_to_le16(0x0002), LOG_RECORD_ADDING = const_cpu_to_le16(0x0004), LOG_RECORD_SIZE_PLACE_HOLDER = 0xffff, /* This has nothing to do with the log record. It is only so gcc knows to make the flags 16-bit. */ } __attribute__((__packed__)) LOG_RECORD_FLAGS; #define LOGFILE_NO_CLIENT const_cpu_to_le16(0xffff) #define RESTART_VOLUME_IS_CLEAN const_cpu_to_le16(0x0002) /* ntfsdoc p 39 (47), not in layout.h */ typedef struct { /* size 32 */ NTFS_RECORD_TYPES magic; le16 usa_ofs; le16 usa_count; leLSN chkdsk_lsn; le32 system_page_size; le32 log_page_size; le16 restart_area_offset; le16 minor_ver; le16 major_ver; le16 usn; } __attribute__((__packed__)) RESTART_PAGE_HEADER; /* ntfsdoc p 40 (48), not in layout.h */ typedef struct { /* size 44 */ leLSN current_lsn; le16 log_clients; le16 client_free_list; le16 client_in_use_list; le16 flags; le32 seq_number_bits; le16 restart_area_length; le16 client_array_offset; le64 file_size; le32 last_lsn_data_length; le16 log_record_header_length; le16 log_page_data_offset; le32 restart_log_open_count; } __attribute__((__packed__)) RESTART_AREA; typedef struct { /* size 160 */ /*Ofs*/ /* 0*/ leLSN oldest_lsn; /* Oldest LSN needed by this client. On create set to 0. */ /* 8*/ leLSN client_restart_lsn;/* LSN at which this client needs to restart the volume, i.e. the current position within the log file. At present, if clean this should = current_lsn in restart area but it probably also = current_lsn when dirty most of the time. At create set to 0. */ /* 16*/ le16 prev_client; /* The offset to the previous log client record in the array of log client records. LOGFILE_NO_CLIENT means there is no previous client record, i.e. this is the first one. This is always LOGFILE_NO_CLIENT. */ /* 18*/ le16 next_client; /* The offset to the next log client record in the array of log client records. LOGFILE_NO_CLIENT means there are no next client records, i.e. this is the last one. This is always LOGFILE_NO_CLIENT. */ /* 20*/ le16 seq_number; /* On Win2k and presumably earlier, this is set to zero every time the logfile is restarted and it is incremented when the logfile is closed at dismount time. Thus it is 0 when dirty and 1 when clean. On WinXP and presumably later, this is always 0. */ /* 22*/ u8 reserved[6]; /* Reserved/alignment. */ /* 28*/ le32 client_name_length;/* Length of client name in bytes. Should always be 8. */ /* 32*/ le16 client_name[64]; /* Name of the client in Unicode. Should always be "NTFS" with the remaining bytes set to 0. */ /* sizeof() = 160 (0xa0) bytes */ } __attribute__((__packed__)) LOG_CLIENT_RECORD; /* ntfsdoc p 41 (49), not in layout.h */ typedef struct { /* size 40 */ NTFS_RECORD_TYPES magic; le16 usa_ofs; le16 usa_count; union { leLSN last_lsn; sle64 file_offset; } __attribute__((__packed__)) copy; le32 flags; le16 page_count; le16 page_position; le16 next_record_offset; le16 reserved4[3]; leLSN last_end_lsn; } __attribute__((__packed__)) RECORD_PAGE_HEADER; /* ntfsdoc p 42 (50), not in layout.h */ #define LOG_RECORD_HEAD_SZ 0x30 /* size of header of struct LOG_RECORD */ typedef struct { /* size 80 */ leLSN this_lsn; leLSN client_previous_lsn; leLSN client_undo_next_lsn; le32 client_data_length; struct { le16 seq_number; le16 client_index; } __attribute__((__packed__)) client_id; LOG_RECORD_TYPE record_type; le32 transaction_id; LOG_RECORD_FLAGS log_record_flags; le16 reserved1[3]; le16 redo_operation; le16 undo_operation; le16 redo_offset; le16 redo_length; union { struct { le16 undo_offset; le16 undo_length; le16 target_attribute; le16 lcns_to_follow; le16 record_offset; le16 attribute_offset; le16 cluster_index; ATTRIBUTE_FLAGS attribute_flags; leVCN target_vcn; le64 lcn_list[0]; } __attribute__((__packed__)); struct { leLSN transaction_lsn; leLSN attributes_lsn; leLSN names_lsn; leLSN dirty_pages_lsn; le64 unknown_list[0]; } __attribute__((__packed__)); } __attribute__((__packed__)); } __attribute__((__packed__)) LOG_RECORD; struct BUFFER { unsigned int num; unsigned int size; unsigned int headsz; BOOL safe; union { RESTART_PAGE_HEADER restart; RECORD_PAGE_HEADER record; char data[1]; } block; /* variable length, keep at the end */ } ; struct ACTION_RECORD { struct ACTION_RECORD *next; struct ACTION_RECORD *prev; int num; unsigned int flags; LOG_RECORD record; /* variable length, keep at the end */ } ; enum { /* Flag values for ACTION_RECORD */ ACTION_TO_REDO = 1 /* Committed, possibly not synced */ } ; struct ATTR { u64 inode; u64 lsn; le32 type; u16 key; u16 namelen; le16 name[1]; } ; struct BITMAP_ACTION { le32 firstbit; le32 count; } ; /** * struct ATTR - Attribute record. * * The format of an attribute record has changed from Windows 10. * The old format was 44 bytes long, despite having 8 bytes fields, * and this leads to alignment problems in arrays. * This problem does not occur in the new format, which is shorter. * The format being used can generally be determined from size. */ typedef struct { /* Format up to Win10 (44 bytes) */ le64 unknown1; le64 unknown2; le64 inode; leLSN lsn; le32 unknown3; le32 type; le32 unknown4; } __attribute__((__packed__)) ATTR_OLD; typedef struct { /* Format since Win10 (40 bytes) */ le64 unknown1; le64 unknown2; le32 type; le32 unknown3; le64 inode; leLSN lsn; } __attribute__((__packed__)) ATTR_NEW; extern u32 clustersz; extern int clusterbits; extern u32 blocksz; extern int blockbits; extern u16 bytespersect; extern u64 mftlcn; extern u32 mftrecsz; extern int mftrecbits; extern u32 mftcnt; /* number of entries */ extern BOOL optc; extern BOOL optn; extern int opts; extern int optv; extern unsigned int redocount; extern unsigned int undocount; extern ntfs_inode *log_ni; extern ntfs_attr *log_na; extern u64 logfilelcn; extern u32 logfilesz; /* bytes */ extern u64 redos_met; extern u64 committed_lsn; extern u64 synced_lsn; extern u64 latest_lsn; extern u64 restart_lsn; extern RESTART_AREA restart; extern LOG_CLIENT_RECORD client; const char *actionname(int op); const char *mftattrname(ATTR_TYPES attr); void showname(const char *prefix, const char *name, int cnt); int fixnamelen(const char *name, int len); BOOL within_lcn_range(const LOG_RECORD *logr); struct ATTR *getattrentry(unsigned int key, unsigned int lth); void copy_attribute(struct ATTR *pa, const char *buf, int length); u32 get_undo_offset(const LOG_RECORD *logr); u32 get_redo_offset(const LOG_RECORD *logr); u32 get_extra_offset(const LOG_RECORD *logr); BOOL exception(int num); struct STORE; BOOL ntfs_check_logfile(ntfs_attr *log_na, RESTART_PAGE_HEADER **rp); extern int play_undos(ntfs_volume *vol, const struct ACTION_RECORD *firstundo); extern int play_redos(ntfs_volume *vol, const struct ACTION_RECORD *firstredo); extern void show_redos(void); extern void freeclusterentry(struct STORE*); void hexdump(const char *buf, unsigned int lth);