| /* |
| * 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))) |
| |
| enum LOG_RECORD_TYPE { |
| LOG_STANDARD = 1, |
| LOG_CHECKPOINT = 2 |
| } ; |
| |
| /* These flags were introduced in Vista in field attribute_flags */ |
| enum ATTRIBUTE_FLAGS { |
| ACTS_ON_MFT = 2, |
| ACTS_ON_INDX = 8 |
| } ; |
| |
| 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 */ |
| } ; |
| |
| /* Flags for field log_record_flags, their meaning is unclear */ |
| enum RECORD_FLAGS { |
| RECORD_UNKNOWN = 1, |
| /* The flags below were introduced in Windows 10 */ |
| RECORD_DELETING = 2, |
| RECORD_ADDING = 4 |
| } ; |
| typedef le16 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 RESTART_PAGE_HEADER { /* size 32 */ |
| NTFS_RECORD head; |
| leLSN chkdsk_lsn; |
| le32 system_page_size; |
| le32 log_page_size; |
| le16 restart_offset; |
| le16 minor_ver; |
| le16 major_ver; |
| le16 usn; |
| } __attribute__((__packed__)) RESTART_PAGE_HEADER; |
| |
| /* ntfsdoc p 40 (48), not in layout.h */ |
| |
| struct RESTART_AREA { /* 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 record_length; |
| le16 log_page_data_offset; |
| le32 restart_log_open_count; |
| } __attribute__((__packed__)) ; |
| |
| typedef struct RESTART_CLIENT { /* 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 */ |
| |
| struct RECORD_PAGE_HEADER { /* size 40 */ |
| NTFS_RECORD head; /* the magic is "RCRD" */ |
| union { |
| leLSN last_lsn; |
| le32 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__)) ; |
| |
| /* ntfsdoc p 42 (50), not in layout.h */ |
| |
| #define LOG_RECORD_HEAD_SZ 0x30 /* size of header of struct LOG_RECORD */ |
| |
| typedef struct LOG_RECORD { /* 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; |
| le32 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; |
| le16 attribute_flags; |
| le32 target_vcn; |
| le32 reserved3; |
| 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 { |
| struct RESTART_PAGE_HEADER restart; |
| struct 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; |
| struct 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; |
| } ; |
| |
| /* Danger in arrays : contains le64's though size is not a multiple of 8 */ |
| typedef struct ATTR_OLD { /* 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 ATTR_NEW { /* 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 struct RESTART_AREA restart; |
| extern struct RESTART_CLIENT 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 struct 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 struct LOG_RECORD *logr); |
| u32 get_redo_offset(const struct LOG_RECORD *logr); |
| u32 get_extra_offset(const struct 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); |