blob: 5da42c66ad6bbd2c768f9e7c48d013457b150128 [file] [log] [blame]
/*
* 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);