diff --git a/include/ntfs-3g/logfile.h b/include/ntfs-3g/logfile.h index 8ce7307b..d1f1222a 100644 --- a/include/ntfs-3g/logfile.h +++ b/include/ntfs-3g/logfile.h @@ -2,6 +2,7 @@ * logfile.h - Exports for $LogFile handling. Originated from the Linux-NTFS project. * * Copyright (c) 2000-2005 Anton Altaparmakov + * Copyright (c) 2016 Jean-Pierre Andre * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -102,8 +103,8 @@ typedef struct { * in this particular client array. Also inside the client records themselves, * this means that there are no client records preceding or following this one. */ -#define LOGFILE_NO_CLIENT const_cpu_to_le16(0xffff) #define LOGFILE_NO_CLIENT_CPU 0xffff +#define LOGFILE_NO_CLIENT const_cpu_to_le16(LOGFILE_NO_CLIENT_CPU) /* * These are the so far known RESTART_AREA_* flags (16-bit) which contain @@ -322,22 +323,23 @@ typedef struct { le32 flags; le16 page_count; le16 page_position; - union { - struct { - le16 next_record_offset; - u8 reserved[6]; - leLSN last_end_lsn; - } __attribute__((__packed__)) packed; - } __attribute__((__packed__)) header; + le16 next_record_offset; + le16 reserved[3]; + leLSN last_end_lsn; } __attribute__((__packed__)) RECORD_PAGE_HEADER; /** * 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. */ @@ -351,6 +353,32 @@ typedef struct { le16 client_index; } __attribute__((__packed__)) LOG_CLIENT_ID; +/* + * 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; + +#define LOG_RECORD_HEAD_SZ 0x30 /* size of header of struct LOG_RECORD */ + /** * struct LOG_RECORD - Log record header. * @@ -362,32 +390,79 @@ typedef struct { leLSN client_undo_next_lsn; le32 client_data_length; LOG_CLIENT_ID client_id; - le32 record_type; + LOG_RECORD_TYPE record_type; le32 transaction_id; - le16 flags; + LOG_RECORD_FLAGS log_record_flags; le16 reserved_or_alignment[3]; /* Now are at ofs 0x30 into struct. */ le16 redo_operation; le16 undo_operation; le16 redo_offset; le16 redo_length; - le16 undo_offset; - le16 undo_length; - le16 target_attribute; - le16 lcns_to_follow; /* Number of lcn_list entries + union { + struct { + le16 undo_offset; + le16 undo_length; + le16 target_attribute; + le16 lcns_to_follow; /* Number of lcn_list entries following this entry. */ /* Now at ofs 0x40. */ - le16 record_offset; - le16 attribute_offset; - le32 alignment_or_reserved; - leVCN target_vcn; + le16 record_offset; + le16 attribute_offset; + le16 cluster_index; + ATTRIBUTE_FLAGS attribute_flags; + leVCN target_vcn; /* Now at ofs 0x50. */ - struct { /* Only present if lcns_to_follow - is not 0. */ - leLCN lcn; - } __attribute__((__packed__)) lcn_list[0]; + leLCN lcn_list[0]; /* Only present if lcns_to_follow + is not 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 BITMAP_ACTION - Bitmap change being logged + */ + +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 BOOL ntfs_check_logfile(ntfs_attr *log_na, RESTART_PAGE_HEADER **rp); extern BOOL ntfs_is_logfile_clean(ntfs_attr *log_na, RESTART_PAGE_HEADER *rp); extern int ntfs_empty_logfile(ntfs_attr *na); diff --git a/ntfsprogs/ntfsdump_logfile.c b/ntfsprogs/ntfsdump_logfile.c index 074f87ef..2327cc19 100644 --- a/ntfsprogs/ntfsdump_logfile.c +++ b/ntfsprogs/ntfsdump_logfile.c @@ -557,17 +557,17 @@ static void dump_log_record(LOG_RECORD *lr) (unsigned int)le32_to_cpu(lr->record_type)); ntfs_log_info("transaction_id = 0x%x\n", (unsigned int)le32_to_cpu(lr->transaction_id)); - ntfs_log_info("flags = 0x%x:", le16_to_cpu(lr->flags)); - if (!lr->flags) + ntfs_log_info("flags = 0x%x:", le16_to_cpu(lr->log_record_flags)); + if (!lr->log_record_flags) ntfs_log_info(" NONE\n"); else { int _b = 0; - if (lr->flags & LOG_RECORD_MULTI_PAGE) { + if (lr->log_record_flags & LOG_RECORD_MULTI_PAGE) { ntfs_log_info(" LOG_RECORD_MULTI_PAGE"); _b = 1; } - if (lr->flags & ~LOG_RECORD_MULTI_PAGE) { + if (lr->log_record_flags & ~LOG_RECORD_MULTI_PAGE) { if (_b) ntfs_log_info(" |"); ntfs_log_info(" Unknown flags"); @@ -589,8 +589,8 @@ static void dump_log_record(LOG_RECORD *lr) if (le16_to_cpu(lr->lcns_to_follow) > 0) ntfs_log_info("Array of lcns:\n"); for (i = 0; i < le16_to_cpu(lr->lcns_to_follow); i++) - ntfs_log_info("lcn_list[%u].lcn = 0x%llx\n", i, (unsigned long long) - sle64_to_cpu(lr->lcn_list[i].lcn)); + ntfs_log_info("lcn_list[%u].lcn = 0x%llx\n", i, + (unsigned long long)sle64_to_cpu(lr->lcn_list[i])); } /** @@ -633,9 +633,9 @@ rcrd_pass_loc: ntfs_log_info("page count = %i\n", le16_to_cpu(rcrd->page_count)); ntfs_log_info("page position = %i\n", le16_to_cpu(rcrd->page_position)); ntfs_log_info("header.next_record_offset = 0x%llx\n", (unsigned long long) - le16_to_cpu(rcrd->header.packed.next_record_offset)); + le16_to_cpu(rcrd->next_record_offset)); ntfs_log_info("header.last_end_lsn = 0x%llx\n", (unsigned long long) - sle64_to_cpu(rcrd->header.packed.last_end_lsn)); + sle64_to_cpu(rcrd->last_end_lsn)); /* * Where does the 0x40 come from? Is it just usa_offset + * usa_client * 2 + 7 & ~7 or is it derived from somewhere? @@ -648,7 +648,7 @@ rcrd_pass_loc: client++; lr = (LOG_RECORD*)((u8*)lr + 0x70); } while (((u8*)lr + 0x70 <= (u8*)rcrd + - le16_to_cpu(rcrd->header.packed.next_record_offset))); + le16_to_cpu(rcrd->next_record_offset))); pass++; goto rcrd_pass_loc; diff --git a/ntfsprogs/ntfsrecover.c b/ntfsprogs/ntfsrecover.c index cfc8d3a1..05a1d087 100644 --- a/ntfsprogs/ntfsrecover.c +++ b/ntfsprogs/ntfsrecover.c @@ -1,7 +1,7 @@ /* * Process log data from an NTFS partition * - * Copyright (c) 2012-2015 Jean-Pierre Andre + * Copyright (c) 2012-2016 Jean-Pierre Andre * * This program examines the Windows log file of an ntfs partition * and plays the committed transactions in order to restore the @@ -101,6 +101,7 @@ #include "volume.h" #include "unistr.h" #include "mst.h" +#include "logfile.h" #include "ntfsrecover.h" #include "utils.h" #include "misc.h" @@ -3832,7 +3833,7 @@ static void version(void) { printf("\n%s v%s (libntfs-3g) - Recover updates committed by Windows" " on an NTFS Volume.\n\n", "ntfsrecover", VERSION); - printf("Copyright (c) 2012-2015 Jean-Pierre Andre\n"); + printf("Copyright (c) 2012-2016 Jean-Pierre Andre\n"); printf("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home); } @@ -3856,7 +3857,6 @@ static void usage(void) fprintf(stderr," -u : undo the latest count transaction sets\n"); fprintf(stderr," -v : show more information (-vv yet more)\n"); fprintf(stderr," -V : show version and exit\n"); - fprintf(stderr," Copyright (c) 2012-2015 Jean-Pierre Andre\n"); } /* diff --git a/ntfsprogs/ntfsrecover.h b/ntfsprogs/ntfsrecover.h index a43feef4..abc72a0f 100644 --- a/ntfsprogs/ntfsrecover.h +++ b/ntfsprogs/ntfsrecover.h @@ -2,7 +2,7 @@ * Declarations for processing log data * * Copyright (c) 2000-2005 Anton Altaparmakov - * Copyright (c) 2014-2015 Jean-Pierre Andre + * Copyright (c) 2014-2016 Jean-Pierre Andre */ /* @@ -22,16 +22,6 @@ * 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))) @@ -40,30 +30,6 @@ #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 */ @@ -106,157 +72,6 @@ enum ACTIONS { 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; - le32 reserved; -} __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 reserved[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 reserved_or_alignment[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; @@ -290,39 +105,6 @@ struct ATTR { 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; @@ -364,7 +146,6 @@ 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); diff --git a/ntfsprogs/playlog.c b/ntfsprogs/playlog.c index 40781462..8bc5cf2f 100644 --- a/ntfsprogs/playlog.c +++ b/ntfsprogs/playlog.c @@ -1,7 +1,7 @@ /* * Redo or undo a list of logged actions * - * Copyright (c) 2014-2015 Jean-Pierre Andre + * Copyright (c) 2014-2016 Jean-Pierre Andre * */ @@ -67,6 +67,7 @@ #include "volume.h" #include "unistr.h" #include "mst.h" +#include "logfile.h" #include "ntfsrecover.h" #include "misc.h"