Question

Delphi code for undelete file?

Asked by: andreamatt

Is 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-exchange.com/Programming/Languages/Pascal/Delphi/Q_21529939.html?sfQueryTermInfo=1+delphi+undelet

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.

Subscribe now for full access to Experts Exchange and get

Instant Access to this Solution

  • Plus...
  • 30 Day FREE access, no risk, no obligation
  • Collaborate with the world's top tech experts
  • Unlimited access to our exclusive solution database
  • Never be left without tech help again

Subscribe Now

Asked On
2008-11-18 at 06:52:59ID23914302
Tags

Microsoft

,

Delphi

,

Delphi 7

Topics

Delphi Programming

,

Delphi IDE

Participating Experts
3
Points
500
Comments
18

Trusted by hundreds of thousands everyday for fast, accurate and reliable tech support.

  • "The time we save is the biggest benefit of Experts Exchange to Warner Bros. What could take multiple guys 2 hours or more each to find is accessed in around 15 minutes on Experts Exchange." Mike Kapnisakis, Warner Bros.
  • "Our team likes having a resource that is more secure than just using Google and most experts using this service really know their stuff. It's nice to look here first versus using Google." Dayna Sellner, Lockheed Martin
  • "Anytime that I've been stumped with a problem, 9 out of 10 times Experts Exchange has either the accepted solution or an open discussion of the potential solution to the problem." Kenny Red, eBay Inc.

See what Experts Exchange can do for you.

Got a question?

We've got the answer.

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.

Screenshot of Experts Exchange Knowledgebase

Need individual assistance?

Our experts are ready to help.

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.

Screenshot of Experts Exchange Knowledgebase

Want to learn from the best?

Read articles from industry experts.

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.

Screenshot of an Article

Working on a long term project?

Store your work and research.

Save solutions to your questions, answers you’ve discovered through searching plus helpful articles in your personal knowledgebase for easy future access.

Screenshot of Experts Exchange Knowledgebase

Access the answers to your technology questions today.

Subscribe Now

30-day free trial. Register in 60 seconds.

What Makes Experts Exchange Unique?

Members of the expert community talk about why the experience at Experts Exchange is different than what you will find anywhere else.

Trusted by the world's most respected brands.

image of each brand's logo

Faithfully serving IT professionals since 1996.

Experts Exchange Logo

Try it out and discover for yourself.

Subscribe Now

30-day free trial. Register in 60 seconds.

Related Solutions

  1. Undelete
    Is it possible to search for and list deleted files on Win95/98/ME and select to undelete them using VB6. And if so could the same code be used accross a network to undelete files on a networked PC. Could some one please help me out or point to where I can find information on...

Free Tech Articles

  1. WARNING: 5 Reasons why you should NEVER fix a computer for free.
    It is in our nature to love the puzzle. We are obsessed. The lot of us. We love puzzles. We love the challenge. We thrive on finding the answer. We hate disarray. It bothers us deep in our soul. W...
  2. SCCM OSD Basic troubleshooting
    SCCM 2007 OSD is a fantastic way to deploy operating systems, however, like most things SCCM issues can sometimes be difficult to resolve due to the sheer volume of logs to sift through and the dispe...
  3. Migrate Small Business Server 2003 to Exchange 2010 and Windows 2008 R2
    This guide is intended to provide step by step instructions on how to migrate from Small Business Server 2003 to Windows 2008 R2 with Exchange 2010. For this migration to work you will need the fo...
  4. Create a Win7 Gadget
    This article shows you how to create a simple "Gadget" -- a sort of mini-application supported by Windows 7 and Vista. Gadgets can be dropped anywhere on the desktop to provide instant information, ...
  5. Outlook continually prompting for username and password
    There have been a lot of questions recently regarding Outlook prompting for a username and password whilst using Exchange 2007. There are a few reasons why this would happen and I will try to cover t...
  6. Backup Exchange 2010 Information Store using Windows Backup
    There seems to be quite a lot of confusion around the ability to backup Exchange 2010 using the built in Windows Backup feature. This stems from the omission of this feature prior to Exchange 2007 s...

