Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Declarations for processing log data |
| 3 | * |
| 4 | * Copyright (c) 2000-2005 Anton Altaparmakov |
| 5 | * Copyright (c) 2014-2015 Jean-Pierre Andre |
| 6 | */ |
| 7 | |
| 8 | /* |
| 9 | * This program is free software; you can redistribute it and/or modify |
| 10 | * it under the terms of the GNU General Public License as published by |
| 11 | * the Free Software Foundation; either version 2 of the License, or |
| 12 | * (at your option) any later version. |
| 13 | * |
| 14 | * This program is distributed in the hope that it will be useful, |
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 17 | * GNU General Public License for more details. |
| 18 | * |
| 19 | * You should have received a copy of the GNU General Public License |
| 20 | * along with this program (in the main directory of the NTFS-3G |
| 21 | * distribution in the file COPYING); if not, write to the Free Software |
| 22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 23 | */ |
| 24 | |
| 25 | /* |
| 26 | * TODO |
| 27 | * This file partially duplicates logfile.h (with modifications). |
| 28 | * The generic declarations are to be moved to logfile.h, thus |
| 29 | * implying adapting (at least) libntfs-3g/logfile.c and |
| 30 | * ntfsprogs/ntfsdump_logfile.c, and the declarations specific to |
| 31 | * ntfsrecover should be kept in this file. |
| 32 | * (removing ntfsdump_logfile.c might also be considered). |
| 33 | */ |
| 34 | |
| 35 | #define getle16(p,x) le16_to_cpu(*(const le16*)((const char*)(p) + (x))) |
| 36 | #define getle32(p,x) le32_to_cpu(*(const le32*)((const char*)(p) + (x))) |
| 37 | #define getle64(p,x) le64_to_cpu(*(const le64*)((const char*)(p) + (x))) |
| 38 | |
| 39 | #define feedle16(p,x) (*(const le16*)((const char*)(p) + (x))) |
| 40 | #define feedle32(p,x) (*(const le32*)((const char*)(p) + (x))) |
| 41 | #define feedle64(p,x) (*(const le64*)((const char*)(p) + (x))) |
| 42 | |
| 43 | enum LOG_RECORD_TYPE { |
| 44 | LOG_STANDARD = 1, |
| 45 | LOG_CHECKPOINT = 2 |
| 46 | } ; |
| 47 | |
| 48 | /* These flags were introduced in Vista in field attribute_flags */ |
| 49 | enum ATTRIBUTE_FLAGS { |
| 50 | ACTS_ON_MFT = 2, |
| 51 | ACTS_ON_INDX = 8 |
| 52 | } ; |
| 53 | |
| 54 | enum ACTIONS { |
| 55 | Noop, /* 0 */ |
| 56 | CompensationlogRecord, /* 1 */ |
| 57 | InitializeFileRecordSegment, /* 2 */ |
| 58 | DeallocateFileRecordSegment, /* 3 */ |
| 59 | WriteEndofFileRecordSegment, /* 4 */ |
| 60 | CreateAttribute, /* 5 */ |
| 61 | DeleteAttribute, /* 6 */ |
| 62 | UpdateResidentValue, /* 7 */ |
| 63 | UpdateNonResidentValue, /* 8 */ |
| 64 | UpdateMappingPairs, /* 9 */ |
| 65 | DeleteDirtyClusters, /* 10 */ |
| 66 | SetNewAttributeSizes, /* 11 */ |
| 67 | AddIndexEntryRoot, /* 12 */ |
| 68 | DeleteIndexEntryRoot, /* 13 */ |
| 69 | AddIndexEntryAllocation, /* 14 */ |
| 70 | DeleteIndexEntryAllocation, /* 15 */ |
| 71 | WriteEndOfIndexBuffer, /* 16 */ |
| 72 | SetIndexEntryVcnRoot, /* 17 */ |
| 73 | SetIndexEntryVcnAllocation, /* 18 */ |
| 74 | UpdateFileNameRoot, /* 19 */ |
| 75 | UpdateFileNameAllocation, /* 20 */ |
| 76 | SetBitsInNonResidentBitMap, /* 21 */ |
| 77 | ClearBitsInNonResidentBitMap, /* 22 */ |
| 78 | HotFix, /* 23 */ |
| 79 | EndTopLevelAction, /* 24 */ |
| 80 | PrepareTransaction, /* 25 */ |
| 81 | CommitTransaction, /* 26 */ |
| 82 | ForgetTransaction, /* 27 */ |
| 83 | OpenNonResidentAttribute, /* 28 */ |
| 84 | OpenAttributeTableDump, /* 29 */ |
| 85 | AttributeNamesDump, /* 30 */ |
| 86 | DirtyPageTableDump, /* 31 */ |
| 87 | TransactionTableDump, /* 32 */ |
| 88 | UpdateRecordDataRoot, /* 33 */ |
| 89 | UpdateRecordDataAllocation, /* 34 */ |
| 90 | Win10Action35, /* 35 */ |
| 91 | Win10Action36, /* 36 */ |
| 92 | Win10Action37, /* 37 */ |
| 93 | LastAction /* 38 */ |
| 94 | } ; |
| 95 | |
| 96 | /* Flags for field log_record_flags, their meaning is unclear */ |
| 97 | enum RECORD_FLAGS { |
| 98 | RECORD_UNKNOWN = 1, |
| 99 | /* The flags below were introduced in Windows 10 */ |
| 100 | RECORD_DELETING = 2, |
| 101 | RECORD_ADDING = 4 |
| 102 | } ; |
| 103 | typedef le16 LOG_RECORD_FLAGS; |
| 104 | |
| 105 | #define LOGFILE_NO_CLIENT const_cpu_to_le16(0xffff) |
| 106 | #define RESTART_VOLUME_IS_CLEAN const_cpu_to_le16(0x0002) |
| 107 | |
| 108 | /* ntfsdoc p 39 (47), not in layout.h */ |
| 109 | |
| 110 | typedef struct RESTART_PAGE_HEADER { /* size 32 */ |
| 111 | NTFS_RECORD head; |
| 112 | leLSN chkdsk_lsn; |
| 113 | le32 system_page_size; |
| 114 | le32 log_page_size; |
| 115 | le16 restart_offset; |
| 116 | le16 minor_ver; |
| 117 | le16 major_ver; |
| 118 | le16 usn; |
| 119 | } __attribute__((__packed__)) RESTART_PAGE_HEADER; |
| 120 | |
| 121 | /* ntfsdoc p 40 (48), not in layout.h */ |
| 122 | |
| 123 | struct RESTART_AREA { /* size 44 */ |
| 124 | leLSN current_lsn; |
| 125 | le16 log_clients; |
| 126 | le16 client_free_list; |
| 127 | le16 client_in_use_list; |
| 128 | le16 flags; |
| 129 | le32 seq_number_bits; |
| 130 | le16 restart_area_length; |
| 131 | le16 client_array_offset; |
| 132 | le64 file_size; |
| 133 | le32 last_lsn_data_length; |
| 134 | le16 record_length; |
| 135 | le16 log_page_data_offset; |
| 136 | le32 restart_log_open_count; |
| 137 | } __attribute__((__packed__)) ; |
| 138 | |
| 139 | typedef struct RESTART_CLIENT { /* size 160 */ |
| 140 | /*Ofs*/ |
| 141 | /* 0*/ leLSN oldest_lsn; /* Oldest LSN needed by this client. On create |
| 142 | set to 0. */ |
| 143 | /* 8*/ leLSN client_restart_lsn;/* LSN at which this client needs to restart |
| 144 | the volume, i.e. the current position within |
| 145 | the log file. At present, if clean this |
| 146 | should = current_lsn in restart area but it |
| 147 | probably also = current_lsn when dirty most |
| 148 | of the time. At create set to 0. */ |
| 149 | /* 16*/ le16 prev_client; /* The offset to the previous log client record |
| 150 | in the array of log client records. |
| 151 | LOGFILE_NO_CLIENT means there is no previous |
| 152 | client record, i.e. this is the first one. |
| 153 | This is always LOGFILE_NO_CLIENT. */ |
| 154 | /* 18*/ le16 next_client; /* The offset to the next log client record in |
| 155 | the array of log client records. |
| 156 | LOGFILE_NO_CLIENT means there are no next |
| 157 | client records, i.e. this is the last one. |
| 158 | This is always LOGFILE_NO_CLIENT. */ |
| 159 | /* 20*/ le16 seq_number; /* On Win2k and presumably earlier, this is set |
| 160 | to zero every time the logfile is restarted |
| 161 | and it is incremented when the logfile is |
| 162 | closed at dismount time. Thus it is 0 when |
| 163 | dirty and 1 when clean. On WinXP and |
| 164 | presumably later, this is always 0. */ |
| 165 | /* 22*/ u8 reserved[6]; /* Reserved/alignment. */ |
| 166 | /* 28*/ le32 client_name_length;/* Length of client name in bytes. Should |
| 167 | always be 8. */ |
| 168 | /* 32*/ le16 client_name[64]; /* Name of the client in Unicode. Should |
| 169 | always be "NTFS" with the remaining bytes |
| 170 | set to 0. */ |
| 171 | /* sizeof() = 160 (0xa0) bytes */ |
| 172 | } __attribute__((__packed__)) LOG_CLIENT_RECORD; |
| 173 | |
| 174 | /* ntfsdoc p 41 (49), not in layout.h */ |
| 175 | |
| 176 | struct RECORD_PAGE_HEADER { /* size 40 */ |
| 177 | NTFS_RECORD head; /* the magic is "RCRD" */ |
| 178 | union { |
| 179 | leLSN last_lsn; |
| 180 | le32 file_offset; |
| 181 | } __attribute__((__packed__)) copy; |
| 182 | le32 flags; |
| 183 | le16 page_count; |
| 184 | le16 page_position; |
| 185 | le16 next_record_offset; |
| 186 | le16 reserved4[3]; |
| 187 | leLSN last_end_lsn; |
| 188 | } __attribute__((__packed__)) ; |
| 189 | |
| 190 | /* ntfsdoc p 42 (50), not in layout.h */ |
| 191 | |
| 192 | #define LOG_RECORD_HEAD_SZ 0x30 /* size of header of struct LOG_RECORD */ |
| 193 | |
| 194 | typedef struct LOG_RECORD { /* size 80 */ |
| 195 | leLSN this_lsn; |
| 196 | leLSN client_previous_lsn; |
| 197 | leLSN client_undo_next_lsn; |
| 198 | le32 client_data_length; |
| 199 | struct { |
| 200 | le16 seq_number; |
| 201 | le16 client_index; |
| 202 | } __attribute__((__packed__)) client_id; |
| 203 | le32 record_type; |
| 204 | le32 transaction_id; |
| 205 | LOG_RECORD_FLAGS log_record_flags; |
| 206 | le16 reserved1[3]; |
| 207 | le16 redo_operation; |
| 208 | le16 undo_operation; |
| 209 | le16 redo_offset; |
| 210 | le16 redo_length; |
| 211 | union { |
| 212 | struct { |
| 213 | le16 undo_offset; |
| 214 | le16 undo_length; |
| 215 | le16 target_attribute; |
| 216 | le16 lcns_to_follow; |
| 217 | le16 record_offset; |
| 218 | le16 attribute_offset; |
| 219 | le16 cluster_index; |
| 220 | le16 attribute_flags; |
| 221 | le32 target_vcn; |
| 222 | le32 reserved3; |
| 223 | le64 lcn_list[0]; |
| 224 | } __attribute__((__packed__)); |
| 225 | struct { |
| 226 | leLSN transaction_lsn; |
| 227 | leLSN attributes_lsn; |
| 228 | leLSN names_lsn; |
| 229 | leLSN dirty_pages_lsn; |
| 230 | le64 unknown_list[0]; |
| 231 | } __attribute__((__packed__)); |
| 232 | } __attribute__((__packed__)); |
| 233 | } __attribute__((__packed__)) LOG_RECORD; |
| 234 | |
| 235 | struct BUFFER { |
| 236 | unsigned int num; |
| 237 | unsigned int size; |
| 238 | unsigned int headsz; |
| 239 | BOOL safe; |
| 240 | union { |
| 241 | struct RESTART_PAGE_HEADER restart; |
| 242 | struct RECORD_PAGE_HEADER record; |
| 243 | char data[1]; |
| 244 | } block; /* variable length, keep at the end */ |
| 245 | } ; |
| 246 | |
| 247 | struct ACTION_RECORD { |
| 248 | struct ACTION_RECORD *next; |
| 249 | struct ACTION_RECORD *prev; |
| 250 | int num; |
| 251 | unsigned int flags; |
| 252 | struct LOG_RECORD record; /* variable length, keep at the end */ |
| 253 | } ; |
| 254 | |
| 255 | enum { /* Flag values for ACTION_RECORD */ |
| 256 | ACTION_TO_REDO = 1 /* Committed, possibly not synced */ |
| 257 | } ; |
| 258 | |
| 259 | struct ATTR { |
| 260 | u64 inode; |
| 261 | u64 lsn; |
| 262 | le32 type; |
| 263 | u16 key; |
| 264 | u16 namelen; |
| 265 | le16 name[1]; |
| 266 | } ; |
| 267 | |
| 268 | struct BITMAP_ACTION { |
| 269 | le32 firstbit; |
| 270 | le32 count; |
| 271 | } ; |
| 272 | |
| 273 | /* Danger in arrays : contains le64's though size is not a multiple of 8 */ |
| 274 | typedef struct ATTR_OLD { /* Format up to Win10 (44 bytes) */ |
| 275 | le64 unknown1; |
| 276 | le64 unknown2; |
| 277 | le64 inode; |
| 278 | leLSN lsn; |
| 279 | le32 unknown3; |
| 280 | le32 type; |
| 281 | le32 unknown4; |
| 282 | } __attribute__((__packed__)) ATTR_OLD; |
| 283 | |
| 284 | typedef struct ATTR_NEW { /* Format since Win10 (40 bytes) */ |
| 285 | le64 unknown1; |
| 286 | le64 unknown2; |
| 287 | le32 type; |
| 288 | le32 unknown3; |
| 289 | le64 inode; |
| 290 | leLSN lsn; |
| 291 | } __attribute__((__packed__)) ATTR_NEW; |
| 292 | |
| 293 | extern u32 clustersz; |
| 294 | extern int clusterbits; |
| 295 | extern u32 blocksz; |
| 296 | extern int blockbits; |
| 297 | extern u16 bytespersect; |
| 298 | extern u64 mftlcn; |
| 299 | extern u32 mftrecsz; |
| 300 | extern int mftrecbits; |
| 301 | extern u32 mftcnt; /* number of entries */ |
| 302 | extern BOOL optc; |
| 303 | extern BOOL optn; |
| 304 | extern int opts; |
| 305 | extern int optv; |
| 306 | extern unsigned int redocount; |
| 307 | extern unsigned int undocount; |
| 308 | extern ntfs_inode *log_ni; |
| 309 | extern ntfs_attr *log_na; |
| 310 | extern u64 logfilelcn; |
| 311 | extern u32 logfilesz; /* bytes */ |
| 312 | extern u64 redos_met; |
| 313 | extern u64 committed_lsn; |
| 314 | extern u64 synced_lsn; |
| 315 | extern u64 latest_lsn; |
| 316 | extern u64 restart_lsn; |
| 317 | |
| 318 | extern struct RESTART_AREA restart; |
| 319 | extern struct RESTART_CLIENT client; |
| 320 | |
| 321 | const char *actionname(int op); |
| 322 | const char *mftattrname(ATTR_TYPES attr); |
| 323 | void showname(const char *prefix, const char *name, int cnt); |
| 324 | int fixnamelen(const char *name, int len); |
| 325 | BOOL within_lcn_range(const struct LOG_RECORD *logr); |
| 326 | struct ATTR *getattrentry(unsigned int key, unsigned int lth); |
| 327 | void copy_attribute(struct ATTR *pa, const char *buf, int length); |
| 328 | u32 get_undo_offset(const struct LOG_RECORD *logr); |
| 329 | u32 get_redo_offset(const struct LOG_RECORD *logr); |
| 330 | u32 get_extra_offset(const struct LOG_RECORD *logr); |
| 331 | BOOL exception(int num); |
| 332 | |
| 333 | struct STORE; |
| 334 | BOOL ntfs_check_logfile(ntfs_attr *log_na, RESTART_PAGE_HEADER **rp); |
| 335 | extern int play_undos(ntfs_volume *vol, const struct ACTION_RECORD *firstundo); |
| 336 | extern int play_redos(ntfs_volume *vol, const struct ACTION_RECORD *firstredo); |
| 337 | extern void show_redos(void); |
| 338 | extern void freeclusterentry(struct STORE*); |
| 339 | void hexdump(const char *buf, unsigned int lth); |