mirror of
https://github.com/Wuentin/ntfsDump.git
synced 2026-06-08 12:54:08 +00:00
Add files via upload
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.25420.1
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ntfsDump", "ntfsDump\ntfsDump.vcxproj", "{9622A76B-A2B2-4E45-B38B-1EBD2A0DDAEF}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{9622A76B-A2B2-4E45-B38B-1EBD2A0DDAEF}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{9622A76B-A2B2-4E45-B38B-1EBD2A0DDAEF}.Debug|x64.Build.0 = Debug|x64
|
||||
{9622A76B-A2B2-4E45-B38B-1EBD2A0DDAEF}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{9622A76B-A2B2-4E45-B38B-1EBD2A0DDAEF}.Debug|x86.Build.0 = Debug|Win32
|
||||
{9622A76B-A2B2-4E45-B38B-1EBD2A0DDAEF}.Release|x64.ActiveCfg = Release|x64
|
||||
{9622A76B-A2B2-4E45-B38B-1EBD2A0DDAEF}.Release|x64.Build.0 = Release|x64
|
||||
{9622A76B-A2B2-4E45-B38B-1EBD2A0DDAEF}.Release|x86.ActiveCfg = Release|Win32
|
||||
{9622A76B-A2B2-4E45-B38B-1EBD2A0DDAEF}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* NTFS include files
|
||||
*
|
||||
* Copyright(C) 2010 cyb70289 <cyb70289@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef __NTFS_H_CYB70289
|
||||
#define __NTFS_H_CYB70289
|
||||
|
||||
#pragma pack(8)
|
||||
|
||||
#include "NTFS_Common.h"
|
||||
#include "NTFS_FileRecord.h"
|
||||
#include "NTFS_Attribute.h"
|
||||
|
||||
#pragma pack()
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,307 @@
|
||||
/*
|
||||
* NTFS Class common definitions
|
||||
*
|
||||
* Copyright(C) 2010 cyb70289 <cyb70289@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef __NTFS_COMMON_H_CYB70289
|
||||
#define __NTFS_COMMON_H_CYB70289
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <tchar.h>
|
||||
#include <crtdbg.h>
|
||||
|
||||
#include "NTFS_DataType.h"
|
||||
|
||||
#define ATTR_NUMS 16 // Attribute Types count
|
||||
#define ATTR_INDEX(at) (((at)>>4)-1) // Attribute Type to Index, eg. 0x10->0, 0x30->2
|
||||
#define ATTR_MASK(at) (((DWORD)1)<<ATTR_INDEX(at)) // Attribute Bit Mask
|
||||
|
||||
// Bit masks of Attributes
|
||||
#define MASK_STANDARD_INFORMATION ATTR_MASK(ATTR_TYPE_STANDARD_INFORMATION)
|
||||
#define MASK_ATTRIBUTE_LIST ATTR_MASK(ATTR_TYPE_ATTRIBUTE_LIST)
|
||||
#define MASK_FILE_NAME ATTR_MASK(ATTR_TYPE_FILE_NAME)
|
||||
#define MASK_OBJECT_ID ATTR_MASK(ATTR_TYPE_OBJECT_ID)
|
||||
#define MASK_SECURITY_DESCRIPTOR ATTR_MASK(ATTR_TYPE_SECURITY_DESCRIPTOR)
|
||||
#define MASK_VOLUME_NAME ATTR_MASK(ATTR_TYPE_VOLUME_NAME)
|
||||
#define MASK_VOLUME_INFORMATION ATTR_MASK(ATTR_TYPE_VOLUME_INFORMATION)
|
||||
#define MASK_DATA ATTR_MASK(ATTR_TYPE_DATA)
|
||||
#define MASK_INDEX_ROOT ATTR_MASK(ATTR_TYPE_INDEX_ROOT)
|
||||
#define MASK_INDEX_ALLOCATION ATTR_MASK(ATTR_TYPE_INDEX_ALLOCATION)
|
||||
#define MASK_BITMAP ATTR_MASK(ATTR_TYPE_BITMAP)
|
||||
#define MASK_REPARSE_POINT ATTR_MASK(ATTR_TYPE_REPARSE_POINT)
|
||||
#define MASK_EA_INFORMATION ATTR_MASK(ATTR_TYPE_EA_INFORMATION)
|
||||
#define MASK_EA ATTR_MASK(ATTR_TYPE_EA)
|
||||
#define MASK_LOGGED_UTILITY_STREAM ATTR_MASK(ATTR_TYPE_LOGGED_UTILITY_STREAM)
|
||||
|
||||
#define MASK_ALL ((DWORD)-1)
|
||||
|
||||
#define NTFS_TRACE(t1) _RPT0(_CRT_WARN, t1)
|
||||
#define NTFS_TRACE1(t1, t2) _RPT1(_CRT_WARN, t1, t2)
|
||||
#define NTFS_TRACE2(t1, t2, t3) _RPT2(_CRT_WARN, t1, t2, t3)
|
||||
#define NTFS_TRACE3(t1, t2, t3, t4) _RPT3(_CRT_WARN, t1, t2, t3, t4)
|
||||
#define NTFS_TRACE4(t1, t2, t3, t4, t5) _RPT4(_CRT_WARN, t1, t2, t3, t4, t5)
|
||||
|
||||
// User defined Callback routines to process raw attribute data
|
||||
// Set bDiscard to TRUE if this Attribute is to be discarded
|
||||
// Set bDiscard to FALSE to let CFileRecord process it
|
||||
typedef void (*ATTR_RAW_CALLBACK)(const ATTR_HEADER_COMMON *attrHead, BOOL *bDiscard);
|
||||
|
||||
// User defined Callback routine to handle CFileRecord parsed attributes
|
||||
// Will be called by CFileRecord::TraverseAttrs() for each attribute
|
||||
// attrClass is the according attribute's wrapping class, CAttr_xxx
|
||||
// Set bStop to TRUE if don't want to continue
|
||||
// Set bStop to FALSE to continue processing
|
||||
class CAttrBase;
|
||||
typedef void (*ATTRS_CALLBACK)(const CAttrBase *attr, void *context, BOOL *bStop);
|
||||
|
||||
// User defined Callback routine to handle Directory traversing
|
||||
// Will be called by CFileRecord::TraverseSubEntries for each sub entry
|
||||
class CIndexEntry;
|
||||
typedef void (*SUBENTRY_CALLBACK)(const CIndexEntry *ie);
|
||||
|
||||
|
||||
// List Entry
|
||||
template <class ENTRY_TYPE>
|
||||
struct NTSLIST_ENTRY
|
||||
{
|
||||
NTSLIST_ENTRY *Next;
|
||||
ENTRY_TYPE *Entry;
|
||||
};
|
||||
|
||||
// List Entry Smart Pointer
|
||||
template <class ENTRY_TYPE>
|
||||
class CEntrySmartPtr
|
||||
{
|
||||
public:
|
||||
CEntrySmartPtr(ENTRY_TYPE *ptr = NULL)
|
||||
{
|
||||
EntryPtr = ptr;
|
||||
}
|
||||
|
||||
virtual ~CEntrySmartPtr()
|
||||
{
|
||||
if (EntryPtr)
|
||||
delete EntryPtr;
|
||||
}
|
||||
|
||||
private:
|
||||
const ENTRY_TYPE *EntryPtr;
|
||||
|
||||
public:
|
||||
__inline CEntrySmartPtr<ENTRY_TYPE> operator = (const ENTRY_TYPE* ptr)
|
||||
{
|
||||
// Delete previous pointer if allocated
|
||||
if (EntryPtr)
|
||||
delete EntryPtr;
|
||||
|
||||
EntryPtr = ptr;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
__inline const ENTRY_TYPE* operator->() const
|
||||
{
|
||||
_ASSERT(EntryPtr);
|
||||
return EntryPtr;
|
||||
}
|
||||
|
||||
__inline BOOL IsValid() const
|
||||
{
|
||||
return EntryPtr != NULL;
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////
|
||||
// Single list implementation
|
||||
//////////////////////////////////////
|
||||
template <class ENTRY_TYPE>
|
||||
class CSList
|
||||
{
|
||||
public:
|
||||
CSList()
|
||||
{
|
||||
ListHead = ListTail = NULL;
|
||||
ListCurrent = NULL;
|
||||
EntryCount = 0;
|
||||
}
|
||||
|
||||
virtual ~CSList()
|
||||
{
|
||||
RemoveAll();
|
||||
}
|
||||
|
||||
private:
|
||||
int EntryCount;
|
||||
NTSLIST_ENTRY<ENTRY_TYPE> *ListHead;
|
||||
NTSLIST_ENTRY<ENTRY_TYPE> *ListTail;
|
||||
NTSLIST_ENTRY<ENTRY_TYPE> *ListCurrent;
|
||||
|
||||
public:
|
||||
// Get entry count
|
||||
__inline int GetCount() const
|
||||
{
|
||||
return EntryCount;
|
||||
}
|
||||
|
||||
// Insert to tail
|
||||
BOOL InsertEntry(ENTRY_TYPE *entry)
|
||||
{
|
||||
NTSLIST_ENTRY<ENTRY_TYPE> *le = new NTSLIST_ENTRY<ENTRY_TYPE>;
|
||||
if (!le)
|
||||
return FALSE;
|
||||
|
||||
le->Entry = entry;
|
||||
le->Next = NULL;
|
||||
|
||||
if (ListTail == NULL)
|
||||
ListHead = le; // Empty list
|
||||
else
|
||||
ListTail->Next = le;
|
||||
|
||||
ListTail = le;
|
||||
|
||||
EntryCount++;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Remove all entries
|
||||
void RemoveAll()
|
||||
{
|
||||
while (ListHead)
|
||||
{
|
||||
ListCurrent = ListHead->Next;
|
||||
delete ListHead->Entry;
|
||||
delete ListHead;
|
||||
|
||||
ListHead = ListCurrent;
|
||||
}
|
||||
|
||||
ListHead = ListTail = NULL;
|
||||
ListCurrent = NULL;
|
||||
EntryCount = 0;
|
||||
}
|
||||
|
||||
// Find first entry
|
||||
__inline ENTRY_TYPE *FindFirstEntry() const
|
||||
{
|
||||
((CSList<ENTRY_TYPE>*)this)->ListCurrent = ListHead;
|
||||
|
||||
if (ListCurrent)
|
||||
return ListCurrent->Entry;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Find next entry
|
||||
__inline ENTRY_TYPE *FindNextEntry() const
|
||||
{
|
||||
if (ListCurrent)
|
||||
((CSList<ENTRY_TYPE>*)this)->ListCurrent = ListCurrent->Next;
|
||||
|
||||
if (ListCurrent)
|
||||
return ListCurrent->Entry;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Throw all entries
|
||||
// Caution! All entries are just thrown without free
|
||||
__inline void ThrowAll()
|
||||
{
|
||||
ListHead = ListTail = NULL;
|
||||
ListCurrent = NULL;
|
||||
EntryCount = 0;
|
||||
}
|
||||
}; //CSList
|
||||
|
||||
|
||||
//////////////////////////////////////
|
||||
// Stack implementation
|
||||
//////////////////////////////////////
|
||||
template <class ENTRY_TYPE>
|
||||
class CStack
|
||||
{
|
||||
public:
|
||||
CStack()
|
||||
{
|
||||
ListHead = ListTail = NULL;
|
||||
EntryCount = 0;
|
||||
}
|
||||
|
||||
virtual ~CStack()
|
||||
{
|
||||
RemoveAll();
|
||||
}
|
||||
|
||||
private:
|
||||
int EntryCount;
|
||||
NTSLIST_ENTRY<ENTRY_TYPE> *ListHead;
|
||||
NTSLIST_ENTRY<ENTRY_TYPE> *ListTail;
|
||||
|
||||
public:
|
||||
// Get entry count
|
||||
__inline int GetCount() const
|
||||
{
|
||||
return EntryCount;
|
||||
}
|
||||
|
||||
// Insert to head
|
||||
BOOL Push(ENTRY_TYPE *entry)
|
||||
{
|
||||
NTSLIST_ENTRY<ENTRY_TYPE> *le = new NTSLIST_ENTRY<ENTRY_TYPE>;
|
||||
if (!le)
|
||||
return FALSE;
|
||||
|
||||
le->Entry = entry;
|
||||
le->Next = ListHead;
|
||||
|
||||
ListHead = le;
|
||||
|
||||
if (ListTail == NULL)
|
||||
ListTail = le; // Empty list
|
||||
|
||||
EntryCount ++;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Remove from head
|
||||
ENTRY_TYPE* Pop()
|
||||
{
|
||||
if (ListHead == NULL)
|
||||
return NULL;
|
||||
|
||||
NTSLIST_ENTRY<ENTRY_TYPE> *le = ListHead;
|
||||
ENTRY_TYPE *e = le->Entry;
|
||||
|
||||
if (ListTail == ListHead)
|
||||
ListTail = ListHead->Next;
|
||||
ListHead = ListHead->Next;
|
||||
|
||||
delete le;
|
||||
EntryCount --;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
// Remove all entries
|
||||
void RemoveAll()
|
||||
{
|
||||
NTSLIST_ENTRY<ENTRY_TYPE> *le;
|
||||
|
||||
while (ListHead)
|
||||
{
|
||||
le = ListHead->Next;
|
||||
delete ListHead->Entry;
|
||||
delete ListHead;
|
||||
|
||||
ListHead = le;
|
||||
}
|
||||
|
||||
ListHead = ListTail = NULL;
|
||||
EntryCount = 0;
|
||||
}
|
||||
}; //CStack
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,370 @@
|
||||
/*
|
||||
* NTFS data structures and definitions
|
||||
*
|
||||
* Copyright(C) 2010 cyb70289 <cyb70289@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef __NTFS_DATATYPE_H_CYB70289
|
||||
#define __NTFS_DATATYPE_H_CYB70289
|
||||
|
||||
// NTFS Boot Sector BPB
|
||||
|
||||
#define NTFS_SIGNATURE "NTFS "
|
||||
|
||||
#pragma pack(1)
|
||||
typedef struct tagNTFS_BPB
|
||||
{
|
||||
// jump instruction
|
||||
BYTE Jmp[3];
|
||||
|
||||
// signature
|
||||
BYTE Signature[8];
|
||||
|
||||
// BPB and extended BPB
|
||||
WORD BytesPerSector;
|
||||
BYTE SectorsPerCluster;
|
||||
WORD ReservedSectors;
|
||||
BYTE Zeros1[3];
|
||||
WORD NotUsed1;
|
||||
BYTE MediaDescriptor;
|
||||
WORD Zeros2;
|
||||
WORD SectorsPerTrack;
|
||||
WORD NumberOfHeads;
|
||||
DWORD HiddenSectors;
|
||||
DWORD NotUsed2;
|
||||
DWORD NotUsed3;
|
||||
ULONGLONG TotalSectors;
|
||||
ULONGLONG LCN_MFT;
|
||||
ULONGLONG LCN_MFTMirr;
|
||||
DWORD ClustersPerFileRecord;
|
||||
DWORD ClustersPerIndexBlock;
|
||||
BYTE VolumeSN[8];
|
||||
|
||||
// boot code
|
||||
BYTE Code[430];
|
||||
|
||||
//0xAA55
|
||||
BYTE _AA;
|
||||
BYTE _55;
|
||||
} NTFS_BPB;
|
||||
#pragma pack()
|
||||
|
||||
|
||||
// MFT Indexes
|
||||
#define MFT_IDX_MFT 0
|
||||
#define MFT_IDX_MFT_MIRR 1
|
||||
#define MFT_IDX_LOG_FILE 2
|
||||
#define MFT_IDX_VOLUME 3
|
||||
#define MFT_IDX_ATTR_DEF 4
|
||||
#define MFT_IDX_ROOT 5
|
||||
#define MFT_IDX_BITMAP 6
|
||||
#define MFT_IDX_BOOT 7
|
||||
#define MFT_IDX_BAD_CLUSTER 8
|
||||
#define MFT_IDX_SECURE 9
|
||||
#define MFT_IDX_UPCASE 10
|
||||
#define MFT_IDX_EXTEND 11
|
||||
#define MFT_IDX_RESERVED12 12
|
||||
#define MFT_IDX_RESERVED13 13
|
||||
#define MFT_IDX_RESERVED14 14
|
||||
#define MFT_IDX_RESERVED15 15
|
||||
#define MFT_IDX_USER 16
|
||||
|
||||
|
||||
/******************************
|
||||
File Record
|
||||
---------------------
|
||||
| File Record Header|
|
||||
---------------------
|
||||
| Attribute 1 |
|
||||
---------------------
|
||||
| Attribute 2 |
|
||||
---------------------
|
||||
| ...... |
|
||||
---------------------
|
||||
| 0xFFFFFFFF |
|
||||
---------------------
|
||||
*******************************/
|
||||
|
||||
// File Record Header
|
||||
|
||||
#define FILE_RECORD_MAGIC 'ELIF'
|
||||
#define FILE_RECORD_FLAG_INUSE 0x01 // File record is in use
|
||||
#define FILE_RECORD_FLAG_DIR 0x02 // File record is a directory
|
||||
|
||||
typedef struct tagFILE_RECORD_HEADER
|
||||
{
|
||||
DWORD Magic; // "FILE"
|
||||
WORD OffsetOfUS; // Offset of Update Sequence
|
||||
WORD SizeOfUS; // Size in words of Update Sequence Number & Array
|
||||
ULONGLONG LSN; // $LogFile Sequence Number
|
||||
WORD SeqNo; // Sequence number
|
||||
WORD Hardlinks; // Hard link count
|
||||
WORD OffsetOfAttr; // Offset of the first Attribute
|
||||
WORD Flags; // Flags
|
||||
DWORD RealSize; // Real size of the FILE record
|
||||
DWORD AllocSize; // Allocated size of the FILE record
|
||||
ULONGLONG RefToBase; // File reference to the base FILE record
|
||||
WORD NextAttrId; // Next Attribute Id
|
||||
WORD Align; // Align to 4 byte boundary
|
||||
DWORD RecordNo; // Number of this MFT Record
|
||||
} FILE_RECORD_HEADER;
|
||||
|
||||
|
||||
/******************************
|
||||
Attribute
|
||||
--------------------
|
||||
| Attribute Header |
|
||||
--------------------
|
||||
| Attribute Data |
|
||||
--------------------
|
||||
*******************************/
|
||||
|
||||
// Attribute Header
|
||||
|
||||
#define ATTR_TYPE_STANDARD_INFORMATION 0x10
|
||||
#define ATTR_TYPE_ATTRIBUTE_LIST 0x20
|
||||
#define ATTR_TYPE_FILE_NAME 0x30
|
||||
#define ATTR_TYPE_OBJECT_ID 0x40
|
||||
#define ATTR_TYPE_SECURITY_DESCRIPTOR 0x50
|
||||
#define ATTR_TYPE_VOLUME_NAME 0x60
|
||||
#define ATTR_TYPE_VOLUME_INFORMATION 0x70
|
||||
#define ATTR_TYPE_DATA 0x80
|
||||
#define ATTR_TYPE_INDEX_ROOT 0x90
|
||||
#define ATTR_TYPE_INDEX_ALLOCATION 0xA0
|
||||
#define ATTR_TYPE_BITMAP 0xB0
|
||||
#define ATTR_TYPE_REPARSE_POINT 0xC0
|
||||
#define ATTR_TYPE_EA_INFORMATION 0xD0
|
||||
#define ATTR_TYPE_EA 0xE0
|
||||
#define ATTR_TYPE_LOGGED_UTILITY_STREAM 0x100
|
||||
|
||||
#define ATTR_FLAG_COMPRESSED 0x0001
|
||||
#define ATTR_FLAG_ENCRYPTED 0x4000
|
||||
#define ATTR_FLAG_SPARSE 0x8000
|
||||
|
||||
typedef struct tagATTR_HEADER_COMMON
|
||||
{
|
||||
DWORD Type; // Attribute Type
|
||||
DWORD TotalSize; // Length (including this header)
|
||||
BYTE NonResident; // 0 - resident, 1 - non resident
|
||||
BYTE NameLength; // name length in words
|
||||
WORD NameOffset; // offset to the name
|
||||
WORD Flags; // Flags
|
||||
WORD Id; // Attribute Id
|
||||
} ATTR_HEADER_COMMON;
|
||||
|
||||
typedef struct tagATTR_HEADER_RESIDENT
|
||||
{
|
||||
ATTR_HEADER_COMMON Header; // Common data structure
|
||||
DWORD AttrSize; // Length of the attribute body
|
||||
WORD AttrOffset; // Offset to the Attribute
|
||||
BYTE IndexedFlag; // Indexed flag
|
||||
BYTE Padding; // Padding
|
||||
} ATTR_HEADER_RESIDENT;
|
||||
|
||||
typedef struct tagATTR_HEADER_NON_RESIDENT
|
||||
{
|
||||
ATTR_HEADER_COMMON Header; // Common data structure
|
||||
ULONGLONG StartVCN; // Starting VCN
|
||||
ULONGLONG LastVCN; // Last VCN
|
||||
WORD DataRunOffset; // Offset to the Data Runs
|
||||
WORD CompUnitSize; // Compression unit size
|
||||
DWORD Padding; // Padding
|
||||
ULONGLONG AllocSize; // Allocated size of the attribute
|
||||
ULONGLONG RealSize; // Real size of the attribute
|
||||
ULONGLONG IniSize; // Initialized data size of the stream
|
||||
} ATTR_HEADER_NON_RESIDENT;
|
||||
|
||||
|
||||
// Attribute: STANDARD_INFORMATION
|
||||
|
||||
#define ATTR_STDINFO_PERMISSION_READONLY 0x00000001
|
||||
#define ATTR_STDINFO_PERMISSION_HIDDEN 0x00000002
|
||||
#define ATTR_STDINFO_PERMISSION_SYSTEM 0x00000004
|
||||
#define ATTR_STDINFO_PERMISSION_ARCHIVE 0x00000020
|
||||
#define ATTR_STDINFO_PERMISSION_DEVICE 0x00000040
|
||||
#define ATTR_STDINFO_PERMISSION_NORMAL 0x00000080
|
||||
#define ATTR_STDINFO_PERMISSION_TEMP 0x00000100
|
||||
#define ATTR_STDINFO_PERMISSION_SPARSE 0x00000200
|
||||
#define ATTR_STDINFO_PERMISSION_REPARSE 0x00000400
|
||||
#define ATTR_STDINFO_PERMISSION_COMPRESSED 0x00000800
|
||||
#define ATTR_STDINFO_PERMISSION_OFFLINE 0x00001000
|
||||
#define ATTR_STDINFO_PERMISSION_NCI 0x00002000
|
||||
#define ATTR_STDINFO_PERMISSION_ENCRYPTED 0x00004000
|
||||
|
||||
typedef struct tagATTR_STANDARD_INFORMATION
|
||||
{
|
||||
ULONGLONG CreateTime; // File creation time
|
||||
ULONGLONG AlterTime; // File altered time
|
||||
ULONGLONG MFTTime; // MFT changed time
|
||||
ULONGLONG ReadTime; // File read time
|
||||
DWORD Permission; // Dos file permission
|
||||
DWORD MaxVersionNo; // Maxim number of file versions
|
||||
DWORD VersionNo; // File version number
|
||||
DWORD ClassId; // Class Id
|
||||
DWORD OwnerId; // Owner Id
|
||||
DWORD SecurityId; // Security Id
|
||||
ULONGLONG QuotaCharged; // Quota charged
|
||||
ULONGLONG USN; // USN Journel
|
||||
} ATTR_STANDARD_INFORMATION;
|
||||
|
||||
|
||||
// Attribute: ATTRIBUTE_LIST
|
||||
|
||||
typedef struct tagATTR_ATTRIBUTE_LIST
|
||||
{
|
||||
DWORD AttrType; // Attribute type
|
||||
WORD RecordSize; // Record length
|
||||
BYTE NameLength; // Name length in characters
|
||||
BYTE NameOffset; // Name offset
|
||||
ULONGLONG StartVCN; // Start VCN
|
||||
ULONGLONG BaseRef; // Base file reference to the attribute
|
||||
WORD AttrId; // Attribute Id
|
||||
} ATTR_ATTRIBUTE_LIST;
|
||||
|
||||
// Attribute: FILE_NAME
|
||||
|
||||
#define ATTR_FILENAME_FLAG_READONLY 0x00000001
|
||||
#define ATTR_FILENAME_FLAG_HIDDEN 0x00000002
|
||||
#define ATTR_FILENAME_FLAG_SYSTEM 0x00000004
|
||||
#define ATTR_FILENAME_FLAG_ARCHIVE 0x00000020
|
||||
#define ATTR_FILENAME_FLAG_DEVICE 0x00000040
|
||||
#define ATTR_FILENAME_FLAG_NORMAL 0x00000080
|
||||
#define ATTR_FILENAME_FLAG_TEMP 0x00000100
|
||||
#define ATTR_FILENAME_FLAG_SPARSE 0x00000200
|
||||
#define ATTR_FILENAME_FLAG_REPARSE 0x00000400
|
||||
#define ATTR_FILENAME_FLAG_COMPRESSED 0x00000800
|
||||
#define ATTR_FILENAME_FLAG_OFFLINE 0x00001000
|
||||
#define ATTR_FILENAME_FLAG_NCI 0x00002000
|
||||
#define ATTR_FILENAME_FLAG_ENCRYPTED 0x00004000
|
||||
#define ATTR_FILENAME_FLAG_DIRECTORY 0x10000000
|
||||
#define ATTR_FILENAME_FLAG_INDEXVIEW 0x20000000
|
||||
|
||||
#define ATTR_FILENAME_NAMESPACE_POSIX 0x00
|
||||
#define ATTR_FILENAME_NAMESPACE_WIN32 0x01
|
||||
#define ATTR_FILENAME_NAMESPACE_DOS 0x02
|
||||
|
||||
typedef struct tagATTR_FILE_NAME
|
||||
{
|
||||
ULONGLONG ParentRef; // File reference to the parent directory
|
||||
ULONGLONG CreateTime; // File creation time
|
||||
ULONGLONG AlterTime; // File altered time
|
||||
ULONGLONG MFTTime; // MFT changed time
|
||||
ULONGLONG ReadTime; // File read time
|
||||
ULONGLONG AllocSize; // Allocated size of the file
|
||||
ULONGLONG RealSize; // Real size of the file
|
||||
DWORD Flags; // Flags
|
||||
DWORD ER; // Used by EAs and Reparse
|
||||
BYTE NameLength; // Filename length in characters
|
||||
BYTE NameSpace; // Filename space
|
||||
WORD Name[1]; // Filename
|
||||
} ATTR_FILE_NAME;
|
||||
|
||||
|
||||
// Attribute: VOLUME_INFORMATION
|
||||
|
||||
#define ATTR_VOLINFO_FLAG_DIRTY 0x0001 // Dirty
|
||||
#define ATTR_VOLINFO_FLAG_RLF 0x0002 // Resize logfile
|
||||
#define ATTR_VOLINFO_FLAG_UOM 0x0004 // Upgrade on mount
|
||||
#define ATTR_VOLINFO_FLAG_MONT 0x0008 // Mounted on NT4
|
||||
#define ATTR_VOLINFO_FLAG_DUSN 0x0010 // Delete USN underway
|
||||
#define ATTR_VOLINFO_FLAG_ROI 0x0020 // Repair object Ids
|
||||
#define ATTR_VOLINFO_FLAG_MBC 0x8000 // Modified by chkdsk
|
||||
|
||||
typedef struct tagATTR_VOLUME_INFORMATION
|
||||
{
|
||||
BYTE Reserved1[8]; // Always 0 ?
|
||||
BYTE MajorVersion; // Major version
|
||||
BYTE MinorVersion; // Minor version
|
||||
WORD Flags; // Flags
|
||||
BYTE Reserved2[4]; // Always 0 ?
|
||||
} ATTR_VOLUME_INFORMATION;
|
||||
|
||||
|
||||
// Attribute: INDEX_ROOT
|
||||
/******************************
|
||||
INDEX_ROOT
|
||||
---------------------
|
||||
| Index Root Header |
|
||||
---------------------
|
||||
| Index Header |
|
||||
---------------------
|
||||
| Index Entry |
|
||||
---------------------
|
||||
| Index Entry |
|
||||
---------------------
|
||||
| ...... |
|
||||
---------------------
|
||||
*******************************/
|
||||
|
||||
#define ATTR_INDEXROOT_FLAG_SMALL 0x00 // Fits in Index Root File Record
|
||||
#define ATTR_INDEXROOT_FLAG_LARGE 0x01 // Index Allocation and Bitmap needed
|
||||
|
||||
typedef struct tagATTR_INDEX_ROOT
|
||||
{
|
||||
// Index Root Header
|
||||
DWORD AttrType; // Attribute type (ATTR_TYPE_FILE_NAME: Directory, 0: Index View)
|
||||
DWORD CollRule; // Collation rule
|
||||
DWORD IBSize; // Size of index block
|
||||
BYTE ClustersPerIB; // Clusters per index block (same as BPB?)
|
||||
BYTE Padding1[3]; // Padding
|
||||
// Index Header
|
||||
DWORD EntryOffset; // Offset to the first index entry, relative to this address(0x10)
|
||||
DWORD TotalEntrySize; // Total size of the index entries
|
||||
DWORD AllocEntrySize; // Allocated size of the index entries
|
||||
BYTE Flags; // Flags
|
||||
BYTE Padding2[3]; // Padding
|
||||
} ATTR_INDEX_ROOT;
|
||||
|
||||
|
||||
// INDEX ENTRY
|
||||
|
||||
#define INDEX_ENTRY_FLAG_SUBNODE 0x01 // Index entry points to a sub-node
|
||||
#define INDEX_ENTRY_FLAG_LAST 0x02 // Last index entry in the node, no Stream
|
||||
|
||||
typedef struct tagINDEX_ENTRY
|
||||
{
|
||||
ULONGLONG FileReference; // Low 6B: MFT record index, High 2B: MFT record sequence number
|
||||
WORD Size; // Length of the index entry
|
||||
WORD StreamSize; // Length of the stream
|
||||
BYTE Flags; // Flags
|
||||
BYTE Padding[3]; // Padding
|
||||
BYTE Stream[1]; // Stream
|
||||
// VCN of the sub node in Index Allocation, Offset = Size - 8
|
||||
} INDEX_ENTRY;
|
||||
|
||||
|
||||
// INDEX BLOCK
|
||||
/******************************
|
||||
INDEX_BLOCK
|
||||
-----------------------
|
||||
| Index Block Header |
|
||||
-----------------------
|
||||
| Index Header |
|
||||
-----------------------
|
||||
| Index Entry |
|
||||
-----------------------
|
||||
| Index Entry |
|
||||
-----------------------
|
||||
| ...... |
|
||||
-----------------------
|
||||
*******************************/
|
||||
|
||||
#define INDEX_BLOCK_MAGIC 'XDNI'
|
||||
|
||||
typedef struct tagINDEX_BLOCK
|
||||
{
|
||||
// Index Block Header
|
||||
DWORD Magic; // "INDX"
|
||||
WORD OffsetOfUS; // Offset of Update Sequence
|
||||
WORD SizeOfUS; // Size in words of Update Sequence Number & Array
|
||||
ULONGLONG LSN; // $LogFile Sequence Number
|
||||
ULONGLONG VCN; // VCN of this index block in the index allocation
|
||||
// Index Header
|
||||
DWORD EntryOffset; // Offset of the index entries, relative to this address(0x18)
|
||||
DWORD TotalEntrySize; // Total size of the index entries
|
||||
DWORD AllocEntrySize; // Allocated size of index entries
|
||||
BYTE NotLeaf; // 1 if not leaf node (has children)
|
||||
BYTE Padding[3]; // Padding
|
||||
} INDEX_BLOCK;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,979 @@
|
||||
/*
|
||||
* NTFS Volume and File Record Class
|
||||
*
|
||||
* Copyright(C) 2010 cyb70289 <cyb70289@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef __NTFS_FILERECORD_H_CYB70289
|
||||
#define __NTFS_FILERECORD_H_CYB70289
|
||||
|
||||
|
||||
///////////////////////////////////////
|
||||
// NTFS Volume forward declaration
|
||||
///////////////////////////////////////
|
||||
class CNTFSVolume
|
||||
{
|
||||
public:
|
||||
CNTFSVolume(_TCHAR volume);
|
||||
virtual ~CNTFSVolume();
|
||||
|
||||
friend class CFileRecord;
|
||||
friend class CAttrBase;
|
||||
|
||||
private:
|
||||
WORD SectorSize;
|
||||
DWORD ClusterSize;
|
||||
DWORD FileRecordSize;
|
||||
DWORD IndexBlockSize;
|
||||
ULONGLONG MFTAddr;
|
||||
HANDLE hVolume;
|
||||
BOOL VolumeOK;
|
||||
ATTR_RAW_CALLBACK AttrRawCallBack[ATTR_NUMS];
|
||||
WORD Version;
|
||||
|
||||
// MFT file records ($MFT file itself) may be fragmented
|
||||
// Get $MFT Data attribute to translate FileRecord to correct disk offset
|
||||
CFileRecord *MFTRecord; // $MFT File Record
|
||||
const CAttrBase *MFTData; // $MFT Data Attribute
|
||||
|
||||
BOOL OpenVolume(_TCHAR volume);
|
||||
|
||||
public:
|
||||
__inline BOOL IsVolumeOK() const;
|
||||
__inline WORD GetVersion() const;
|
||||
__inline ULONGLONG GetRecordsCount() const;
|
||||
|
||||
__inline DWORD GetSectorSize() const;
|
||||
__inline DWORD GetClusterSize() const;
|
||||
__inline DWORD GetFileRecordSize() const;
|
||||
__inline DWORD GetIndexBlockSize() const;
|
||||
__inline ULONGLONG GetMFTAddr() const;
|
||||
|
||||
BOOL InstallAttrRawCB(DWORD attrType, ATTR_RAW_CALLBACK cb);
|
||||
__inline void ClearAttrRawCB();
|
||||
}; // CNTFSVolume
|
||||
|
||||
|
||||
////////////////////////////////////////////
|
||||
// List to hold Attributes of the same type
|
||||
////////////////////////////////////////////
|
||||
typedef class CSList<CAttrBase> CAttrList;
|
||||
|
||||
// It seems VC6.0 doesn't support template class friends
|
||||
#if _MSC_VER <= 1200
|
||||
class CAttrResident;
|
||||
class CAttrNonResident;
|
||||
template <class TYPE_RESIDENT> class CAttr_AttrList;
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
// Process a single File Record
|
||||
////////////////////////////////
|
||||
class CFileRecord
|
||||
{
|
||||
public:
|
||||
CFileRecord(const CNTFSVolume *volume);
|
||||
virtual ~CFileRecord();
|
||||
|
||||
friend class CAttrBase;
|
||||
#if _MSC_VER <= 1200
|
||||
// Walk around VC6.0 compiler defect
|
||||
friend class CAttr_AttrList<CAttrResident>;
|
||||
friend class CAttr_AttrList<CAttrNonResident>;
|
||||
#else
|
||||
template <class TYPE_RESIDENT> friend class CAttr_AttrList; // Won't compiler in VC6.0, why?
|
||||
#endif
|
||||
|
||||
private:
|
||||
const CNTFSVolume *Volume;
|
||||
FILE_RECORD_HEADER *FileRecord;
|
||||
ULONGLONG FileReference;
|
||||
ATTR_RAW_CALLBACK AttrRawCallBack[ATTR_NUMS];
|
||||
DWORD AttrMask;
|
||||
CAttrList AttrList[ATTR_NUMS]; // Attributes
|
||||
|
||||
void ClearAttrs();
|
||||
BOOL PatchUS(WORD *sector, int sectors, WORD usn, WORD *usarray);
|
||||
__inline void UserCallBack(DWORD attType, ATTR_HEADER_COMMON *ahc, BOOL *bDiscard);
|
||||
CAttrBase* AllocAttr(ATTR_HEADER_COMMON *ahc, BOOL *bUnhandled);
|
||||
BOOL ParseAttr(ATTR_HEADER_COMMON *ahc);
|
||||
FILE_RECORD_HEADER* ReadFileRecord(ULONGLONG &fileRef);
|
||||
BOOL VisitIndexBlock(const ULONGLONG &vcn, const _TCHAR *fileName, CIndexEntry &ieFound) const;
|
||||
void TraverseSubNode(const ULONGLONG &vcn, SUBENTRY_CALLBACK seCallBack) const;
|
||||
|
||||
public:
|
||||
BOOL ParseFileRecord(ULONGLONG fileRef);
|
||||
BOOL ParseAttrs();
|
||||
|
||||
BOOL InstallAttrRawCB(DWORD attrType, ATTR_RAW_CALLBACK cb);
|
||||
__inline void ClearAttrRawCB();
|
||||
|
||||
__inline void SetAttrMask(DWORD mask);
|
||||
void TraverseAttrs(ATTRS_CALLBACK attrCallBack, void *context);
|
||||
__inline const CAttrBase* FindFirstAttr(DWORD attrType) const;
|
||||
const CAttrBase* FindNextAttr(DWORD attrType) const;
|
||||
|
||||
int GetFileName(_TCHAR *buf, DWORD bufLen) const;
|
||||
__inline ULONGLONG GetFileSize() const;
|
||||
void GetFileTime(FILETIME *writeTm, FILETIME *createTm = NULL, FILETIME *accessTm = NULL) const;
|
||||
|
||||
void TraverseSubEntries(SUBENTRY_CALLBACK seCallBack) const;
|
||||
__inline const BOOL FindSubEntry(const _TCHAR *fileName, CIndexEntry &ieFound) const;
|
||||
const CAttrBase* FindStream(_TCHAR *name = NULL);
|
||||
|
||||
__inline BOOL IsDeleted() const;
|
||||
__inline BOOL IsDirectory() const;
|
||||
__inline BOOL IsReadOnly() const;
|
||||
__inline BOOL IsHidden() const;
|
||||
__inline BOOL IsSystem() const;
|
||||
__inline BOOL IsCompressed() const;
|
||||
__inline BOOL IsEncrypted() const;
|
||||
__inline BOOL IsSparse() const;
|
||||
}; // CFileRecord
|
||||
|
||||
|
||||
#include "NTFS_Attribute.h"
|
||||
|
||||
|
||||
CFileRecord::CFileRecord(const CNTFSVolume *volume)
|
||||
{
|
||||
_ASSERT(volume);
|
||||
Volume = volume;
|
||||
FileRecord = NULL;
|
||||
FileReference = (ULONGLONG)-1;
|
||||
|
||||
ClearAttrRawCB();
|
||||
|
||||
// Default to parse all attributes
|
||||
AttrMask = MASK_ALL;
|
||||
}
|
||||
|
||||
CFileRecord::~CFileRecord()
|
||||
{
|
||||
ClearAttrs();
|
||||
|
||||
if (FileRecord)
|
||||
delete FileRecord;
|
||||
}
|
||||
|
||||
// Free all CAttr_xxx
|
||||
void CFileRecord::ClearAttrs()
|
||||
{
|
||||
for (int i = 0; i<ATTR_NUMS; i++)
|
||||
{
|
||||
AttrList[i].RemoveAll();
|
||||
}
|
||||
}
|
||||
|
||||
// Verify US and update sectors
|
||||
BOOL CFileRecord::PatchUS(WORD *sector, int sectors, WORD usn, WORD *usarray)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i<sectors; i++)
|
||||
{
|
||||
sector += ((Volume->SectorSize >> 1) - 1);
|
||||
if (*sector != usn)
|
||||
return FALSE; // USN error
|
||||
*sector = usarray[i]; // Write back correct data
|
||||
sector++;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Call user defined Callback routines for an attribute
|
||||
__inline void CFileRecord::UserCallBack(DWORD attType, ATTR_HEADER_COMMON *ahc, BOOL *bDiscard)
|
||||
{
|
||||
*bDiscard = FALSE;
|
||||
|
||||
if (AttrRawCallBack[attType])
|
||||
AttrRawCallBack[attType](ahc, bDiscard);
|
||||
else if (Volume->AttrRawCallBack[attType])
|
||||
Volume->AttrRawCallBack[attType](ahc, bDiscard);
|
||||
}
|
||||
|
||||
CAttrBase* CFileRecord::AllocAttr(ATTR_HEADER_COMMON *ahc, BOOL *bUnhandled)
|
||||
{
|
||||
switch (ahc->Type)
|
||||
{
|
||||
case ATTR_TYPE_STANDARD_INFORMATION:
|
||||
return new CAttr_StdInfo(ahc, this);
|
||||
|
||||
case ATTR_TYPE_ATTRIBUTE_LIST:
|
||||
if (ahc->NonResident)
|
||||
return new CAttr_AttrList<CAttrNonResident>(ahc, this);
|
||||
else
|
||||
return new CAttr_AttrList<CAttrResident>(ahc, this);
|
||||
|
||||
case ATTR_TYPE_FILE_NAME:
|
||||
return new CAttr_FileName(ahc, this);
|
||||
|
||||
case ATTR_TYPE_VOLUME_NAME:
|
||||
return new CAttr_VolName(ahc, this);
|
||||
|
||||
case ATTR_TYPE_VOLUME_INFORMATION:
|
||||
return new CAttr_VolInfo(ahc, this);
|
||||
|
||||
case ATTR_TYPE_DATA:
|
||||
if (ahc->NonResident)
|
||||
return new CAttr_Data<CAttrNonResident>(ahc, this);
|
||||
else
|
||||
return new CAttr_Data<CAttrResident>(ahc, this);
|
||||
|
||||
case ATTR_TYPE_INDEX_ROOT:
|
||||
return new CAttr_IndexRoot(ahc, this);
|
||||
|
||||
case ATTR_TYPE_INDEX_ALLOCATION:
|
||||
return new CAttr_IndexAlloc(ahc, this);
|
||||
|
||||
case ATTR_TYPE_BITMAP:
|
||||
if (ahc->NonResident)
|
||||
return new CAttr_Bitmap<CAttrNonResident>(ahc, this);
|
||||
else
|
||||
// Resident Bitmap may exist in a directory's FileRecord
|
||||
// or in $MFT for a very small volume in theory
|
||||
return new CAttr_Bitmap<CAttrResident>(ahc, this);
|
||||
|
||||
// Unhandled Attributes
|
||||
default:
|
||||
*bUnhandled = TRUE;
|
||||
if (ahc->NonResident)
|
||||
return new CAttrNonResident(ahc, this);
|
||||
else
|
||||
return new CAttrResident(ahc, this);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse a single Attribute
|
||||
// Return False on error
|
||||
BOOL CFileRecord::ParseAttr(ATTR_HEADER_COMMON *ahc)
|
||||
{
|
||||
DWORD attrIndex = ATTR_INDEX(ahc->Type);
|
||||
if (attrIndex < ATTR_NUMS)
|
||||
{
|
||||
BOOL bDiscard = FALSE;
|
||||
UserCallBack(attrIndex, ahc, &bDiscard);
|
||||
|
||||
if (!bDiscard)
|
||||
{
|
||||
BOOL bUnhandled = FALSE;
|
||||
CAttrBase *attr = AllocAttr(ahc, &bUnhandled);
|
||||
if (attr)
|
||||
{
|
||||
if (bUnhandled)
|
||||
{
|
||||
NTFS_TRACE1("Unhandled attribute: 0x%04X\n", ahc->Type);
|
||||
}
|
||||
AttrList[attrIndex].InsertEntry(attr);
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
NTFS_TRACE1("Attribute Parse error: 0x%04X\n", ahc->Type);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NTFS_TRACE1("User Callback has processed this Attribute: 0x%04X\n", ahc->Type);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NTFS_TRACE1("Invalid Attribute Type: 0x%04X\n", ahc->Type);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// Read File Record
|
||||
FILE_RECORD_HEADER* CFileRecord::ReadFileRecord(ULONGLONG &fileRef)
|
||||
{
|
||||
FILE_RECORD_HEADER *fr = NULL;
|
||||
DWORD len;
|
||||
|
||||
if (fileRef < MFT_IDX_USER || Volume->MFTData == NULL)
|
||||
{
|
||||
// Take as continuous disk allocation
|
||||
LARGE_INTEGER frAddr;
|
||||
frAddr.QuadPart = Volume->MFTAddr + (Volume->FileRecordSize) * fileRef;
|
||||
frAddr.LowPart = SetFilePointer(Volume->hVolume, frAddr.LowPart, &frAddr.HighPart, FILE_BEGIN);
|
||||
|
||||
if (frAddr.LowPart == DWORD(-1) && GetLastError() != NO_ERROR)
|
||||
return FALSE;
|
||||
else
|
||||
{
|
||||
fr = (FILE_RECORD_HEADER*)new BYTE[Volume->FileRecordSize];
|
||||
|
||||
if (ReadFile(Volume->hVolume, fr, Volume->FileRecordSize, &len, NULL)
|
||||
&& len == Volume->FileRecordSize)
|
||||
return fr;
|
||||
else
|
||||
{
|
||||
delete fr;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// May be fragmented $MFT
|
||||
ULONGLONG frAddr;
|
||||
frAddr = (Volume->FileRecordSize) * fileRef;
|
||||
|
||||
fr = (FILE_RECORD_HEADER*)new BYTE[Volume->FileRecordSize];
|
||||
|
||||
if (Volume->MFTData->ReadData(frAddr, fr, Volume->FileRecordSize, &len)
|
||||
&& len == Volume->FileRecordSize)
|
||||
return fr;
|
||||
else
|
||||
{
|
||||
delete fr;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Read File Record, verify and patch the US (update sequence)
|
||||
BOOL CFileRecord::ParseFileRecord(ULONGLONG fileRef)
|
||||
{
|
||||
// Clear previous data
|
||||
ClearAttrs();
|
||||
if (FileRecord)
|
||||
{
|
||||
delete FileRecord;
|
||||
FileRecord = NULL;
|
||||
}
|
||||
|
||||
FILE_RECORD_HEADER *fr = ReadFileRecord(fileRef);
|
||||
if (fr == NULL)
|
||||
{
|
||||
NTFS_TRACE1("Cannot read file record %I64u\n", fileRef);
|
||||
|
||||
FileReference = (ULONGLONG)-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
FileReference = fileRef;
|
||||
|
||||
if (fr->Magic == FILE_RECORD_MAGIC)
|
||||
{
|
||||
// Patch US
|
||||
WORD *usnaddr = (WORD*)((BYTE*)fr + fr->OffsetOfUS);
|
||||
WORD usn = *usnaddr;
|
||||
WORD *usarray = usnaddr + 1;
|
||||
if (PatchUS((WORD*)fr, Volume->FileRecordSize / Volume->SectorSize, usn, usarray))
|
||||
{
|
||||
NTFS_TRACE1("File Record %I64u Found\n", fileRef);
|
||||
FileRecord = fr;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
NTFS_TRACE("Update Sequence Number error\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NTFS_TRACE("Invalid file record\n");
|
||||
}
|
||||
|
||||
delete fr;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Visit IndexBlocks recursivly to find a specific FileName
|
||||
BOOL CFileRecord::VisitIndexBlock(const ULONGLONG &vcn, const _TCHAR *fileName, CIndexEntry &ieFound) const
|
||||
{
|
||||
CAttr_IndexAlloc *ia = (CAttr_IndexAlloc*)FindFirstAttr(ATTR_TYPE_INDEX_ALLOCATION);
|
||||
if (ia == NULL)
|
||||
return FALSE;
|
||||
|
||||
CIndexBlock ib;
|
||||
if (ia->ParseIndexBlock(vcn, ib))
|
||||
{
|
||||
CIndexEntry *ie = ib.FindFirstEntry();
|
||||
while (ie)
|
||||
{
|
||||
if (ie->HasName())
|
||||
{
|
||||
// Compare name
|
||||
int i = ie->Compare(fileName);
|
||||
if (i == 0)
|
||||
{
|
||||
ieFound = *ie;
|
||||
return TRUE;
|
||||
}
|
||||
else if (i < 0) // fileName is smaller than IndexEntry
|
||||
{
|
||||
// Visit SubNode
|
||||
if (ie->IsSubNodePtr())
|
||||
{
|
||||
// Search in SubNode (IndexBlock), recursive call
|
||||
if (VisitIndexBlock(ie->GetSubNodeVCN(), fileName, ieFound))
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
return FALSE; // not found
|
||||
}
|
||||
// Just step forward if fileName is bigger than IndexEntry
|
||||
}
|
||||
else if (ie->IsSubNodePtr())
|
||||
{
|
||||
// Search in SubNode (IndexBlock), recursive call
|
||||
if (VisitIndexBlock(ie->GetSubNodeVCN(), fileName, ieFound))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
ie = ib.FindNextEntry();
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Traverse SubNode recursivly in ascending order
|
||||
// Call user defined callback routine once found an subentry
|
||||
void CFileRecord::TraverseSubNode(const ULONGLONG &vcn, SUBENTRY_CALLBACK seCallBack) const
|
||||
{
|
||||
CAttr_IndexAlloc *ia = (CAttr_IndexAlloc*)FindFirstAttr(ATTR_TYPE_INDEX_ALLOCATION);
|
||||
if (ia == NULL)
|
||||
return;
|
||||
|
||||
CIndexBlock ib;
|
||||
if (ia->ParseIndexBlock(vcn, ib))
|
||||
{
|
||||
CIndexEntry *ie = ib.FindFirstEntry();
|
||||
while (ie)
|
||||
{
|
||||
if (ie->IsSubNodePtr())
|
||||
TraverseSubNode(ie->GetSubNodeVCN(), seCallBack); // recursive call
|
||||
|
||||
if (ie->HasName())
|
||||
seCallBack(ie);
|
||||
|
||||
ie = ib.FindNextEntry();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse all the attributes in a File Record
|
||||
// And insert them into a link list
|
||||
BOOL CFileRecord::ParseAttrs()
|
||||
{
|
||||
_ASSERT(FileRecord);
|
||||
|
||||
// Clear previous data
|
||||
ClearAttrs();
|
||||
|
||||
// Visit all attributes
|
||||
|
||||
DWORD dataPtr = 0; // guard if data exceeds FileRecordSize bounds
|
||||
ATTR_HEADER_COMMON *ahc = (ATTR_HEADER_COMMON*)((BYTE*)FileRecord + FileRecord->OffsetOfAttr);
|
||||
dataPtr += FileRecord->OffsetOfAttr;
|
||||
|
||||
while (ahc->Type != (DWORD)-1 && (dataPtr + ahc->TotalSize) <= Volume->FileRecordSize)
|
||||
{
|
||||
if (ATTR_MASK(ahc->Type) & AttrMask) // Skip unwanted attributes
|
||||
{
|
||||
if (!ParseAttr(ahc)) // Parse error
|
||||
return FALSE;
|
||||
|
||||
if (IsEncrypted() || IsCompressed())
|
||||
{
|
||||
NTFS_TRACE("Compressed and Encrypted file not supported yet !\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
dataPtr += ahc->TotalSize;
|
||||
ahc = (ATTR_HEADER_COMMON*)((BYTE*)ahc + ahc->TotalSize); // next attribute
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Install Attribute raw data CallBack routines for a single File Record
|
||||
BOOL CFileRecord::InstallAttrRawCB(DWORD attrType, ATTR_RAW_CALLBACK cb)
|
||||
{
|
||||
DWORD atIdx = ATTR_INDEX(attrType);
|
||||
if (atIdx < ATTR_NUMS)
|
||||
{
|
||||
AttrRawCallBack[atIdx] = cb;
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Clear all Attribute CallBack routines
|
||||
__inline void CFileRecord::ClearAttrRawCB()
|
||||
{
|
||||
for (int i = 0; i < ATTR_NUMS; i++)
|
||||
AttrRawCallBack[i] = NULL;
|
||||
}
|
||||
|
||||
// Choose attributes to handle, unwanted attributes will be discarded silently
|
||||
__inline void CFileRecord::SetAttrMask(DWORD mask)
|
||||
{
|
||||
// Standard Information and Attribute List is needed always
|
||||
AttrMask = mask | MASK_STANDARD_INFORMATION | MASK_ATTRIBUTE_LIST;
|
||||
}
|
||||
|
||||
// Traverse all Attribute and return CAttr_xxx classes to User Callback routine
|
||||
void CFileRecord::TraverseAttrs(ATTRS_CALLBACK attrCallBack, void *context)
|
||||
{
|
||||
_ASSERT(attrCallBack);
|
||||
|
||||
for (int i = 0; i < ATTR_NUMS; i++)
|
||||
{
|
||||
if (AttrMask & (((DWORD)1) << i)) // skip masked attributes
|
||||
{
|
||||
const CAttrBase *ab = AttrList[i].FindFirstEntry();
|
||||
while (ab)
|
||||
{
|
||||
BOOL bStop;
|
||||
bStop = FALSE;
|
||||
attrCallBack(ab, context, &bStop);
|
||||
if (bStop)
|
||||
return;
|
||||
|
||||
ab = AttrList[i].FindNextEntry();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find Attributes
|
||||
__inline const CAttrBase* CFileRecord::FindFirstAttr(DWORD attrType) const
|
||||
{
|
||||
DWORD attrIdx = ATTR_INDEX(attrType);
|
||||
|
||||
return attrIdx < ATTR_NUMS ? AttrList[attrIdx].FindFirstEntry() : NULL;
|
||||
}
|
||||
|
||||
const CAttrBase* CFileRecord::FindNextAttr(DWORD attrType) const
|
||||
{
|
||||
DWORD attrIdx = ATTR_INDEX(attrType);
|
||||
|
||||
return attrIdx < ATTR_NUMS ? AttrList[attrIdx].FindNextEntry() : NULL;
|
||||
}
|
||||
|
||||
// Get File Name (First Win32 name)
|
||||
int CFileRecord::GetFileName(_TCHAR *buf, DWORD bufLen) const
|
||||
{
|
||||
// A file may have several filenames
|
||||
// Return the first Win32 filename
|
||||
CAttr_FileName *fn = (CAttr_FileName*)AttrList[ATTR_INDEX(ATTR_TYPE_FILE_NAME)].FindFirstEntry();
|
||||
while (fn)
|
||||
{
|
||||
if (fn->IsWin32Name())
|
||||
{
|
||||
int len = fn->GetFileName(buf, bufLen);
|
||||
if (len != 0)
|
||||
return len; // success or fail
|
||||
}
|
||||
|
||||
fn = (CAttr_FileName*)AttrList[ATTR_INDEX(ATTR_TYPE_FILE_NAME)].FindNextEntry();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Get File Size
|
||||
__inline ULONGLONG CFileRecord::GetFileSize() const
|
||||
{
|
||||
CAttr_FileName *fn = (CAttr_FileName*)AttrList[ATTR_INDEX(ATTR_TYPE_FILE_NAME)].FindFirstEntry();
|
||||
return fn ? fn->GetFileSize() : 0;
|
||||
}
|
||||
|
||||
// Get File Times
|
||||
void CFileRecord::GetFileTime(FILETIME *writeTm, FILETIME *createTm, FILETIME *accessTm) const
|
||||
{
|
||||
// Standard Information attribute hold the most updated file time
|
||||
CAttr_StdInfo *si = (CAttr_StdInfo*)AttrList[ATTR_INDEX(ATTR_TYPE_STANDARD_INFORMATION)].FindFirstEntry();
|
||||
if (si)
|
||||
si->GetFileTime(writeTm, createTm, accessTm);
|
||||
else
|
||||
{
|
||||
writeTm->dwHighDateTime = 0;
|
||||
writeTm->dwLowDateTime = 0;
|
||||
if (createTm)
|
||||
{
|
||||
createTm->dwHighDateTime = 0;
|
||||
createTm->dwLowDateTime = 0;
|
||||
}
|
||||
if (accessTm)
|
||||
{
|
||||
accessTm->dwHighDateTime = 0;
|
||||
accessTm->dwLowDateTime = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Traverse all sub directories and files contained
|
||||
// Call user defined callback routine once found an entry
|
||||
void CFileRecord::TraverseSubEntries(SUBENTRY_CALLBACK seCallBack) const
|
||||
{
|
||||
_ASSERT(seCallBack);
|
||||
|
||||
// Start traversing from IndexRoot (B+ tree root node)
|
||||
|
||||
CAttr_IndexRoot* ir = (CAttr_IndexRoot*)FindFirstAttr(ATTR_TYPE_INDEX_ROOT);
|
||||
if (ir == NULL || !ir->IsFileName())
|
||||
return;
|
||||
|
||||
CIndexEntryList *ieList = (CIndexEntryList*)ir;
|
||||
CIndexEntry *ie = ieList->FindFirstEntry();
|
||||
while (ie)
|
||||
{
|
||||
// Visit subnode first
|
||||
if (ie->IsSubNodePtr())
|
||||
TraverseSubNode(ie->GetSubNodeVCN(), seCallBack);
|
||||
|
||||
if (ie->HasName())
|
||||
seCallBack(ie);
|
||||
|
||||
ie = ieList->FindNextEntry();
|
||||
}
|
||||
}
|
||||
|
||||
// Find a specific FileName from InexRoot described B+ tree
|
||||
__inline const BOOL CFileRecord::FindSubEntry(const _TCHAR *fileName, CIndexEntry &ieFound) const
|
||||
{
|
||||
// Start searching from IndexRoot (B+ tree root node)
|
||||
CAttr_IndexRoot *ir = (CAttr_IndexRoot*)FindFirstAttr(ATTR_TYPE_INDEX_ROOT);
|
||||
if (ir == NULL || !ir->IsFileName())
|
||||
return FALSE;
|
||||
|
||||
CIndexEntryList *ieList = (CIndexEntryList*)ir;
|
||||
CIndexEntry *ie = ieList->FindFirstEntry();
|
||||
while (ie)
|
||||
{
|
||||
if (ie->HasName())
|
||||
{
|
||||
// Compare name
|
||||
int i = ie->Compare(fileName);
|
||||
if (i == 0)
|
||||
{
|
||||
ieFound = *ie;
|
||||
return TRUE;
|
||||
}
|
||||
else if (i < 0) // fileName is smaller than IndexEntry
|
||||
{
|
||||
// Visit SubNode
|
||||
if (ie->IsSubNodePtr())
|
||||
{
|
||||
// Search in SubNode (IndexBlock)
|
||||
if (VisitIndexBlock(ie->GetSubNodeVCN(), fileName, ieFound))
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
return FALSE; // not found
|
||||
}
|
||||
// Just step forward if fileName is bigger than IndexEntry
|
||||
}
|
||||
else if (ie->IsSubNodePtr())
|
||||
{
|
||||
// Search in SubNode (IndexBlock)
|
||||
if (VisitIndexBlock(ie->GetSubNodeVCN(), fileName, ieFound))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
ie = ieList->FindNextEntry();
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Find Data attribute class of
|
||||
const CAttrBase* CFileRecord::FindStream(_TCHAR *name)
|
||||
{
|
||||
const CAttrBase *data = FindFirstAttr(ATTR_TYPE_DATA);
|
||||
while (data)
|
||||
{
|
||||
if (data->IsUnNamed() && name == NULL) // Unnamed stream
|
||||
break;
|
||||
if ((!data->IsUnNamed()) && name) // Named stream
|
||||
{
|
||||
_TCHAR an[MAX_PATH];
|
||||
if (data->GetAttrName(an, MAX_PATH))
|
||||
{
|
||||
if (_tcscmp(an, name) == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
data = FindNextAttr(ATTR_TYPE_DATA);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
// Check if it's deleted or in use
|
||||
__inline BOOL CFileRecord::IsDeleted() const
|
||||
{
|
||||
return !(FileRecord->Flags & FILE_RECORD_FLAG_INUSE);
|
||||
}
|
||||
|
||||
// Check if it's a directory
|
||||
__inline BOOL CFileRecord::IsDirectory() const
|
||||
{
|
||||
return FileRecord->Flags & FILE_RECORD_FLAG_DIR;
|
||||
}
|
||||
|
||||
__inline BOOL CFileRecord::IsReadOnly() const
|
||||
{
|
||||
// Standard Information attribute holds the most updated file time
|
||||
const CAttr_StdInfo *si = (CAttr_StdInfo*)AttrList[ATTR_INDEX(ATTR_TYPE_STANDARD_INFORMATION)].FindFirstEntry();
|
||||
return si ? si->IsReadOnly() : FALSE;
|
||||
}
|
||||
|
||||
__inline BOOL CFileRecord::IsHidden() const
|
||||
{
|
||||
const CAttr_StdInfo *si = (CAttr_StdInfo*)AttrList[ATTR_INDEX(ATTR_TYPE_STANDARD_INFORMATION)].FindFirstEntry();
|
||||
return si ? si->IsHidden() : FALSE;
|
||||
}
|
||||
|
||||
__inline BOOL CFileRecord::IsSystem() const
|
||||
{
|
||||
const CAttr_StdInfo *si = (CAttr_StdInfo*)AttrList[ATTR_INDEX(ATTR_TYPE_STANDARD_INFORMATION)].FindFirstEntry();
|
||||
return si ? si->IsSystem() : FALSE;
|
||||
}
|
||||
|
||||
__inline BOOL CFileRecord::IsCompressed() const
|
||||
{
|
||||
const CAttr_StdInfo *si = (CAttr_StdInfo*)AttrList[ATTR_INDEX(ATTR_TYPE_STANDARD_INFORMATION)].FindFirstEntry();
|
||||
return si ? si->IsCompressed() : FALSE;
|
||||
}
|
||||
|
||||
__inline BOOL CFileRecord::IsEncrypted() const
|
||||
{
|
||||
const CAttr_StdInfo *si = (CAttr_StdInfo*)AttrList[ATTR_INDEX(ATTR_TYPE_STANDARD_INFORMATION)].FindFirstEntry();
|
||||
return si ? si->IsEncrypted() : FALSE;
|
||||
}
|
||||
|
||||
__inline BOOL CFileRecord::IsSparse() const
|
||||
{
|
||||
const CAttr_StdInfo *si = (CAttr_StdInfo*)AttrList[ATTR_INDEX(ATTR_TYPE_STANDARD_INFORMATION)].FindFirstEntry();
|
||||
return si ? si->IsSparse() : FALSE;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////
|
||||
// NTFS Volume Implementation
|
||||
///////////////////////////////////////
|
||||
CNTFSVolume::CNTFSVolume(_TCHAR volume)
|
||||
{
|
||||
hVolume = INVALID_HANDLE_VALUE;
|
||||
VolumeOK = FALSE;
|
||||
MFTRecord = NULL;
|
||||
MFTData = NULL;
|
||||
Version = 0;
|
||||
ClearAttrRawCB();
|
||||
|
||||
if (!OpenVolume(volume))
|
||||
return;
|
||||
|
||||
// Verify NTFS volume version (must >= 3.0)
|
||||
|
||||
CFileRecord vol(this);
|
||||
vol.SetAttrMask(MASK_VOLUME_NAME | MASK_VOLUME_INFORMATION);
|
||||
if (!vol.ParseFileRecord(MFT_IDX_VOLUME))
|
||||
return;
|
||||
|
||||
vol.ParseAttrs();
|
||||
CAttr_VolInfo *vi = (CAttr_VolInfo*)vol.FindFirstAttr(ATTR_TYPE_VOLUME_INFORMATION);
|
||||
if (!vi)
|
||||
return;
|
||||
|
||||
Version = vi->GetVersion();
|
||||
NTFS_TRACE2("NTFS volume version: %u.%u\n", HIBYTE(Version), LOBYTE(Version));
|
||||
if (Version < 0x0300) // NT4 ?
|
||||
return;
|
||||
|
||||
#ifdef _DEBUG
|
||||
CAttr_VolName *vn = (CAttr_VolName*)vol.FindFirstAttr(ATTR_TYPE_VOLUME_NAME);
|
||||
if (vn)
|
||||
{
|
||||
char volname[MAX_PATH];
|
||||
if (vn->GetName(volname, MAX_PATH) > 0)
|
||||
{
|
||||
NTFS_TRACE1("NTFS volume name: %s\n", volname);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
VolumeOK = TRUE;
|
||||
|
||||
MFTRecord = new CFileRecord(this);
|
||||
MFTRecord->SetAttrMask(MASK_DATA);
|
||||
if (MFTRecord->ParseFileRecord(MFT_IDX_MFT))
|
||||
{
|
||||
MFTRecord->ParseAttrs();
|
||||
MFTData = MFTRecord->FindFirstAttr(ATTR_TYPE_DATA);
|
||||
if (MFTData == NULL)
|
||||
{
|
||||
delete MFTRecord;
|
||||
MFTRecord = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CNTFSVolume::~CNTFSVolume()
|
||||
{
|
||||
if (hVolume != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(hVolume);
|
||||
|
||||
if (MFTRecord)
|
||||
delete MFTRecord;
|
||||
}
|
||||
|
||||
// Open a volume ('a' - 'z', 'A' - 'Z'), get volume handle and BPB
|
||||
BOOL CNTFSVolume::OpenVolume(_TCHAR volume)
|
||||
{
|
||||
// Verify parameter
|
||||
if (!_istalpha(volume))
|
||||
{
|
||||
NTFS_TRACE("Volume name error, should be like 'C', 'D'\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
_TCHAR volumePath[7];
|
||||
_sntprintf(volumePath, 6, _T("\\\\.\\%c:"), volume);
|
||||
volumePath[6] = _T('\0');
|
||||
|
||||
hVolume = CreateFile(volumePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
|
||||
if (hVolume != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
DWORD num;
|
||||
NTFS_BPB bpb;
|
||||
|
||||
// Read the first sector (boot sector)
|
||||
if (ReadFile(hVolume, &bpb, 512, &num, NULL) && num == 512)
|
||||
{
|
||||
if (strncmp((const char*)bpb.Signature, NTFS_SIGNATURE, 8) == 0)
|
||||
{
|
||||
// Log important volume parameters
|
||||
|
||||
SectorSize = bpb.BytesPerSector;
|
||||
NTFS_TRACE1("Sector Size = %u bytes\n", SectorSize);
|
||||
|
||||
ClusterSize = SectorSize * bpb.SectorsPerCluster;
|
||||
NTFS_TRACE1("Cluster Size = %u bytes\n", ClusterSize);
|
||||
|
||||
int sz = (char)bpb.ClustersPerFileRecord;
|
||||
if (sz > 0)
|
||||
FileRecordSize = ClusterSize * sz;
|
||||
else
|
||||
FileRecordSize = 1 << (-sz);
|
||||
NTFS_TRACE1("FileRecord Size = %u bytes\n", FileRecordSize);
|
||||
|
||||
sz = (char)bpb.ClustersPerIndexBlock;
|
||||
if (sz > 0)
|
||||
IndexBlockSize = ClusterSize * sz;
|
||||
else
|
||||
IndexBlockSize = 1 << (-sz);
|
||||
NTFS_TRACE1("IndexBlock Size = %u bytes\n", IndexBlockSize);
|
||||
|
||||
MFTAddr = bpb.LCN_MFT * ClusterSize;
|
||||
NTFS_TRACE1("MFT address = 0x%016I64X\n", MFTAddr);
|
||||
}
|
||||
else
|
||||
{
|
||||
NTFS_TRACE("Volume file system is not NTFS\n");
|
||||
goto IOError;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NTFS_TRACE("Read boot sector error\n");
|
||||
goto IOError;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NTFS_TRACE1("Cannnot open volume %c\n", (char)volume);
|
||||
IOError:
|
||||
if (hVolume != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CloseHandle(hVolume);
|
||||
hVolume = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Check if Volume is successfully opened
|
||||
__inline BOOL CNTFSVolume::IsVolumeOK() const
|
||||
{
|
||||
return VolumeOK;
|
||||
}
|
||||
|
||||
// Get NTFS volume version
|
||||
__inline WORD CNTFSVolume::GetVersion() const
|
||||
{
|
||||
return Version;
|
||||
}
|
||||
|
||||
// Get File Record count
|
||||
__inline ULONGLONG CNTFSVolume::GetRecordsCount() const
|
||||
{
|
||||
return (MFTData->GetDataSize() / FileRecordSize);
|
||||
}
|
||||
|
||||
// Get BPB information
|
||||
|
||||
__inline DWORD CNTFSVolume::GetSectorSize() const
|
||||
{
|
||||
return SectorSize;
|
||||
}
|
||||
|
||||
__inline DWORD CNTFSVolume::GetClusterSize() const
|
||||
{
|
||||
return ClusterSize;
|
||||
}
|
||||
|
||||
__inline DWORD CNTFSVolume::GetFileRecordSize() const
|
||||
{
|
||||
return FileRecordSize;
|
||||
}
|
||||
|
||||
__inline DWORD CNTFSVolume::GetIndexBlockSize() const
|
||||
{
|
||||
return IndexBlockSize;
|
||||
}
|
||||
|
||||
// Get MFT starting address
|
||||
__inline ULONGLONG CNTFSVolume::GetMFTAddr() const
|
||||
{
|
||||
return MFTAddr;
|
||||
}
|
||||
|
||||
// Install Attribute CallBack routines for the whole Volume
|
||||
BOOL CNTFSVolume::InstallAttrRawCB(DWORD attrType, ATTR_RAW_CALLBACK cb)
|
||||
{
|
||||
DWORD atIdx = ATTR_INDEX(attrType);
|
||||
if (atIdx < ATTR_NUMS)
|
||||
{
|
||||
AttrRawCallBack[atIdx] = cb;
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Clear all Attribute CallBack routines
|
||||
__inline void CNTFSVolume::ClearAttrRawCB()
|
||||
{
|
||||
for (int i = 0; i < ATTR_NUMS; i++)
|
||||
AttrRawCallBack[i] = NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
Binary file not shown.
@@ -0,0 +1,160 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{9622A76B-A2B2-4E45-B38B-1EBD2A0DDAEF}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>ntfsDump</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="NTFS.h" />
|
||||
<ClInclude Include="NTFS_Attribute.h" />
|
||||
<ClInclude Include="NTFS_Common.h" />
|
||||
<ClInclude Include="NTFS_DataType.h" />
|
||||
<ClInclude Include="NTFS_FileRecord.h" />
|
||||
<ClInclude Include="stdafx.h" />
|
||||
<ClInclude Include="targetver.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="ntfsDump.cpp" />
|
||||
<ClCompile Include="stdafx.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user