Cloud Class Webinars

  1. Avoiding Bugs in Microsoft Access
    Alison Balter takes and in-depth look at avoiding bugs in Access. In this webinar you will learn about using the immediate window to debug your applications, invoking the debugger, using breakpoints to troubleshoot, stepping through code, setting the next statement to execute, ...
  2. Top 10 Best New Features in Visio 2010
    Scott Helmers gives live demonstrations of the top 10 new features in Visio 2010. This webinar will teach you how to create compelling diagrams by adding shapes to the page with a single click, linking the shapes in a diagram to data in Excel (or SQL Server, or SharePoint), ...
  3. IT Consultant Business Secrets Revealed
    Michael Munger, Experts Exchange tech pro and IT consultant, pulls back the curtain on his very successful businesses and answers question on every IT consultant and business owner should know about. He shares secrets on what he did to solve the 5 most common problems in IT, ...
  4. Disaster Recovery and Business Continuity
    Quest CTO, Mike Billon, gives an overview of the steps involved in building a dunamic disaster recovery plan. Through case studies and an examination of software/hardware tooles for monitoring and testing, you'll gain a better understandin of where you are, where you want ...
  5. Organize Your Visio Diagrams with Containers and Lists
    Scott Helmers uses cross functional flowcharts, wireframe diagrams, data graphic legends and seating charts to teach you: how to ustilize all three new structured diagram components in Visio 2010, the best practices for organizeing shapes in previous version of Visio, how to organize ...
  6. How to Us Objects, Properties, Events and Methods in Microsoft Access
    Alison Dalter gives an in-depbth look at objects, properties, events and methods in Microsoft Access. In this webinar you will learn about using the object browser, referring to objects, working with properties and methods, working with object variables, understanding the ...

Join the Community

Give a Little. Get a Lot.

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.

Join the Community

Answers

 

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.

 

by: andreamattPosted on 2008-11-19 at 00:42:41ID: 22992488

Hi CodedK,

I don't find it on Google. Some keywords to find?

Andrea

 

by: andreamattPosted on 2008-11-19 at 00:49:50ID: 22992515

Hi,
I find it. Thanks.

Andrea

 

by: andreamattPosted on 2008-11-19 at 00:53:50ID: 22992536

Hi CodedK,
I have see the software but there is no code for Delphi!
Do you have this code? I only want to know the list of the file that is it possible to recover. No the code to recover the files.

Andrea

 

by: CodedKPosted on 2008-11-19 at 05:11:14ID: 22993758

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.

 

by: andreamattPosted on 2008-11-19 at 05:28:43ID: 22993881

Hi,
I understand the situation.

Thanks.

Someone have a free code?

Andrea

 

by: CodedKPosted on 2008-11-19 at 07:24:01ID: 22994974

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/Windows-File-System-Internals-Developers/dp/1565922492

I'll upload the sources here :
http://www.geocities.com/kalatz_gr_fisher/Undelete.zip

Tell me when you will download it, so i can remove it.

 

by: andreamattPosted on 2008-11-19 at 07:31:52ID: 22995080

Hi,
just download. You can remove it. I see it now.
Thanks,
Andrea

 

by: andreamattPosted on 2008-11-21 at 05:26:01ID: 23012546

Hi,

good code! Thanks.
But is very difficult for me to find or create a procedure-function to have the list of file from a drive. Can you help me?

Andrea


 

by: CodedKPosted on 2008-11-21 at 13:54:49ID: 23017487

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 ;)

  • First of all you need to know the specifications for your file system. In case of NTFS this is not publicly available !!!  The link to the book i post earlier is a very good source though. 
  • Then you can write a program that reads the partition sector by sector and it will be your program that has to analyze the structure according to the specifications, search for the lost data and try to rebuild the file from the raw sectors. There is a component to read file sectors "Raw Disk Access v.1.1" inside Torry site :  http://www.torry.net/quicksearchd.php?String=Raw+Disk+Access&Title=Yes   , (demo app with source included...free), but this is the 1st step only....  :/
     

Do not except some 100 line code. You need to build a driver and some serious low level programming. Your question sounds like "can you give me the code of WindowsXP".
Its just not possible sorry.

If you feel like it, there is the code i gave you so you can study it and all the other info.
Sorry for letting you down. :/
If you think that i might be wrong feel free to wait for other experts to help you :)

 

