mirror of
https://github.com/Wuentin/ntfsDump.git
synced 2026-06-11 06:01:19 +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