372 lines
11 KiB
C
372 lines
11 KiB
C
/*
|
|
* 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_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 record_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);
|