by: andreamattPosted on 2008-11-24 at 01:53:28ID: 23027201

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?

 

by: andreamattPosted on 2008-11-25 at 01:41:06ID: 23033311

Hi,

Now 500 points!

Please, help me!

Andrea

 

by: rllibbyPosted on 2008-12-09 at 14:28:44ID: 23134511

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/KB/files/NTFSUndelete.aspx
//   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: LONGLONG;
            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(lpDriveInfo: LPDRIVEINFO_ARRAY; var Count: Integer): Integer;

implementation

//// TMFTRecord ////////////////////////////////////////////////////////////////
function TMFTRecord.ReadRaw(n64LCN: LONGLONG; lpData: PByteArray; var n64Len: LONGLONG): Integer;
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:=FBytesPerCluster;
               // 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(ntfsAttr: NTFS_ATTRIBUTE; var lpData: PByteArray; out dwDataLen: DWORD): Integer;
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.Resident.dwLength;
        // Allocate memory for data
        lpData:=AllocMem(dwDataLen);
        // Copy data
        Move(FMFTRecord[dwCurPos + ntfsAttr.Attr.Resident.wAttrOffset], lpData^, dwDataLen);
     end
         else
     begin
            // Non-residence attribute, this resides in the other part of the physical drive
               if (ntfsAttr.Attr.NonResident.n64AllocSize = 0) then
        begin
           ntfsAttr.Attr.NonResident.n64AllocSize:=(ntfsAttr.Attr.NonResident.n64EndVCN - ntfsAttr.Attr.NonResident.n64StartVCN) + 1;
        end;
               // ATTR_STANDARD size may not be correct
               dwDataLen:=ntfsAttr.Attr.NonResident.n64RealSize;
               // Allocate for reading data
               lpData:=AllocMem(ntfsAttr.Attr.NonResident.n64AllocSize);
        // Set pointer
               n64LCN:=0;
        // Set pointer to temp data
               lpTmpBuff:=lpData;
        // Update current position
               Inc(dwCurPos, ntfsAttr.Attr.NonResident.wDatarunOffset);
        // While forever
               while True do
        begin
                     // Read the length of LCN / VCN and length
           chLenOffSz:=FMFTRecord[dwCurPos];
           // 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], n64Len, chLenSz);
           // Increment position
           Inc(dwCurPos, chLenSz);
                     // Read the LCN / VCN offset
                     n64Offset:=0;
           // Copy memory
                     Move(FMFTRecord[dwCurPos], n64Offset, chOffsetSz);
           // Increment position
                     Inc(dwCurPos, chOffsetSz);
           // Cast as byte array
           lpTemp:=PByteArray(@n64Offset);
                     // 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(LONGLONG)) downto chOffsetSz do lpTemp[dwIndex]:=$FF;
           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(lpMFTBuffer: PByteArray; dwLen: DWORD; bExcludeData: Boolean = False): Integer;
var  ntfsMFT:       NTFS_MFT_FILE;
         ntfsAttr:      NTFS_ATTRIBUTE;
     lpTempData:    PByteArray;
     dwTempData:    DWORD;
begin

  // Check params
      if (FMaxMFTRecSize > dwLen) or not(Assigned(lpMFTBuffer)) then
     // Invalid params
     result:=ERROR_INVALID_PARAMETER
  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.szSignature, 'FILE', 4) <> 0) then
        // Not the correct signature
        result:=ERROR_INVALID_PARAMETER
     else
     begin
        // Default result
        result:=ERROR_SUCCESS;
        // Determine if in use
        FInUse:=((ntfsMFT.wFlags and $01) = $01);
        // Set current pos
        FCurPos:=ntfsMFT.wAttribOffset;
        // 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(ntfsAttr, lpTempData, dwTempData);
                 // 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(ntfsAttr, lpTempData, dwTempData);
                 // 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(ntfsAttr, lpTempData, dwTempData);
                    // 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:=dwBytesPerCluster;
  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(SysErrorMessage(ERROR_INVALID_PARAMETER))
  // Params must be non zero, and divisible by 2
  else if (dwRecSize = 0) or ((dwRecSize mod 2) <> 0) then
     // Raise
     raise Exception.Create(SysErrorMessage(ERROR_INVALID_PARAMETER))
  // Params must be non zero, and divisible by 2
  else if (dwBytesPerCluster = 0) or ((dwBytesPerCluster mod 2) <> 0) then
     // Raise
     raise Exception.Create(SysErrorMessage(ERROR_INVALID_PARAMETER));

