Nice wish, may not happen- but you never know. If the files are on NTFS drives, there's a modification from
Code: Select all
#NoEnv
#SingleInstance, force
SetBatchLines, -1
showprogress := 1
#MaxMem 256
NotepadWaitCount := 0
continueWait := 0
if not A_IsAdmin
{
run *runAs "%A_ScriptFullPath%" ; Requires v1.0.92.01+
ExitApp
}
;MsgBox % RegExMatch("C:\Users\New\AppData\Local\Google\Chrome\User Data\Default\IndexedDB\https_www.greetingcardpoet.com_0.indexeddb.leveldb\000003.log", "i)(.*)local(.*)\.log$")
; i): AHK's "break from tradition": https://www.autohotkey.com/docs/misc/RegEx-QuickRef.htm#Options
inputbox, s, ListMFTfiles, Folder [regex]`n(no spaces in regex), , 300, 140, , , , , % substr(A_WinDir, 1, 2) " US)(.*)\\AppData\\(.*)\\Local\\(.*)(.*)\.log$"
If(ErrorLevel)
ExitApp
t1 := A_TickCount
s := regExReplace(regExReplace(s, "^\s+", ""), "\s+$", "")
i := instr(s, " ", true, 0)
i := (i && FileExist(s)="") ? i : strlen(s) + 1
filelist := ListMFTfiles(regExReplace(substr(s, 1, i-1), "\s$", ""), substr(s, i + 1), "|", showprogress, num, 1000000)
if (!filelist)
{
if (showprogress)
{
SetTimer, WaitForNotepad, Delete
Progress, Off
}
msgbox Nothing found for %s%`nError code: %num%
exitApp
}
if( strlen(filelist)>1250000 )
{
StringReplace, filelist, filelist, |, `n, all
file := fileOpen(A_Temp "\MFTreader file list.txt", "w", "utf-8"), file.Write(filelist), file.close()
Run, notepad "%A_Temp%\MFTreader file list.txt"
Return
}
GuiControl, -Redraw, flChoice
gui, add, listbox, % "R" (num>30 ? 30 : num) " W700 vflChoice gflClick Multi", %filelist%
gui, add, button, default gflRunBtn, &Run
gui, add, button, % x + 10 "gflFolderBtn", &Folder
gui, add, button, % x + 10 "gflSellAllBtn", &Select all
gui, add, button, % x + 10 "gflCopyBtn", &Copy names
gui, add, button, % x + 10 "gflCancel", &Cancel
GuiControl, +Redraw, flChoice
if (showprogress)
{
SetTimer, WaitForNotepad, Delete
Progress, Off
}
gui, show, autosize, % "ListMFTfiles: " num " files in " (A_TickCount-t1) "ms for " s
HotKey, ifWinActive, % "ahk_id " WinExist("A")
HotKey, Enter, flRunBtn
HotKey, ^Enter, flFolderBtn
HotKey, ^a, flSellAllBtn
HotKey, ^c, flCopyBtn
HotKey, ^Ins, flCopyBtn
HotKey, ^Insert, flCopyBtn
HotKey, Escape, flCancel
return
WaitForNotepad:
If (WinExist("MFTreader file list.txt - Notepad"))
{
SetTimer, WaitForNotepad, Delete
if (showProgress)
Progress, Off
exitapp
}
else
{
if (NotepadWaitCount < 35)
{
NotepadWaitCount++
if (!continueWait)
Progress, % 83 + NotepadWaitCount/2
}
else
{
if (filelist)
{
NotepadWaitCount++
if (NotepadWaitCount > 150)
{
if (showProgress)
Progress, Off
msgbox, 8196 , Notepad?, The MFTreader file list in Notepad is not available. Continue Waiting?
IfMsgBox, Yes
{
NotepadWaitCount := 0
continueWait := 1
}
else
{
SetTimer, WaitForNotepad, Delete
exitapp
}
}
}
}
}
Return
#IfWinActive ListMFTfiles ahk_class #32770
flClick:
IfEqual, A_GuiEvent, DoubleClick, goto flRunBtn
return
flRunBtn:
ControlGet, c, Choice, , ListBox1, A
SplitPath, c, fname, fdir
run, %c%, %fdir%, UseErrorLevel
return
flFolderBtn:
ControlGet, c, Choice, , ListBox1, A
run, explorer /select`, "%c%", , UseErrorLevel
return
flSellAllBtn:
PostMessage, LB_SETSEL := 0x185, 1, -1, ListBox1, A
return
flCopyBtn:
gui, submit, nohide
StringReplace, Clipboard, flChoice, |, `n, all
return
^w::
flCancel:
ExitApp
#IfWinActive
; path:
; where to search, drive or fully specified folder, for example C:\folder
; regex:
; search for file names that match regex, only file name is matched, default is none
; delim:
; filelist delimiter, default is newline `n
; showprogress:
; show minimal progressbar in screen center
; num:
; variable that receives number of files returned or error status when trying to obtain:
; -1, -2: root folder handle or info, -3, -4: path handle or info (To be done), -5, Createfile root handle
; -6: Query Journal fail ,-7: volume handle or info, -8: USN journal handle
; plainSearchTimeout: (ms)
; if greater than 0 (default), plain folder enumeration is used for no more than specified time.
;
; RETURN VALUE:
; filelist or empty string if error occured (also see 'num' parameter)
ListMFTfiles(path, regex = "", delim = "`n", showProgress := 0, byref numF = "", plainSearchTimeout := 0)
{
; Fun fact: NTFS max files is 4,294,967,295 (2³² minus 1 file)
;Windows 2000 Change Journal Explained: https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-2000-server/bb742450(v=technet.10)
;Nfts Workings: https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2003/cc781134(v=ws.10)
;=== init
t0 := A_TickCount
drive := substr(path, 1, 2)
path := (substr(path, 0)="\") ? path : path "\"
OPEN_EXISTING := 3
FILE_FLAG_BACKUP_SEMANTICS := 0x2000000
SHARE_RW := 3 ;FILE_SHARE_READ | FILE_SHARE_WRITE
GENERIC_RW := 0xC0000000 ;GENERIC_READ | GENERIC_WRITE
DWORDLONG_SIZE := 8
STATUS_SUCCESS := 1
;=== if path can be enumerated within specified time, return filelist at once
if( plainSearchTimeout>0 )
{
numF := 0
bUsePath := true
VarSetCapacity(filelist, 1000 * 200) ; 1000 filepaths of ~100 widechars
loop, %path%*, 1, 1 ;folders too, with recursion
if(A_TickCount - t0 > plainSearchTimeout)
{
bUsePath := false
break
}
else if(regex = "" || regExMatch(A_LoopFilePath, regex))
{
filelist .= A_LoopFileLongPath delim
numF++
}
if(bUsePath)
{
VarSetCapacity(filelist, -1)
Sort, filelist, D%delim%
return filelist
}
}
;=== get root folder ("\") refnumber
hRoot := dllCall("CreateFile", "wstr", "\\.\" drive "\", "uint", 0, "uint", SHARE_RW, "uint", 0
, "uint", OPEN_EXISTING, "uint", FILE_FLAG_BACKUP_SEMANTICS, "uint", 0)
if(hRoot = -1)
{
numF := -1
return
}
;BY_HANDLE_FILE_INFORMATION
; 0 DWORD dwFileAttributes;
; 4 FILETIME ftCreationTime: DWORD Lodate DWORD Hidate
; 12 FILETIME ftLastAccessTime; DWORD Lodate DWORD HIdate
; 20 FILETIME ftLastWriteTime;
; 28 DWORD dwVolumeSerialNumber;
; 32 DWORD nFileSizeHigh;
; 36 DWORD nFileSizeLow;
; 40 DWORD nNumberOfLinks;
; 44 DWORD nFileIndexHigh;
; 48 DWORD nFileIndexLow;
; See note in DOCs: Windows Server 2012 requires GetFileInformationByHandleEx for hRoot, which is 128 bits on that system.
; Else it will not work on Windows Server 2012 running the Refs filesystem!
VarSetCapacity(fi, 52, 0)
if(dllCall("GetFileInformationByHandle", "uint", hRoot, "uint", &fi) != STATUS_SUCCESS)
{
dllCall("CloseHandle", "uint", hRoot)
numF := -2
return
}
dllCall("CloseHandle", "uint", hRoot)
dirDict := {}
refMax := ((numget(fi, 44)<<32) + numget(fi, 48)) ;nFileIndex: combined Lo Hi to get a 16 digit file identifier of root
; The big one!
dirDict[refMax] := {"name":drive, "parent":"0", "files":{}}
;=== open volume
hJRoot := dllCall("CreateFile", "wstr", "\\.\" drive, "uint", GENERIC_RW, "uint", SHARE_RW, "uint", 0
, "uint", OPEN_EXISTING, "uint", FILE_FLAG_SEQUENTIAL_SCAN := 0x08000000, "uint", 0)
if(hJRoot = -1)
{
numF := -5
return
}
;=== open Update Sequence Number (USN) journal ("not to be confused with NTFS, a journaling file system which uses the NTFS Log ($LogFile) to record metadata changes to the volume")
; Ref https://blog.synsysit.com/smack-your-head-with-usn-journal-everything-you-ever-wanted-to-know-about-this-digital-forensic-artifact/
; Not sure if the following works on pre NTFS 3.0 (introduced on Win2K)
VarSetCapacity(cujd, 16) ;CREATE_USN_JOURNAL_DATA: cujd
numput(0x800000, cujd, 0, "uint64") ;DWORDLONG: MaximumSize: target maximum size that the NTFS file system allocates for the change journal, in bytes
numput(0x100000, cujd, 8, "uint64") ;DWORDLONG: AllocationDelta: size of memory allocation that is added to the end and removed from the beginning of the change journal, in bytes
; FSCTL_* in this function supported in Windows Server 2012 only with a Cluster Shared Volume File System (CsvFS)
; FSCTL_CREATE_USN_JOURNAL requires Admin privileges
; cb receives a null ptr- it seems the documentation wants it there as a dummy.
if(dllCall("DeviceIoControl", "uint", hJRoot, "uint", FSCTL_CREATE_USN_JOURNAL := 0x000900e7, "Ptr", &cujd, "uint", 16, "uint*", 0, "uint", 0, "uint*", cb, "Ptr", 0) != STATUS_SUCCESS)
{
dllCall("CloseHandle", "uint", hJRoot)
numF := -6
return
}
/*
Common errors
ERROR_INVALID_FUNCTION
The specified volume does not support change journals.
ERROR_INVALID_PARAMETER
One or more parameters is invalid, for example, DeviceIoControl returns this error code if the handle supplied is not a volume handle.
ERROR_JOURNAL_DELETE_IN_PROGRESS
An attempt is made to read from, create, delete, or modify the journal while a journal deletion is in process, or an attempt is made to write a USN record while a journal deletion is in process.
*/
;=== estimate overall number of files
;NTFS_VOLUME_DATA_BUFFER
; 0 LARGE_INTEGER (unique) VolumeSerialNumber;
; 8 LARGE_INTEGER NumberSectors;
; 16 LARGE_INTEGER TotalClusters (used and free) ;
; 24 LARGE_INTEGER FreeClusters;
; 32 LARGE_INTEGER TotalReserved;
; 40 DWORD BytesPerSector;
; 44 DWORD BytesPerCluster (cluster factor);
; 48 DWORD BytesPerFileRecordSegment;
; 52 DWORD ClustersPerFileRecordSegment;
; 56 LARGE_INTEGER MftValidDataLength (length of the master file table, in bytes);
; 64 LARGE_INTEGER MftStartLcn (starting kogical cluster number of the master file table);
; 72 LARGE_INTEGER Mft2StartLcn (starting logical cluster number of the master file table mirror);
; 80 LARGE_INTEGER MftZoneStart (starting logical cluster number of the master file table zone);
; 88 LARGE_INTEGER MftZoneEnd (ending logical cluster number of the master file table zone);
VarSetCapacity(voldata, 96, 0)
mftFiles := 0
mftFilesMax := 0
; see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/a5bae3a3-9025-4f07-b70d-e2247b01faa6
; cb a pointer to a variable that receives the size of voldata, in bytes.
if(dllCall("DeviceIoControl", "uint", hJRoot, "uint", FSCTL_GET_NTFS_VOLUME_DATA := 0x00090064, "int*", 0, "uint", 0, "Ptr", &voldata, "uint", 96, "uint*", cb, "Ptr", 0) = STATUS_SUCCESS)
{
if (cb = 96)
if(i := numget(voldata, 48))
mftFilesMax := numget(voldata, 56, "uint64")//i ;MftValidDataLength/BytesPerFileRecordSegment
}
else
{
numF := -7
Return
}
/*
Common errors
STATUS_INVALID_PARAMETER
0xC000000D
The handle specified is not open.
STATUS_VOLUME_DISMOUNTED
0xC000026E
The specified volume is no longer mounted.
STATUS_BUFFER_TOO_SMALL
0xC0000023
*/
;=== USN journal query
;USN_JOURNAL_DATA_V0 returned in object ujd
;USN_JOURNAL_DATA_V1 is not supported before Windows 8 and Windows Server 2012. USN_JOURNAL_DATA_V2 is not supported before Windows 8.1 and Windows Server 2012 R2.
; 0 DWORDLONG UsnJournalID (The NTFS file system uses this current journal identifier for an integrity check)
; 8 USN FirstUsn (number of first record that can be read from the journal)
; 16 USN NextUsn (number of next record to be written to the journal)
; 24 USN LowestValidUsn (First record written into the journal for this journal instance)
; 32 USN MaxUsn (The largest USN that the change journal supports.)
; 40 DWORDLONG MaximumSize (target maximum size for the change journal, in bytes)
; 48 DWORDLONG AllocationDelta (number of bytes of disk memory added to the end and removed from the beginning of the change journal each time memory is allocated or deallocated)
; V1
; 56 WORD MinSupportedMajorVersion (minimum supported version of the USN change journal supported by the filesystem)
; 58 WORD MaxSupportedMajorVersion (maximum supported version of the USN change journal supported by the filesystem)
; V2
; 60 DWORD Flags (A toggle: FLAG_USN_TRACK_MODIFIED_RANGES_ENABLE := 0x00000001 Range tracking is turned on for the volume, 0 otherwise)
; 64 DWORDLONG RangeTrackChunkSize (granularity of tracked ranges, valid when flags above := 1)
; 72 LONGLONG RangeTrackFileSizeThreshold (File size threshold to start tracking range for files with equal or larger size, valid when flags above := 1)
VarSetCapacity(ujd, 56, 0)
; cb a pointer to a variable that receives the size of ujd, in bytes.
if( dllCall("DeviceIoControl", "uint", hJRoot, "uint", FSCTL_QUERY_USN_JOURNAL := 0x000900f4, "uint*", 0, "uint", 0, "Ptr", &ujd, "uint", 56, "uint*", cb, "Ptr", 0) != STATUS_SUCCESS)
{
dllCall("CloseHandle", "uint", hJRoot)
numF := -8
return
}
/*
Common errors
ERROR_INVALID_FUNCTION
The specified volume does not support change journals. Where supported, change journals can also be deleted.
ERROR_INVALID_PARAMETER
One or more parameters is invalid.
For example, DeviceIoControl returns this error code if the handle supplied is not a volume handle.
ERROR_JOURNAL_DELETE_IN_PROGRESS
An attempt is made to read from, create, delete, or modify the journal while a journal deletion is in process, or an attempt is made to write a USN record while a journal deletion is in process.
ERROR_JOURNAL_NOT_ACTIVE
An attempt is made to write a USN record or to read the change journal while the journal is inactive.
*/
JournalMaxSize := numget(ujd, 40, "uint64") + numget(ujd, 48, "uint64") ;MaximumSize + AllocationDelta
JournalChunkSize := 0x100000 ;1MB chunk, ~10-20 read ops for 150k files
if(!mftFilesMax) ; then get an estimate (which might impact performance a little)
mftFilesMax := JournalMaxSize/JournalChunkSize ;
t1 := A_TickCount
if showprogress
Progress, b p0
;=== enumerate USN journal
cb := 0
numF := 0
numD := 0
VarSetCapacity(pData, DWORDLONG_SIZE + JournalChunkSize, 0)
dirDict.SetCapacity(JournalMaxSize//(128 * 50)) ;average file name ~64 widechars, dircount is ~1/50 of filecount. dirDict[refMax] is preserved, of course
;MFT_ENUM_DATA for med.
; 0 DWORDLONG StartFileReferenceNumber (ordinal position within the files on the current volume at which the enumeration is to begin);
; 8 USN LowUsn (lower bounds of range of USN values used to filter which records are returned);
; 16 USN HighUsn(upper bounds of range of USN values used to filter which files are returned);
; V1 (Only for Windows Server 2012)
; 24 WORD MinMajorVersion (minimum supported major version for the USN change journal)
; 26 WORD MaxMajorVersion (maximum supported major version for the USN change journal: 2 or 3 dependent on USN_RECORD_V2 or USN_RECORD_V3)
VarSetCapacity(med, 24, 0)
numput(numget(ujd, 16, "uint64"), med, 16, "uint64") ;med.HighUsn=ujd.NextUsn
; Outer loop is through JournalChunkSize. cb a pointer to a variable that receives the size of med, in bytes.
while(dllCall("DeviceIoControl", "uint", hJRoot, "uint", FSCTL_ENUM_USN_DATA := 0x000900b3, "Ptr", &med, "uint", 24, "Ptr", &pData, "uint", DWORDLONG_SIZE + JournalChunkSize, "uint*", cb, "Ptr", 0))
{
/*
Common errors
ERROR_INVALID_FUNCTION
The file system on the specified volume does not support this control code.
ERROR_INVALID_PARAMETER
One or more parameters is invalid e.g. handle supplied is not a volume handle.
*/
t1a := A_TickCount
if showprogress
Progress, % (mftFiles*82)//mftFilesMax
pUSN := &pData + DWORDLONG_SIZE ; &pData: A pointer to the output buffer that ***receives a USN*** followed by zero or more USN_RECORD_V2 or USN_RECORD_V3 structures so...
; The USN first received may not be the same as the USN in following the USN_RECORD structure. A USN is DWORDLONG.
while(cb>DWORDLONG_SIZE) ;cb decrements by USN.RecordLength as pUSN increments by USN.RecordLength
{
mftFiles++
; USN_RECORD_COMMON_HEADER applies to USN_RECORD_V2, USN_RECORD_V3 and USN_RECORD_V4
; 0 DWORD RecordLength (total length of a record, in bytes);
; 4 WORD MajorVersion (major version number of the change journal software for this record, here it's 3);
; 6 WORD MinorVersion (minor version number of the change journal software for this record);
; USN_RECORD V2 (XP & Server 2003)... (V3 (Win8+ & Win Server 2012) looks like this structure- but FileReferenceNumber & ParentFileReferenceNumber are 128 bit)
; https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/d2a2b53e-bf78-4ef3-90c7-21b918fab304
; 8 DWORDLONG FileReferenceNumber (64 bit ordinal number of the file or directory for which this record notes changes);
; 16 DWORDLONG ParentFileReferenceNumber (64-bit ordinal number of the directory where the file or directory that is associated with this record is located);
; 24 USN Usn (USN of this record);
; 32 LARGE_INTEGER TimeStamp (standard UTC time stamp (FILETIME) of this record, in 64-bit format.);
; 40 DWORD Reason ( flags that identify reasons for changes that have accumulated in this file or directory journal record since the file or directory opened see: https://docs.microsoft.com/en-us/windows/win32/api/winioctl/ns-winioctl-usn_record_v3);
; 44 DWORD SourceInfo (Additional info on the source of the change, set by the FSCTL_MARK_HANDLE of the DeviceIoControl operation);
; 48 DWORD SecurityId (unique security identifier assigned to the file or directory associated with this record);
; 52 DWORD FileAttributes (attributes for the file or directory associated with this record, as returned by the GetFileAttributes);
; 56 WORD FileNameLength (length of the name of the file or directory associated with this record, in bytes);
; 58 WORD FileNameOffset ( offset of the FileName member from the beginning of the structure.);
; 60 WCHAR FileName[1] (name of the file or directory associated with this record in Unicode format. This file or directory name is of variable length);
; USN_RECORD_V4 record is only output when range tracking is turned on. Suitable tor Win8.1+, the structure varies from the above e.g. TimeStamp
fnsize := numget(pUSN + 56, "ushort")
fname := strget(pUSN + 60, fnsize//2, "UTF-16")
isdir := numget(pUSN + 52) & 0x10 ;USN.FileAttributes & FILE_ATTRIBUTE_DIRECTORY
ref := numget(pUSN + 8, "uint64") ;USN.FileReferenceNumber
refparent := numget(pUSN + 16, "uint64") ;USN.ParentFileReferenceNumber
if(isdir)
{
v := dirDict[ref]
if(v = "") ;Not populated yet
{
v := {}
v.files := {}
}
v.setCapacity(4) ;MaxItems: 4th value 'dir' is created later in resolveFolder()
v.setCapacity("name", fnsize), v.name := fname
v.setCapacity("parent", strlen(refparent)), v.parent := refparent
; "Windows computes the file reference number as follows: 48 bits are the index of the file's primary record in the master file table (MFT), and the other 16 bits are a sequence number"
; The following bit shift will fail for nested directories of > Some_To_be_Tested_Value (20 at least). If the bits in a refparent are joined, its length looks to be pretty much the same irrespective of its distance from Root.
;v.setCapacity("parent", strlen(refparent)<<1), v.parent := refparent
dirDict[ref] := v
numD++
}
else
{
if(regex = "" || regExMatch(fname, regex))
{
v := dirDict[refparent]
if(v = "")
{
v := {}
dirDict[refparent] := {"files":v}
}
else
v := v.files
; 3rd value of v
v.SetCapacity(ref, fnsize), v[ref] := fname
numF++
}
}
; Numget: "Do not pass a variable reference if the variable contains the target address; in that case, pass an expression such as MyVar+0"
i := numget(pUSN + 0) ;USN.RecordLength
pUSN += i
cb -= i
}
nextUSN := numget(pData, "uint64")
numput(nextUSN, med, "uint64")
t1b += A_TickCount - t1a
}
dllCall("CloseHandle", "uint", hJRoot)
t2 := A_TickCount
if showprogress
{
Progress, 83
SetTimer, WaitForNotepad, 30
SetTimer, WaitForNotepad, , 2147483647
}
;=== connect files to parent folders & build new cache
VarSetCapacity(filelist, numF*200) ;average full filepath ~100 widechars
bPathFilter := strlen(path) > 3 && instr(FileExist(path), "D")>0
numF := 0
if (bPathFilter)
{
for dk, dv in dirDict
if(dv.files.getCapacity())
{
dir := _ListMFTfiles_resolveFolder(dirDict, dk)
if(instr(dir, path) = 1)
for k, v in dv.files
filelist .= dir v delim, numF++
}
}
else
for dk, dv in dirDict
if(dv.files.getCapacity())
{
dir := _ListMFTfiles_resolveFolder(dirDict, dk)
for k, v in dv.files
filelist .= dir v delim, numF++
}
dirDict=
VarSetCapacity(filelist, -1)
t3:=A_TickCount
;=== sort
Sort, filelist, D%delim%
t4:=A_TickCount
;msgbox % "init`tenum`twinapi`tconnect`tsort`ttotal, ms`n" (t1-t0) "`t" t1b "`t" (t2-t1-t1b) "`t" (t3-t2) "`t" (t4-t3) "`t" (t4-t0) "`n`ndirs:`t" numD "`nfiles:`t" numF
return filelist
}
_ListMFTfiles_resolveFolder(byref dirDict, byref ddref)
{
p := dirDict[ddref], pd := p.dir
if(!pd)
{
pd := (p.parent ? _ListMFTfiles_resolveFolder(dirDict, p.parent) : "") p.name "\"
p.setCapacity("dir", strlen(pd )* 2) ; wchar_t
p.dir := pd
}
return pd
}
: This script somehow magically worked when posted, doesn't appear to any more, with the path in the regex failing. The
has been updated with a better version, however.