Hi CodedK,
I don't find it on Google. Some keywords to find?
Andrea
Main Topics
Browse All TopicsIs there a code in Delphi like the undelete DOS command? I want to know the list of the files that is possible to recover?
In the
http://www.experts-exchang
there is a solution but it is no longer available.
This Question has been solved and asker verified All Experts Exchange premium technology solutions are available to subscription members.
Experts Exchange has been collecting answers to technology questions since 1996…3 million and counting! If you have a question, chances are we already have your answer.
If you can't find the exact answer you're looking for, ask our exclusive community of 50,000 experts. You’ll get a personalized answer from a trusted professional.
Thousands of free tech tips, tricks, how-to’s and tutorials are available in our peer reviewed articles section. See for yourself how smart our experts are, no login required.
Access the answers to your technology questions today.
30-day free trial. Register in 60 seconds.
Members of the expert community talk about why the experience at Experts Exchange is different than what you will find anywhere else.

Try it out and discover for yourself.
30-day free trial. Register in 60 seconds.
Join the community of experts here and help other tech pros by answering question in your area of expertise. You can earn FREE access to all Experts Exchange's premium features and resources.
Andrea i cant give something that belongs to someone else.
He decided to sell this, i cannot give his source, sorry.
The source is for Delphi and its very good ! Full application with source (view, undelete, restore deleted partitions) everything is inside.
I don't know what to say... Look harder.
If i find anything else i will post something but i doubt it because everyone sells this code.
The problem Andrea is that this kind of source requires the build of a driver for NT file system...
And then some source to handle this.
So i sincerely i doubt that anyone will answer to your question.
"Windows NT File System Internals : A Developer's Guide"
http://www.amazon.com/Wind
I'll upload the sources here :
http://www.geocities.com/k
Tell me when you will download it, so i can remove it.
Hi Andrea.
Look, you asked for a code that will provide a list of the files that is possible to recover.
Short answer : This is not possible.
Because even the pro applications out there that provide undelete functions can sometime give you a corrupted file back or part of a file.
Moreover the code i gave you is for FAT 32 allocation table. It cannot scan NTFS drives (it scans physical as logical though). Like i told you its unbelievably hard to do something like this. If i had this code i would sold it ! And if i started a project like this it would be a fulltime job. In Torry site there is NO Delphi code for this and there is a reason for that ;)
Hi CodedK,
Unfortunately I was not clear in my response or request. I apologize. I'm very sorry for this.
I am only interested in knowing the list of files that can be recovered completely or partially.
I do not care even know if a file is or not in good or poor condition. I am not interested to have the code to retrieve-undelete the file.
The link to the book you have post is very good but for me is difficult to find (in this book-code) or to create a procedure-function to ONLY have the list of file from a specific drive. Can you help me with this new information?
Andrea,
I'm posting a code conversion done from source on CodeProject. Its for undeleting files on an NTFS drive. It seems "fairly" stable, and I have tested it and it does undelete files by using the MFT of the drive. As CodedK already stated, some of the sectors for the file may already be used for something else, so don't expect miracles. Hopefully this will get you started in the right direction.
Russell
----
unit Ntfs;
//////////////////////////
//
// Unit : Ntfs
// Source : http://www.codeproject.com
// Conversion : rllibby
// Date : 12.08.2008
// Description : NTFS drive and file handling
//
//////////////////////////
interface
//////////////////////////
// Include units
//////////////////////////
uses
Windows, SysUtils, Classes;
//////////////////////////
// Constants
//////////////////////////
const
PHYSICAL_DRIVE = '\\.\PhysicalDrive0';
PART_TABLE = 0;
BOOT_RECORD = 1;
EXTENDED_PART = 2;
PART_UNKNOWN = $00; // Unknown.
PART_DOS2_FAT = $01; // 12-bit FAT.
PART_DOS3_FAT = $04; // 16-bit FAT. Partition smaller than 32MB.
PART_EXTENDED = $05; // Extended MS-DOS Partition.
PART_DOS4_FAT = $06; // 16-bit FAT. Partition larger than or equal to 32MB.
PART_DOS32 = $0B; // 32-bit FAT. Partition up to 2047GB.
PART_DOS32X = $0C; // Same as PART_DOS32(0Bh), but uses Logical Block Address Int 13h extensions.
PART_DOSX13 = $0E; // Same as PART_DOS4_FAT(06h), but uses Logical Block Address Int 13h extensions.
PART_DOSX13X = $0F; // Same as PART_EXTENDED(05h), but uses Logical Block Address Int 13h extensions.
//////////////////////////
// Data type declarations
//////////////////////////
type
DRIVEINFO = packed record
wCylinder: Word;
wHead: Word;
wSector: Word;
dwNumSectors: DWORD;
wType: Word;
dwRelativeSector: DWORD;
dwNTRelativeSector: DWORD;
dwBytesPerSector: DWORD;
end;
LPDRIVEINFO = ^DRIVEINFO;
DRIVEINFO_ARRAY = Array [0..MaxWord] of DRIVEINFO;
LPDRIVEINFO_ARRAY = ^DRIVEINFO_ARRAY;
PARTITION = packed record
chBootInd: Byte;
chHead: Byte;
chSector: Byte;
chCylinder: Byte;
chType: Byte;
chLastHead: Byte;
chLastSector: Byte;
chLastCylinder: Byte;
dwRelativeSector: DWORD;
dwNumberSectors: DWORD;
end;
LPPARTITION = ^PARTITION;
ST_FILEINFO = packed record
dwIndex: DWORD;
szFileName: Array [0..Pred(MAX_PATH)] of Char;
n64Create: LONGLONG;
n64Modify: LONGLONG;
n64Modfil: LONGLONG;
n64Access: LONGLONG;
dwAttributes: DWORD;
n64Size: LONGLONG;
bDeleted: BOOL;
end;
NTFS_BPB = packed record
wBytesPerSec: Word;
uchSecPerClust: Byte;
wReservedSec: Word;
uchReserved: Array [0..2] of Byte;
wUnused1: Word;
uchMediaDescriptor: Byte;
wUnused2: Word;
wSecPerTrack: Word;
wNumberOfHeads: Word;
dwHiddenSec: DWORD;
dwUnused3: DWORD;
dwUnused4: DWORD;
n64TotalSec: LONGLONG;
n64MFTLogicalClustNum: LONGLONG;
n64MFTMirrLogicalClustNum:
nClustPerMFTRecord: Integer;
nClustPerIndexRecord: Integer;
n64VolumeSerialNum: LONGLONG;
dwChecksum: DWORD;
end;
NTFS_PART_BOOT_SEC = packed record
chJumpInstruction: Array [0..2] of Char;
chOemID: Array [0..3] of Char;
chDummy: Array [0..3] of Char;
bpb: NTFS_BPB;
chBootstrapCode: Array [0..425] of Char;
wSecMark: Word;
end;
NTFS_MFT_FILE = packed record
szSignature: Array [0..3] of Char;
wFixupOffset: Word;
wFixupSize: Word;
n64LogSeqNumber: LONGLONG;
wSequence: Word;
wHardLinks: Word;
wAttribOffset: Word;
wFlags: Word;
dwRecLength: DWORD;
dwAllLength: DWORD;
n64BaseMftRec: LONGLONG;
wNextAttrID: Word;
wFixupPattern: Word;
dwMFTRecNumber: DWORD;
end;
ATTR_RESIDENT = packed record
dwLength: DWORD;
wAttrOffset: Word;
uchIndexedTag: Byte;
uchPadding: Byte;
end;
ATTR_NONRESIDENT = packed record
n64StartVCN: LONGLONG;
n64EndVCN: LONGLONG;
wDatarunOffset: Word;
wCompressionSize: Word;
uchPadding: Array [0..3] of Byte;
n64AllocSize: LONGLONG;
n64RealSize: LONGLONG;
n64StreamSize: LONGLONG;
end;
ATTR_UNION = packed record
case Integer of
0 : (Resident: ATTR_RESIDENT);
1 : (NonResident: ATTR_NONRESIDENT);
end;
NTFS_ATTRIBUTE = packed record
dwType: DWORD;
dwFullLength: DWORD;
uchNonResFlag: Byte;
uchNameLength: Byte;
wNameOffset: Word;
wFlags: Word;
wID: Word;
Attr: ATTR_UNION;
end;
ATTR_STANDARD = packed record
n64Create: LONGLONG;
n64Modify: LONGLONG;
n64Modfil: LONGLONG;
n64Access: LONGLONG;
dwFATAttributes: DWORD;
dwReserved1: DWORD;
end;
ATTR_FILENAME = packed record
dwMftParentDir: LONGLONG;
n64Create: LONGLONG;
n64Modify: LONGLONG;
n64Modfil: LONGLONG;
n64Access: LONGLONG;
n64Allocated: LONGLONG;
n64RealSize: LONGLONG;
dwFlags: DWORD;
dwEAsReparsTag: DWORD;
chFileNameLength: BYTE;
chFileNameType: BYTE;
wFilename: Array [0..511] of WChar;
end;
//////////////////////////
// Class declarations
//////////////////////////
type
TNTFSDrive = class(TObject)
private
// Private declarations
FDrive: THandle;
FInitialized: Boolean;
FStartSector: DWORD;
FBytesPerCluster: DWORD;
FBytesPerSector: DWORD;
FMFT: PByteArray;
FMFTRecord: PByteArray;
FMFTLen: DWORD;
FMFTRecordSz: DWORD;
function LoadMFT(nStartCluster: LONGLONG): Integer;
protected
// Protected declarations
procedure Cleanup;
public
// Public declarations
constructor Create;
destructor Destroy; override;
function Initialize(lpDriveInfo: DRIVEINFO): Integer;
function GetFileDetail(nFileSeq: DWORD; out stFileInfo: ST_FILEINFO): Integer;
function ReadFile(nFileSeq: DWORD; Stream: TStream): Integer;
// Public properties
property BytesPerCluster: DWORD read FBytesPerCluster;
property BytesPerSector: DWORD read FBytesPerSector;
property Drive: THandle read FDrive;
property IsInitialized: Boolean read FInitialized;
property StartSector: DWORD read FStartSector;
end;
TMFTRecord = class(TObject)
private
// Private declarations
FDrive: THandle;
FMFTRecord: PByteArray;
FMaxMFTRecSize: DWORD;
FCurPos: DWORD;
FBytesPerCluster: DWORD;
F64StartPos: LONGLONG;
FInUse: BOOL;
protected
// Protected declarations
FAttrFilename: ATTR_FILENAME;
FAttrStandard: ATTR_STANDARD;
FFileDataSz: DWORD;
FFileData: PByteArray;
procedure Cleanup;
function ReadRaw(n64LCN: LONGLONG; lpData: PByteArray; var n64Len: LONGLONG): Integer;
function ExtractData(ntfsAttr: NTFS_ATTRIBUTE; var lpData: PByteArray; out dwDataLen: DWORD): Integer;
public
// Public declarations
constructor Create(hDrive: THandle; n64StartPos: LONGLONG; dwRecSize: DWORD; dwBytesPerCluster: DWORD);
destructor Destroy; override;
function ExtractFile(lpMFTBuffer: PByteArray; dwLen: DWORD; bExcludeData: Boolean = False): Integer;
end;
//////////////////////////
//
// Function : ScanLogicalDrives
//
// Parameters : lpDriveInfo - [in] Allocated buffer for an array of DRIVEINFO.
// Count - [in/out] On input, specifies the number of entries
// that lpDriveInfo can hold. On output, it is set
// with the total number of enties located. If the
// buffer is too small to hold all the enties an
// error code of ERROR_INSUFFICIENT_BUFFER will
// be returned.
//
// Returns : On success a code of ERROR_SUCCESS will be returned. If there
// are more entries than the buffer can hold, the buffer is filled
// and a return of ERROR_INSUFFICIENT_BUFFER is passed back. Any
// other code indicates a failure.
//
//////////////////////////
function ScanLogicalDrives(lpDriveI
implementation
//// TMFTRecord //////////////////////////
function TMFTRecord.ReadRaw(n64LCN:
var n64Pos: LARGE_INTEGER;
lpTmp: PByteArray;
dwBytesRead: DWORD;
dwBytes: DWORD;
dwTotRead: DWORD;
begin
// Set position
n64Pos.QuadPart:=(n64LCN) * FBytesPerCluster;
// Update by actual start position
Inc(n64Pos.QuadPart, F64StartPos);
// Data is available in the relative sector from the begining od the drive
if (SetFilePointer(FDrive, n64Pos.LowPart, @n64Pos.HighPart, FILE_BEGIN) = $FFFFFFFF) then
// Failed
result:=GetLastError
else
begin
// Set default result
result:=ERROR_SUCCESS;
// Set temp pointer
lpTmp:=lpData;
// Clear counters
dwBytes:=0;
dwTotRead:=0;
// While total read is less than length
while (dwTotRead < n64Len) do
begin
// Reading a cluster at a time
dwBytesRead:=FBytesPerClus
// This can not read partial sectors
if not(ReadFile(FDrive, lpTmp^, dwBytesRead, dwBytes, nil)) then
begin
// Failure
result:=GetLastError;
// Done processing
break;
end;
// Udpate total
Inc(dwTotRead, dwBytes);
// Update buffer pointer
Inc(PChar(lpTmp), dwBytes);
end;
// Update total read
n64Len:=dwTotRead;
end;
end;
function TMFTRecord.ExtractData(ntf
var n64Len: LONGLONG;
n64Offset: LONGLONG;
n64LCN: LONGLONG;
lpTmpBuff: PByteArray;
lpTemp: PByteArray;
dwCurPos: DWORD;
dwIndex: Integer;
chLenOffSz: Byte;
chLenSz: Byte;
chOffsetSz: Byte;
begin
// Default result
result:=ERROR_SUCCESS;
// Set return buffer
lpData:=nil;
// Resource protection
try
// Get current position
dwCurPos:=FCurPos;
// Check resident flag
if (ntfsAttr.uchNonResFlag = 0) then
begin
// Residence attribute, this always resides in the MFT table itself
dwDataLen:=ntfsAttr.Attr.R
// Allocate memory for data
lpData:=AllocMem(dwDataLen
// Copy data
Move(FMFTRecord[dwCurPos + ntfsAttr.Attr.Resident.wAt
end
else
begin
// Non-residence attribute, this resides in the other part of the physical drive
if (ntfsAttr.Attr.NonResident
begin
ntfsAttr.Attr.NonResident.
end;
// ATTR_STANDARD size may not be correct
dwDataLen:=ntfsAttr.Attr.N
// Allocate for reading data
lpData:=AllocMem(ntfsAttr.
// Set pointer
n64LCN:=0;
// Set pointer to temp data
lpTmpBuff:=lpData;
// Update current position
Inc(dwCurPos, ntfsAttr.Attr.NonResident.
// While forever
while True do
begin
// Read the length of LCN / VCN and length
chLenOffSz:=FMFTRecord[dwC
// Update
Inc(dwCurPos);
// Check for zero
if (chLenOffSz = 0) then break;
// Get len and offset size
chLenSz:=chLenOffSz and $0F;
chOffsetSz:=(chLenOffSz and $F0) shr 4;
// Read the data length
n64Len:=0;
// Copy memory
Move(FMFTRecord[dwCurPos],
// Increment position
Inc(dwCurPos, chLenSz);
// Read the LCN / VCN offset
n64Offset:=0;
// Copy memory
Move(FMFTRecord[dwCurPos],
// Increment position
Inc(dwCurPos, chOffsetSz);
// Cast as byte array
lpTemp:=PByteArray(@n64Off
// If the last bit of n64Offset is 1 then its -ve so youve got to make it -ve
if ((lpTemp[chOffsetSz - 1] and $80) = $80) then
begin
for dwIndex:=Pred(SizeOf(LONGL
end;
// Increment lcn
Inc(n64LCN, n64Offset);
// Multiply and increment
n64Len:=n64Len * FBytesPerCluster;
// Read the actual data; since the data is available out side the MFT table, physical drive should be accessed
result:=ReadRaw(n64LCN, lpTmpBuff, n64Len);
// Bail on error
if (result <> ERROR_SUCCESS) then break;
// Update the buffer
Inc(PChar(lpTmpBuff), n64Len);
end;
end;
finally
// Free memory if failed
if ((result <> ERROR_SUCCESS) and Assigned(lpData)) then
begin
// Free
FreeMem(lpData);
// Clear
lpData:=nil;
// Set data length
dwDataLen:=0;
end;
end;
end;
function TMFTRecord.ExtractFile(lpM
var ntfsMFT: NTFS_MFT_FILE;
ntfsAttr: NTFS_ATTRIBUTE;
lpTempData: PByteArray;
dwTempData: DWORD;
begin
// Check params
if (FMaxMFTRecSize > dwLen) or not(Assigned(lpMFTBuffer))
// Invalid params
result:=ERROR_INVALID_PARA
else
begin
// Set pointer to buffer
FMFTRecord:=lpMFTBuffer;
// Set current position
FCurPos:=0;
// Release file data
Cleanup;
// Copy the record header in MFT table
Move(FMFTRecord[FCurPos], ntfsMFT, SizeOf(NTFS_MFT_FILE));
// Check signature
if (StrLComp(ntfsMFT.szSignat
// Not the correct signature
result:=ERROR_INVALID_PARA
else
begin
// Default result
result:=ERROR_SUCCESS;
// Determine if in use
FInUse:=((ntfsMFT.wFlags and $01) = $01);
// Set current pos
FCurPos:=ntfsMFT.wAttribOf
// Extract the attribute headers
repeat
// Break if current pos is > dwLen
if (FCurPos >= dwLen) then break;
// Copy the header
Move(FMFTRecord[FCurPos], ntfsAttr, SizeOf(NTFS_ATTRIBUTE));
// Handle tha attribute type
case ntfsAttr.dwType of
// Unused
$00 : ;
// Standard information
$10 :
begin
// Extract the data
result:=ExtractData(ntfsAt
// Check result
if (result = ERROR_SUCCESS) then
begin
// Set standard attribute
Move(lpTempData^, FAttrStandard, SizeOf(ATTR_STANDARD));
// Free mem
FreeMem(lpTempData);
// Clear size
dwTempData:=0;
end
else
// Failure
break;
end;
// File name
$30 :
begin
// Extract the data
result:=ExtractData(ntfsAt
// Check result
if (result = ERROR_SUCCESS) then
begin
// Set filename attribute
Move(lpTempData^, FAttrFilename, SizeOf(ATTR_FILENAME));
// Free mem
FreeMem(lpTempData);
// Clear size
dwTempData:=0;
end
else
// Failure
break;
end;
// Object ID
$40 : ;
// Security descriptor
$50 : ;
// Volume name
$60 : ;
// Volume informatio n
$70 : ;
// Data
$80 :
begin
// Check to see if data is to be excluded
if not(bExcludeData) then
begin
// Extract the file data
result:=ExtractData(ntfsAt
// Check result
if (result = ERROR_SUCCESS) then
begin
// Start of data, or data to append
if Assigned(FFileData) then
begin
// Realloc buffer
ReallocMem(FFileData, FFileDataSz + dwTempData);
// Copy new data
Move(lpTempData^, FFileData^[FFileDataSz], dwTempData);
// Update total file size
Inc(FFileDataSz, dwTempData);
// Free mem
FreeMem(lpTempData);
// Clear size
dwTempData:=0;
end
else
begin
// Set data buffer
FFileData:=lpTempData;
// Set data buffer size
FFileDataSz:=dwTempData;
// Clear pointer
lpTempData:=nil;
end;
end
else
// Failure
break;
end;
end;
// Index root
$90 : ;
// Index allocation
$A0 : break;
// Bitmap
$B0 : ;
// Reparse point
$C0 : ;
// EA Information
$D0 : ;
// EA
$E0 : ;
// Property set
$F0 : ;
// Logged utility stream
$100 : ;
// First user defined attribute
$1000 : ;
// End
$FFFFFFFF: break;
else
// Not handled
break;
end;
// Update the current posisition
Inc(FCurPos, ntfsAttr.dwFullLength);
// Repeat while length is not zero
until (ntfsAttr.dwFullLength = 0);
end;
end;
end;
procedure TMFTRecord.Cleanup;
begin
// Resource protection
try
// Clear size
FFileDataSz:=0;
// Release memory
if Assigned(FFileData) then FreeMem(FFileData);
finally
// Clear pointer
FFileData:=nil;
end;
end;
constructor TMFTRecord.Create(hDrive: THandle; n64StartPos: LONGLONG; dwRecSize: DWORD; dwBytesPerCluster: DWORD);
begin
// Perform inherited
inherited Create;
// Set defaults
FDrive:=hDrive;
FMaxMFTRecSize:=dwRecSize;
FBytesPerCluster:=dwBytesP
F64StartPos:=n64StartPos;
FillChar(FAttrStandard, SizeOf(ATTR_STANDARD), 0);
FillChar(FAttrFilename, SizeOf(ATTR_FILENAME), 0);
FFileData:=nil;
FMFTRecord:=nil;
FFileDataSz:=0;
FCurPos:=0;
FInUse:=False;
// Sanity check on the params
if (hDrive = INVALID_HANDLE_VALUE) then
// Raise
raise Exception.Create(SysErrorM
// Params must be non zero, and divisible by 2
else if (dwRecSize = 0) or ((dwRecSize mod 2) <> 0) then
// Raise
raise Exception.Create(SysErrorM
// Params must be non zero, and divisible by 2
else if (dwBytesPerCluster = 0) or ((dwBytesPerCluster mod 2) <> 0) then
// Raise
raise Exception.Create(SysErrorM
end;
destructor TMFTRecord.Destroy;
begin
// Resource protection
try
// Cleanup
Cleanup;
finally
// Perform inherited
inherited Destroy;
end;
end;
//// TNTFSDrive //////////////////////////
function TNTFSDrive.GetFileDetail(n
var mftFile: TMFTRecord;
begin
// Check initialized state
if not(FInitialized) then
// Return error
result:=ERROR_INVALID_ACCE
// Check for end
else if ((nFileSeq * FMFTRecordSz + FMFTRecordSz) >= FMFTLen) then
result:=ERROR_NO_MORE_FILE
else
begin
// Copy the record of the file in the MFT table
Move(FMFT[nFileSeq * FMFTRecordSz], FMFTRecord^, FMFTRecordSz);
// Create record reader
mftFile:=TMFTRecord.Create
// Resource protection
try
// Extract the file
result:=mftFile.ExtractFil
// Check result
if (result = ERROR_SUCCESS) then
begin
// Clear outbound struct
FillChar(stFileInfo, SizeOf(ST_FILEINFO), 0);
// Set index
stFileInfo.dwIndex:=nFileS
// Convert filename from widechar to ansi string
StrPCopy(@stFileInfo.szFil
// Set attributes
stFileInfo.dwAttributes:=m
stFileInfo.n64Create:=mftF
stFileInfo.n64Modify:=mftF
stFileInfo.n64Access:=mftF
stFileInfo.n64Modfil:=mftF
stFileInfo.n64Size:=mftFil
stFileInfo.n64Size:=stFile
if (stFileInfo.n64Size = 0) then stFileInfo.n64Size:=1;
stFileInfo.bDeleted:=not(m
end;
finally
// Free the object
mftFile.Free;
end;
end;
end;
function TNTFSDrive.ReadFile(nFileS
var mftFile: TMFTRecord;
begin
// Check initialized state
if not(FInitialized) then
// Return error
result:=ERROR_INVALID_ACCE
// Check for end
else if ((nFileSeq * FMFTRecordSz + FMFTRecordSz) >= FMFTLen) then
result:=ERROR_NO_MORE_FILE
// Check stream
else if (Stream = nil) then
// Invalid param
result:=ERROR_INVALID_PARA
else
begin
// Copy the record of the file in the MFT table
Move(FMFT[nFileSeq * FMFTRecordSz], FMFTRecord^, FMFTRecordSz);
// Create record reader
mftFile:=TMFTRecord.Create
// Resource protection
try
// Extract the file
result:=mftFile.ExtractFil
// Check result
if (result = ERROR_SUCCESS) then
begin
// Write file data to stream
Stream.Write(mftFile.FFile
end;
finally
// Free the object
mftFile.Free;
end;
end;
end;
function TNTFSDrive.LoadMFT(nStartC
var wszMFTName: Array [0..4] of WideChar;
mftRec: TMFTRecord;
n64Pos: LARGE_INTEGER;
dwBytes: DWORD;
begin
// Convert $MFT to wide char
StringToWideChar('$MFT', @wszMFTName, SizeOf(wszMFTName));
// NTFS starting point
n64Pos.QuadPart:=FBytesPer
// MFT starting point
n64Pos.QuadPart:=n64Pos.Qu
// Set the pointer to the MFT start
if (SetFilePointer(FDrive, n64Pos.LowPart, @n64Pos.HighPart, FILE_BEGIN) = $FFFFFFFF) then
// Failure
result:=GetLastError
else
begin
// Reading the first record in the NTFS table; first record in the NTFS is always MFT record
if not(Windows.ReadFile(FDriv
// Failed to read
result:=GetLastError
else
begin
// Create mft record
mftRec:=TMFTRecord.Create(
// Resource protection
try
// Now extract the MFT record just like the other MFT table records
result:=mftRec.ExtractFile
// Check result
if (result = ERROR_SUCCESS) then
begin
// Check mft name
if not(CompareMem(@mftRec.FAt
// Set result
result:=ERROR_BAD_DEVICE
else
begin
// Delete MFT pointer
if Assigned(FMFT) then
begin
FreeMem(FMFT);
FMFT:=nil;
FMFTLen:=0;
end;
// This data (m_puchFileData) is special since it is the data of entire MFT file
FMFT:=AllocMem(mftRec.FFil
// Set size
FMFTLen:=mftRec.FFileDataS
// Store this file to read other files
Move(mftRec.FFileData^, FMFT^,FMFTLen);
end;
end;
finally
// Free the record info
mftRec.Free;
end;
end;
end;
end;
function TNTFSDrive.Initialize(lpDr
var lpBootSec: NTFS_PART_BOOT_SEC;
n64StartPos: LARGE_INTEGER;
dwBytes: DWORD;
begin
// Cleanup first
Cleanup;
// Default result
result:=ERROR_SUCCESS;
// Resource protection
try
// Attempt to open the physical disk
FDrive:=CreateFile(PHYSICA
// Check handle
if (FDrive = INVALID_HANDLE_VALUE) then
// Failure
result:=GetLastError
else
begin
// Set starting sector
FStartSector:=lpDriveInfo.
// Set bytes per sector
FBytesPerSector:=512;
// Set start pos
n64StartPos.QuadPart:=FByt
// Set pointer to the starting NTFS volume sector in the physical drive
SetFilePointer(FDrive, n64StartPos.LowPart, @n64StartPos.HighPart, FILE_BEGIN);
// Read the boot sector for the MFT infomation
if not(Windows.ReadFile(FDriv
// Failure
result:=GetLastError
else
begin
// Check the buffer for NTFS
if (StrLComp(@lpBootSec.chOem
// Invalid drive type
result:=ERROR_INVALID_DRIV
else
begin
// Cluster is the logical entity which is made up of several sectors (a physical entity)
FBytesPerCluster:=lpBootSe
// Set record size
FMFTRecordSz:=$01 shl ((-1) * (Byte(lpBootSec.bpb.nClust
// Allocate memory for mft record
FMFTRecord:=AllocMem(FMFTR
// Load the mft table
result:=LoadMFT(lpBootSec.
end;
end;
end;
finally
// Set initialized state
FInitialized:=(result = ERROR_SUCCESS);
end;
end;
procedure TNTFSDrive.Cleanup;
begin
// Resource protection
try
// Clear state
FInitialized:=False;
FStartSector:=0;
FBytesPerCluster:=0;
FBytesPerSector:=0;
FMFTLen:=0;
FMFTRecordSz:=0;
// Close handle if open
if (FDrive <> INVALID_HANDLE_VALUE) then CloseHandle(FDrive);
// Deallocate memory
if Assigned(FMFT) then FreeMem(FMFT);
if Assigned(FMFTRecord) then FreeMem(FMFTRecord);
finally
// Clear state
FMFT:=nil;
FMFTRecord:=nil;
FDrive:=INVALID_HANDLE_VAL
end;
end;
constructor TNTFSDrive.Create;
begin
// Perform inherited
inherited Create;
// Set defaults
FDrive:=INVALID_HANDLE_VAL
FInitialized:=False;
FStartSector:=0;
FBytesPerCluster:=0;
FBytesPerSector:=0;
FMFT:=nil;
FMFTRecord:=nil;
FMFTLen:=0;
FMFTRecordSz:=0;
end;
destructor TNTFSDrive.Destroy;
begin
// Resource protection
try
// Perform claenup
Cleanup;
finally
// Perform inherited
inherited Destroy;
end;
end;
//// ScanLogicalDrives //////////////////////////
function ScanLogicalDrives(lpDriveI
var lpSector: Array [0..511] of Char;
lpPartTbl: LPPARTITION;
lpDrive: DRIVEINFO;
n64Pos: LARGE_INTEGER;
hDrive: THandle;
dwPrevRel: DWORD;
dwMainPrevRel: DWORD;
dwBytes: DWORD;
dwExtended: Integer;
dwCount: Integer;
dwIndex: Integer;
begin
// Set initial defaults
FillChar(lpDrive, SizeOf(lpDrive), 0);
dwCount:=(-1);
dwIndex:=0;
dwExtended:=0;
dwPrevRel:=0;
dwMainPrevRel:=0;
// Open the drive
hDrive:=CreateFile(PHYSICA
// Check handle
if (hDrive = INVALID_HANDLE_VALUE) then
// Failure
result:=GetLastError
else
begin
// Resource protection
try
// Read the first sector
if not(ReadFile(hDrive, lpSector, 512, dwBytes, nil)) then
// Failed to read first sector
result:=GetLastError
else
begin
// Set success state
result:=ERROR_SUCCESS;
// Get pointer to partition table
lpPartTbl:=LPPARTITION(@lp
// Scan logical partitions
while (dwIndex < 4) do
begin
// Fill in drive info
lpDrive.wCylinder:=lpPartT
lpDrive.wHead:=lpPartTbl^.
lpDrive.wSector:=lpPartTbl
lpDrive.dwNumSectors:=lpPa
// Check for extended partition or boot record
if ((lpPartTbl^.chType = PART_EXTENDED) or (lpPartTbl^.chType = PART_DOSX13X)) then
begin
lpDrive.wType:=EXTENDED_PA
dwMainPrevRel:=lpPartTbl^.
lpDrive.dwNTRelativeSector
end
else
begin
lpDrive.wType:=BOOT_RECORD
lpDrive.dwNTRelativeSector
end;
// Break if extended part or unknown type
if (lpDrive.wType = EXTENDED_PART) or (lpPartTbl^.chType = 0) then break;
// Update count
Inc(dwCount);
// Check for buffer space
if Assigned(lpDriveInfo) and (dwCount < Count) then
// Fill in array index
lpDriveInfo^[dwCount]:=lpD
else
// Set error result for buffer size
result:=ERROR_INSUFFICIENT
// Update partition table
Inc(lpPartTbl);
// Update indexer
Inc(dwIndex);
end;
// Break if index = 4
if (dwIndex < 4) then
begin
// Scan partition tables
while (dwExtended < 50) do
begin
// Check drive info
if (lpDrive.wType = EXTENDED_PART) then
begin
// Set relative sector location
n64Pos.QuadPart:=lpDrive.d
// Set file pointer
if (SetFilePointer(hDrive, n64Pos.LowPart, @n64Pos.HighPart, FILE_BEGIN) = $FFFFFFFF) then
begin
// Failure
result:=GetLastError;
// Done processing
break;
end;
// Read from drive
if not(ReadFile(hDrive, lpSector, 512, dwBytes, nil)) then
begin
// Failure
result:=GetLastError;
// Done processing
break;
end
// Must have read 512 bytes
else if (dwBytes <> 512) then
begin
// Failure
result:=ERROR_READ_FAULT;
// Done processing
break;
end;
// Access the partition table
lpPartTbl:=LPPARTITION(@lp
// Set indexer
dwIndex:=0;
// Scan drive info
while (dwIndex < 4) do
begin
// Fill in drive info
lpDrive.wCylinder:=lpPartT
lpDrive.wHead:=lpPartTbl^.
lpDrive.wSector:=lpPartTbl
lpDrive.dwNumSectors:=lpPa
lpDrive.dwRelativeSector:=
// Check for extended partition or boot record
if ((lpPartTbl^.chType = PART_EXTENDED) or (lpPartTbl^.chType = PART_DOSX13X)) then
begin
lpDrive.wType:=EXTENDED_PA
dwPrevRel:=lpPartTbl^.dwRe
lpDrive.dwNTRelativeSector
end
else
begin
lpDrive.wType:=BOOT_RECORD
lpDrive.dwNTRelativeSector
end;
// Break if extended part or unknown type
if (lpDrive.wType = EXTENDED_PART) or (lpPartTbl^.chType = 0) then break;
// Update count
Inc(dwCount);
// Check for buffer space
if Assigned(lpDriveInfo) and (dwCount < Count) then
// Fill in array index
lpDriveInfo^[dwCount]:=lpD
else
// Set error result for buffer size
result:=ERROR_INSUFFICIENT
// Update partition table
Inc(lpPartTbl);
// Update indexer
Inc(dwIndex);
end;
// Break if index = 4
if (dwIndex = 4) then break;
end;
// Update extended counter
Inc(dwExtended);
end;
end;
end;
finally
// Close the drive handle
CloseHandle(hDrive);
end;
// Set number of entries processed
Count:=Succ(dwCount);
end;
end;
end.
-- example usage --
var lpDrives: Array [0..63] of DRIVEINFO;
stFileInfo: ST_FILEINFO;
strmFile: TFileStream;
dwIndex: Integer;
dwUndelete: Integer;
begin
// Max size of array index
dwIndex:=64;
// Only want the first drive
if (ScanLogicalDrives(@lpDriv
begin
// Create ntfs drive handler
with TNTFSDrive.Create do
begin
// Initialize; this takes a few seconds because it loads the full MFT
Initialize(lpDrives[0]);
// Set starting index to skip the ($filenames)
dwIndex:=30;
// Create directory
CreateDirectory('c:\undele
// Set undelete count
dwUndelete:=0;
// While true
while True do
begin
// Get file details
if not(GetFileDetail(dwIndex,
// Check deleted
if stFileInfo.bDeleted then
begin
try
// Create file stream
strmFile:=TFileStream.Crea
// Resource protection
try
// Read file into stream
ReadFile(dwIndex, strmFile);
finally
// Free file stream
strmFile.Free;
end;
// Increment count
Inc(dwUndelete);
// Break after undeleting up to 20 files
if (dwUndelete > 20) then break;
except
// Ignore exception
end;
end;
// Check for deleted
Inc(dwIndex);
end;
end;
end;
end;
Business Accounts
Answer for Membership
by: CodedKPosted on 2008-11-18 at 21:17:07ID: 22991715
I have a source code by Christian Grau.
Once upon a time ha gave it for free now i think he sells it so i cannot give it to you.
Maybe if you search for this source in google you will find it.