end;

destructor TMFTRecord.Destroy;
begin

  // Resource protection
  try
     // Cleanup
     Cleanup;
  finally
     // Perform inherited
     inherited Destroy;
  end;

end;

//// TNTFSDrive ////////////////////////////////////////////////////////////////
function TNTFSDrive.GetFileDetail(nFileSeq: DWORD; out stFileInfo: ST_FILEINFO): Integer;
var  mftFile:       TMFTRecord;
begin

  // Check initialized state
      if not(FInitialized) then
     // Return error
            result:=ERROR_INVALID_ACCESS
  // Check for end
  else if ((nFileSeq * FMFTRecordSz + FMFTRecordSz) >= FMFTLen) then
            result:=ERROR_NO_MORE_FILES
  else
  begin
         // Copy the record of the file in the MFT table
     Move(FMFT[nFileSeq * FMFTRecordSz], FMFTRecord^, FMFTRecordSz);
     // Create record reader
     mftFile:=TMFTRecord.Create(FDrive, FStartSector * FBytesPerSector, FMFTRecordSz, FBytesPerCluster);
     // Resource protection
     try
        // Extract the file
            result:=mftFile.ExtractFile(FMFTRecord, FMFTRecordSz, True);
        // Check result
        if (result = ERROR_SUCCESS) then
        begin
           // Clear outbound struct
           FillChar(stFileInfo, SizeOf(ST_FILEINFO), 0);
           // Set index
           stFileInfo.dwIndex:=nFileSeq;
           // Convert filename from widechar to ansi string
           StrPCopy(@stFileInfo.szFileName, WideCharLenToString(@mftFile.FAttrFilename.wFilename, mftFile.FAttrFilename.chFileNameLength));
           // Set attributes
               stFileInfo.dwAttributes:=mftFile.FAttrFilename.dwFlags;
               stFileInfo.n64Create:=mftFile.FAttrStandard.n64Create;
               stFileInfo.n64Modify:=mftFile.FAttrStandard.n64Modify;
               stFileInfo.n64Access:=mftFile.FAttrStandard.n64Access;
           stFileInfo.n64Modfil:=mftFile.FAttrStandard.n64Modfil;
               stFileInfo.n64Size:=mftFile.FAttrFilename.n64Allocated;
               stFileInfo.n64Size:=stFileInfo.n64Size div FBytesPerCluster;
           if (stFileInfo.n64Size = 0) then stFileInfo.n64Size:=1;
               stFileInfo.bDeleted:=not(mftFile.FInUse);
        end;
     finally
        // Free the object
        mftFile.Free;
     end;
  end;

end;

function TNTFSDrive.ReadFile(nFileSeq: DWORD; Stream: TStream): Integer;
var  mftFile:       TMFTRecord;
begin

  // Check initialized state
      if not(FInitialized) then
     // Return error
            result:=ERROR_INVALID_ACCESS
  // Check for end
  else if ((nFileSeq * FMFTRecordSz + FMFTRecordSz) >= FMFTLen) then
            result:=ERROR_NO_MORE_FILES
  // Check stream
  else if (Stream = nil) then
     // Invalid param
     result:=ERROR_INVALID_PARAMETER
  else
  begin
         // Copy the record of the file in the MFT table
     Move(FMFT[nFileSeq * FMFTRecordSz], FMFTRecord^, FMFTRecordSz);
     // Create record reader
     mftFile:=TMFTRecord.Create(FDrive, FStartSector * FBytesPerSector, FMFTRecordSz, FBytesPerCluster);
     // Resource protection
     try
        // Extract the file
            result:=mftFile.ExtractFile(FMFTRecord, FMFTRecordSz, False);
        // Check result
        if (result = ERROR_SUCCESS) then
        begin
           // Write file data to stream
           Stream.Write(mftFile.FFileData^, mftFile.FFileDataSz);
        end;
     finally
        // Free the object
        mftFile.Free;
     end;
  end;

end;

function TNTFSDrive.LoadMFT(nStartCluster: LONGLONG): Integer;
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:=FBytesPerSector * FStartSector;

  // MFT starting point
  n64Pos.QuadPart:=n64Pos.QuadPart + nStartCluster * FBytesPerCluster;

      // 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(FDrive, FMFTRecord^, FMFTRecordSz, dwBytes, nil)) then
        // Failed to read
        result:=GetLastError
     else
     begin
        // Create mft record
        mftRec:=TMFTRecord.Create(FDrive, LONGLONG(FStartSector * FBytesPerSector), FMFTRecordSz, FBytesPerCluster);
        // Resource protection
        try
           // Now extract the MFT record just like the other MFT table records
           result:=mftRec.ExtractFile(FMFTRecord, dwBytes);
           // Check result
           if (result = ERROR_SUCCESS) then
           begin
              // Check mft name
              if not(CompareMem(@mftRec.FAttrFilename.wFilename, @wszMFTName, 8)) then
                 // 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.FFileDataSz);
                 // Set size
                 FMFTLen:=mftRec.FFileDataSz;
                 // 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(lpDriveInfo: DRIVEINFO): Integer;
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(PHYSICAL_DRIVE, GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
     // Check handle
     if (FDrive = INVALID_HANDLE_VALUE) then
        // Failure
        result:=GetLastError
     else
     begin
        // Set starting sector
        FStartSector:=lpDriveInfo.dwNTRelativeSector;
        // Set bytes per sector
        FBytesPerSector:=512;
        // Set start pos
        n64StartPos.QuadPart:=FBytesPerSector * FStartSector;
            // 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(FDrive, lpBootSec, SizeOf(lpBootSec), dwBytes, nil)) then
           // Failure
           result:=GetLastError
        else
        begin
           // Check the buffer for NTFS
           if (StrLComp(@lpBootSec.chOemID, 'NTFS', 4) <> 0) then
              // Invalid drive type
              result:=ERROR_INVALID_DRIVE
           else
           begin
                  // Cluster is the logical entity which is made up of several sectors (a physical entity)
                  FBytesPerCluster:=lpBootSec.bpb.uchSecPerClust * lpBootSec.bpb.wBytesPerSec;
              // Set record size
              FMFTRecordSz:=$01 shl ((-1) * (Byte(lpBootSec.bpb.nClustPerMFTRecord)));
              // Allocate memory for mft record
              FMFTRecord:=AllocMem(FMFTRecordSz);
              // Load the mft table
              result:=LoadMFT(lpBootSec.bpb.n64MFTLogicalClustNum);
           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_VALUE;
  end;

end;

constructor TNTFSDrive.Create;
begin

  // Perform inherited
  inherited Create;

  // Set defaults
  FDrive:=INVALID_HANDLE_VALUE;
  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(lpDriveInfo: LPDRIVEINFO_ARRAY; var Count: Integer): Integer;
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(PHYSICAL_DRIVE, GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);

  // 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(@lpSector[$1BE]);
           // Scan logical partitions
           while (dwIndex < 4) do
           begin
              // Fill in drive info
              lpDrive.wCylinder:=lpPartTbl^.chCylinder;
                     lpDrive.wHead:=lpPartTbl^.chHead;
                     lpDrive.wSector:=lpPartTbl^.chSector;
                     lpDrive.dwNumSectors:=lpPartTbl^.dwNumberSectors;
              // Check for extended partition or boot record
              if ((lpPartTbl^.chType = PART_EXTENDED) or (lpPartTbl^.chType = PART_DOSX13X)) then
              begin
                 lpDrive.wType:=EXTENDED_PART;
                 dwMainPrevRel:=lpPartTbl^.dwRelativeSector;
                           lpDrive.dwNTRelativeSector:=dwMainPrevRel;
              end
              else
              begin
                 lpDrive.wType:=BOOT_RECORD;
                           lpDrive.dwNTRelativeSector:=dwMainPrevRel + lpPartTbl^.dwRelativeSector;
              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]:=lpDrive
              else
                 // Set error result for buffer size
                 result:=ERROR_INSUFFICIENT_BUFFER;
              // 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.dwNTRelativeSector * 512;
                    // 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(@lpSector[$1BE]);
                    // Set indexer
                    dwIndex:=0;
                    // Scan drive info
                    while (dwIndex < 4) do
                    begin
                       // Fill in drive info
                       lpDrive.wCylinder:=lpPartTbl^.chCylinder;
                              lpDrive.wHead:=lpPartTbl^.chHead;
                              lpDrive.wSector:=lpPartTbl^.chSector;
                              lpDrive.dwNumSectors:=lpPartTbl^.dwNumberSectors;
                       lpDrive.dwRelativeSector:=0;
                       // Check for extended partition or boot record
                       if ((lpPartTbl^.chType = PART_EXTENDED) or (lpPartTbl^.chType = PART_DOSX13X)) then
                       begin
                          lpDrive.wType:=EXTENDED_PART;
                          dwPrevRel:=lpPartTbl^.dwRelativeSector;
                                          lpDrive.dwNTRelativeSector:=dwPrevRel + dwMainPrevRel;
                       end
                       else
                       begin
                          lpDrive.wType:=BOOT_RECORD;
                          lpDrive.dwNTRelativeSector:=dwMainPrevRel + dwPrevRel + lpPartTbl^.dwRelativeSector;
                       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]:=lpDrive
                       else
                          // Set error result for buffer size
                          result:=ERROR_INSUFFICIENT_BUFFER;
                       // 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(@lpDrives, dwIndex) = ERROR_SUCCESS) then
  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:\undelete files', nil);
        // Set undelete count
        dwUndelete:=0;
        // While true
        while True do
        begin
           // Get file details
           if not(GetFileDetail(dwIndex, stFileInfo) = ERROR_SUCCESS) then break;
           // Check deleted
           if stFileInfo.bDeleted then
           begin
              try
                 // Create file stream
                 strmFile:=TFileStream.Create('c:\undelete files\' + stFileInfo.szFileName, fmCreate);
                 // 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;

 

by: CodedKPosted on 2008-12-09 at 21:49:20ID: 23136575

Hi Russell. I'm glad to see you :)

 

by: rllibbyPosted on 2008-12-10 at 15:13:25ID: 23144300

@CodedK

Thanks, its good to be seen. Lots of new people in this TA, most don't even know me...

Russell

 

by: andreamattPosted on 2008-12-10 at 15:49:17ID: 23144518

Hi,
Thanks. I look this code in this days. But for the FAT or FAT32?
My request is:
"I am only interested in knowing the list of files that can be recovered completely or partially in a drive"
REMEMBER: the list of file!


Andrea

 

by: rllibbyPosted on 2008-12-10 at 17:33:19ID: 23144996

My reading skills are fine, but you have completely failed to mention if you are trying to recover files on a FAT or NTFS based file system. I gave you code for NTFS, which is obciously not what you want. So good luck with your question.

Russell

 

by: prasidduttaPosted on 2010-03-22 at 02:55:48ID: 28216968

CodedK: I need the source code also. If poosible send an email at dev[at]thebat.net
I would really glad.

20120131-EE-VQP-002

3 Ways to Join

30-Day Free Trial

The Experts

98% positive feedback on 31,087 answers since March 2000. angeliii is a Microsoft Most Valuable Professional for his work with MS SQL Server & Develoment.

He has also proven his knowledge of Visual Basic Programming, PHP Scripting and Oracle Databases.

The Experts

97% positive feedback on 10,752 answers since July 2000. lrmoore has more than 18 years experience in the networking industry.

The six-time Mircosoft MVPs specialties include firewalls, virtual private networking, and network management.

Testimonials

"...and excellent source for support... Kind of like having your very own IT dept." Electriciansnet

Testimonials

"I was apprehensive at signing up at first. However... it has already made my life as an IT administrator much easier." JaCrews

Testimonials

"WOW! You guys have great, active, and knowledgeable people on here." moore50

Business Clients

Business Clients

In the Press

"If you’ve got a question... Experts Exchange can supply an answer.”

In the Press

"...an invaluable aid for both IT professionals and those who require tech support."

In the Press

"where IT professionals provide quick answers on just about any topic"

Business Account Plans

Loading Advertisement...