mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-06 03:07:04 +02:00
Move MFTSearch to find file plugin.
This commit is contained in:
@@ -1,27 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Wox.Infrastructure.MFTSearch
|
||||
{
|
||||
public class MFTSearchRecord
|
||||
{
|
||||
private USNRecord usn;
|
||||
|
||||
public MFTSearchRecord(USNRecord usn)
|
||||
{
|
||||
this.usn = usn;
|
||||
}
|
||||
|
||||
public string FullPath
|
||||
{
|
||||
get { return usn.FullPath; }
|
||||
}
|
||||
|
||||
public bool IsFolder
|
||||
{
|
||||
get { return usn.IsFolder; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,275 +0,0 @@
|
||||
/*
|
||||
* Thanks to the https://github.com/yiwenshengmei/MyEverything, we can bring MFT search to Wox
|
||||
*
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Wox.Infrastructure.MFTSearch
|
||||
{
|
||||
|
||||
public class MFTSearcher
|
||||
{
|
||||
private static MFTSearcherCache cache = new MFTSearcherCache();
|
||||
|
||||
public static void IndexVolume(string volume)
|
||||
{
|
||||
List<USNRecord> files;
|
||||
List<USNRecord> folders;
|
||||
EnumerateVolume(volume, out files, out folders);
|
||||
cache.AddRecord(volume, files, USNRecordType.File);
|
||||
cache.AddRecord(volume, folders, USNRecordType.Folder);
|
||||
}
|
||||
|
||||
public static void IndexAllVolumes()
|
||||
{
|
||||
foreach (DriveInfo drive in DriveInfo.GetDrives())
|
||||
{
|
||||
IndexVolume(drive.Name.Replace("\\", ""));
|
||||
}
|
||||
}
|
||||
|
||||
public static long IndexedFileCount
|
||||
{
|
||||
get { return cache.FileCount; }
|
||||
}
|
||||
public static long IndexedFolderCount
|
||||
{
|
||||
get { return cache.FolderCount; }
|
||||
}
|
||||
|
||||
public static List<MFTSearchRecord> Search(string item)
|
||||
{
|
||||
if (string.IsNullOrEmpty(item)) return new List<MFTSearchRecord>();
|
||||
|
||||
List<USNRecord> found = cache.FindByName(item);
|
||||
found.ForEach(x => FillPath(x.VolumeName, x, cache));
|
||||
return found.ConvertAll(o => new MFTSearchRecord(o));
|
||||
}
|
||||
|
||||
private static void AddVolumeRootRecord(string volumeName, ref List<USNRecord> folders)
|
||||
{
|
||||
string rightVolumeName = string.Concat("\\\\.\\", volumeName);
|
||||
rightVolumeName = string.Concat(rightVolumeName, Path.DirectorySeparatorChar);
|
||||
IntPtr hRoot = PInvokeWin32.CreateFile(rightVolumeName,
|
||||
0,
|
||||
PInvokeWin32.FILE_SHARE_READ | PInvokeWin32.FILE_SHARE_WRITE,
|
||||
IntPtr.Zero,
|
||||
PInvokeWin32.OPEN_EXISTING,
|
||||
PInvokeWin32.FILE_FLAG_BACKUP_SEMANTICS,
|
||||
IntPtr.Zero);
|
||||
|
||||
if (hRoot.ToInt32() != PInvokeWin32.INVALID_HANDLE_VALUE)
|
||||
{
|
||||
PInvokeWin32.BY_HANDLE_FILE_INFORMATION fi = new PInvokeWin32.BY_HANDLE_FILE_INFORMATION();
|
||||
bool bRtn = PInvokeWin32.GetFileInformationByHandle(hRoot, out fi);
|
||||
if (bRtn)
|
||||
{
|
||||
UInt64 fileIndexHigh = (UInt64)fi.FileIndexHigh;
|
||||
UInt64 indexRoot = (fileIndexHigh << 32) | fi.FileIndexLow;
|
||||
|
||||
folders.Add(new USNRecord
|
||||
{
|
||||
FRN = indexRoot,
|
||||
Name = volumeName,
|
||||
ParentFrn = 0,
|
||||
IsVolumeRoot = true,
|
||||
IsFolder = true,
|
||||
VolumeName = volumeName
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IOException("GetFileInformationbyHandle() returned invalid handle",
|
||||
new Win32Exception(Marshal.GetLastWin32Error()));
|
||||
}
|
||||
PInvokeWin32.CloseHandle(hRoot);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IOException("Unable to get root frn entry", new Win32Exception(Marshal.GetLastWin32Error()));
|
||||
}
|
||||
}
|
||||
private static void EnumerateVolume(string volumeName, out List<USNRecord> files, out List<USNRecord> flds)
|
||||
{
|
||||
files = new List<USNRecord>();
|
||||
flds = new List<USNRecord>();
|
||||
IntPtr medBuffer = IntPtr.Zero;
|
||||
IntPtr pVolume = IntPtr.Zero;
|
||||
try
|
||||
{
|
||||
AddVolumeRootRecord(volumeName, ref flds);
|
||||
pVolume = GetVolumeJournalHandle(volumeName);
|
||||
EnableVomuleJournal(pVolume);
|
||||
|
||||
SetupMFTEnumInBuffer(ref medBuffer, pVolume);
|
||||
EnumerateFiles(volumeName, pVolume, medBuffer, ref files, ref flds);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e.Message, e);
|
||||
Exception innerException = e.InnerException;
|
||||
while (innerException != null)
|
||||
{
|
||||
Console.WriteLine(innerException.Message, innerException);
|
||||
innerException = innerException.InnerException;
|
||||
}
|
||||
throw new ApplicationException("Error in EnumerateVolume()", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (pVolume.ToInt32() != PInvokeWin32.INVALID_HANDLE_VALUE)
|
||||
{
|
||||
PInvokeWin32.CloseHandle(pVolume);
|
||||
if (medBuffer != IntPtr.Zero)
|
||||
{
|
||||
Marshal.FreeHGlobal(medBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
internal static IntPtr GetVolumeJournalHandle(string volumeName)
|
||||
{
|
||||
string vol = string.Concat("\\\\.\\", volumeName);
|
||||
IntPtr pVolume = PInvokeWin32.CreateFile(vol,
|
||||
PInvokeWin32.GENERIC_READ | PInvokeWin32.GENERIC_WRITE,
|
||||
PInvokeWin32.FILE_SHARE_READ | PInvokeWin32.FILE_SHARE_WRITE,
|
||||
IntPtr.Zero,
|
||||
PInvokeWin32.OPEN_EXISTING,
|
||||
0,
|
||||
IntPtr.Zero);
|
||||
if (pVolume.ToInt32() == PInvokeWin32.INVALID_HANDLE_VALUE)
|
||||
{
|
||||
throw new IOException(string.Format("CreateFile(\"{0}\") returned invalid handle", volumeName),
|
||||
new Win32Exception(Marshal.GetLastWin32Error()));
|
||||
}
|
||||
else
|
||||
{
|
||||
return pVolume;
|
||||
}
|
||||
}
|
||||
unsafe private static void EnableVomuleJournal(IntPtr pVolume)
|
||||
{
|
||||
UInt64 MaximumSize = 0x800000;
|
||||
UInt64 AllocationDelta = 0x100000;
|
||||
UInt32 cb;
|
||||
PInvokeWin32.CREATE_USN_JOURNAL_DATA cujd;
|
||||
cujd.MaximumSize = MaximumSize;
|
||||
cujd.AllocationDelta = AllocationDelta;
|
||||
|
||||
int sizeCujd = Marshal.SizeOf(cujd);
|
||||
IntPtr cujdBuffer = Marshal.AllocHGlobal(sizeCujd);
|
||||
PInvokeWin32.ZeroMemory(cujdBuffer, sizeCujd);
|
||||
Marshal.StructureToPtr(cujd, cujdBuffer, true);
|
||||
|
||||
bool fOk = PInvokeWin32.DeviceIoControl(pVolume, PInvokeWin32.FSCTL_CREATE_USN_JOURNAL,
|
||||
cujdBuffer, sizeCujd, IntPtr.Zero, 0, out cb, IntPtr.Zero);
|
||||
if (!fOk)
|
||||
{
|
||||
throw new IOException("DeviceIoControl() returned false", new Win32Exception(Marshal.GetLastWin32Error()));
|
||||
}
|
||||
}
|
||||
unsafe internal static bool QueryUSNJournal(IntPtr pVolume, out PInvokeWin32.USN_JOURNAL_DATA ujd, out uint bytesReturned)
|
||||
{
|
||||
bool bOK = PInvokeWin32.DeviceIoControl(
|
||||
pVolume, PInvokeWin32.FSCTL_QUERY_USN_JOURNAL,
|
||||
IntPtr.Zero,
|
||||
0,
|
||||
out ujd,
|
||||
sizeof(PInvokeWin32.USN_JOURNAL_DATA),
|
||||
out bytesReturned,
|
||||
IntPtr.Zero
|
||||
);
|
||||
return bOK;
|
||||
}
|
||||
unsafe private static void SetupMFTEnumInBuffer(ref IntPtr medBuffer, IntPtr pVolume)
|
||||
{
|
||||
uint bytesReturned = 0;
|
||||
PInvokeWin32.USN_JOURNAL_DATA ujd = new PInvokeWin32.USN_JOURNAL_DATA();
|
||||
|
||||
bool bOk = QueryUSNJournal(pVolume, out ujd, out bytesReturned);
|
||||
if (bOk)
|
||||
{
|
||||
PInvokeWin32.MFT_ENUM_DATA med;
|
||||
med.StartFileReferenceNumber = 0;
|
||||
med.LowUsn = 0;
|
||||
med.HighUsn = ujd.NextUsn;
|
||||
int sizeMftEnumData = Marshal.SizeOf(med);
|
||||
medBuffer = Marshal.AllocHGlobal(sizeMftEnumData);
|
||||
PInvokeWin32.ZeroMemory(medBuffer, sizeMftEnumData);
|
||||
Marshal.StructureToPtr(med, medBuffer, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IOException("DeviceIoControl() returned false", new Win32Exception(Marshal.GetLastWin32Error()));
|
||||
}
|
||||
}
|
||||
unsafe private static void EnumerateFiles(string volumeName, IntPtr pVolume, IntPtr medBuffer, ref List<USNRecord> files, ref List<USNRecord> folders)
|
||||
{
|
||||
IntPtr pData = Marshal.AllocHGlobal(sizeof(UInt64) + 0x10000);
|
||||
PInvokeWin32.ZeroMemory(pData, sizeof(UInt64) + 0x10000);
|
||||
uint outBytesReturned = 0;
|
||||
|
||||
while (false != PInvokeWin32.DeviceIoControl(pVolume, PInvokeWin32.FSCTL_ENUM_USN_DATA, medBuffer,
|
||||
sizeof(PInvokeWin32.MFT_ENUM_DATA), pData, sizeof(UInt64) + 0x10000, out outBytesReturned,
|
||||
IntPtr.Zero))
|
||||
{
|
||||
IntPtr pUsnRecord = new IntPtr(pData.ToInt32() + sizeof(Int64));
|
||||
while (outBytesReturned > 60)
|
||||
{
|
||||
PInvokeWin32.USN_RECORD usn = new PInvokeWin32.USN_RECORD(pUsnRecord);
|
||||
|
||||
if (usn.IsFolder)
|
||||
{
|
||||
folders.Add(new USNRecord
|
||||
{
|
||||
Name = usn.FileName,
|
||||
ParentFrn = usn.ParentFRN,
|
||||
FRN = usn.FRN,
|
||||
IsFolder = true,
|
||||
VolumeName = volumeName
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
files.Add(new USNRecord
|
||||
{
|
||||
Name = usn.FileName,
|
||||
ParentFrn = usn.ParentFRN,
|
||||
FRN = usn.FRN,
|
||||
IsFolder = false,
|
||||
VolumeName = volumeName
|
||||
});
|
||||
}
|
||||
|
||||
pUsnRecord = new IntPtr(pUsnRecord.ToInt32() + usn.RecordLength);
|
||||
outBytesReturned -= usn.RecordLength;
|
||||
}
|
||||
Marshal.WriteInt64(medBuffer, Marshal.ReadInt64(pData, 0));
|
||||
}
|
||||
Marshal.FreeHGlobal(pData);
|
||||
}
|
||||
internal static void FillPath(string volume, USNRecord record, MFTSearcherCache db)
|
||||
{
|
||||
if (record == null) return;
|
||||
var fdSource = db.GetFolderSource(volume);
|
||||
string fullpath = record.Name;
|
||||
FindRecordPath(record, ref fullpath, fdSource);
|
||||
record.FullPath = fullpath;
|
||||
}
|
||||
private static void FindRecordPath(USNRecord curRecord, ref string fullpath, Dictionary<ulong, USNRecord> fdSource)
|
||||
{
|
||||
if (curRecord.IsVolumeRoot) return;
|
||||
USNRecord nextRecord = null;
|
||||
if (!fdSource.TryGetValue(curRecord.ParentFrn, out nextRecord))
|
||||
return;
|
||||
fullpath = string.Format("{0}{1}{2}", nextRecord.Name, Path.DirectorySeparatorChar, fullpath);
|
||||
FindRecordPath(nextRecord, ref fullpath, fdSource);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Wox.Infrastructure.MFTSearch
|
||||
{
|
||||
internal class MFTSearcherCache
|
||||
{
|
||||
private Dictionary<string, Dictionary<ulong, USNRecord>> _volumes_files = new Dictionary<string, Dictionary<ulong, USNRecord>>();
|
||||
private Dictionary<string, Dictionary<ulong, USNRecord>> _volumes_folders = new Dictionary<string, Dictionary<ulong, USNRecord>>();
|
||||
|
||||
public MFTSearcherCache() { }
|
||||
|
||||
public bool ContainsVolume(string volume)
|
||||
{
|
||||
return _volumes_files.ContainsKey(volume) && _volumes_folders.ContainsKey(volume);
|
||||
}
|
||||
public void AddRecord(string volume, List<USNRecord> r, USNRecordType type)
|
||||
{
|
||||
if (type == USNRecordType.File)
|
||||
{
|
||||
CheckHashTableKey(_volumes_files, volume);
|
||||
r.ForEach(x => _volumes_files[volume].Add(x.FRN, x));
|
||||
}
|
||||
else
|
||||
{
|
||||
CheckHashTableKey(_volumes_folders, volume);
|
||||
r.ForEach(x => _volumes_folders[volume].Add(x.FRN, x));
|
||||
}
|
||||
}
|
||||
public void AddRecord(string volume, USNRecord record, USNRecordType type)
|
||||
{
|
||||
if (type == USNRecordType.File)
|
||||
{
|
||||
CheckHashTableKey(_volumes_files, volume);
|
||||
_volumes_files[volume].Add(record.FRN, record);
|
||||
}
|
||||
else
|
||||
{
|
||||
CheckHashTableKey(_volumes_folders, volume);
|
||||
_volumes_folders[volume].Add(record.FRN, record);
|
||||
}
|
||||
}
|
||||
private void CheckHashTableKey(Dictionary<string, Dictionary<ulong, USNRecord>> hashtable, string key)
|
||||
{
|
||||
if (!hashtable.ContainsKey(key))
|
||||
hashtable.Add(key, new Dictionary<ulong, USNRecord>());
|
||||
}
|
||||
public bool DeleteRecord(string volume, ulong frn)
|
||||
{
|
||||
bool result = false;
|
||||
result = DeleteRecordHashTableItem(_volumes_files, volume, frn);
|
||||
if (!result) result = DeleteRecordHashTableItem(_volumes_folders, volume, frn);
|
||||
return result;
|
||||
}
|
||||
private bool DeleteRecordHashTableItem(Dictionary<string, Dictionary<ulong, USNRecord>> hashtable, string volume, ulong frn)
|
||||
{
|
||||
if (hashtable.ContainsKey(volume) && hashtable[volume].ContainsKey(frn))
|
||||
{
|
||||
hashtable[volume].Remove(frn);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public void UpdateRecord(string volume, USNRecord record, USNRecordType type)
|
||||
{
|
||||
if (type == USNRecordType.File)
|
||||
RealUpdateRecord(volume, _volumes_files, record);
|
||||
else
|
||||
RealUpdateRecord(volume, _volumes_folders, record);
|
||||
}
|
||||
private bool RealUpdateRecord(string volume, Dictionary<string, Dictionary<ulong, USNRecord>> source, USNRecord record)
|
||||
{
|
||||
if (source.ContainsKey(volume) && source[volume].ContainsKey(record.FRN))
|
||||
{
|
||||
source[volume][record.FRN] = record;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public List<USNRecord> FindByName(string filename)
|
||||
{
|
||||
filename = filename.ToLower();
|
||||
var fileQuery = from filesInVolumeDic in _volumes_files.Values
|
||||
from eachFilePair in filesInVolumeDic
|
||||
where eachFilePair.Value.Name.ToLower().Contains(filename)
|
||||
select eachFilePair.Value;
|
||||
|
||||
var folderQuery = from fldsInVolumeDic in _volumes_folders.Values
|
||||
from eachFldPair in fldsInVolumeDic
|
||||
where eachFldPair.Value.Name.ToLower().Contains(filename)
|
||||
select eachFldPair.Value;
|
||||
|
||||
List<USNRecord> result = new List<USNRecord>();
|
||||
|
||||
result.AddRange(fileQuery);
|
||||
result.AddRange(folderQuery);
|
||||
|
||||
return result;
|
||||
}
|
||||
public USNRecord FindByFrn(string volume, ulong frn)
|
||||
{
|
||||
if ((!_volumes_files.ContainsKey(volume)) || (!_volumes_folders.ContainsKey(volume)))
|
||||
throw new Exception(string.Format("DB not contain the volume: {0}", volume));
|
||||
USNRecord result = null;
|
||||
_volumes_files[volume].TryGetValue(frn, out result);
|
||||
if (result != null) return result;
|
||||
_volumes_folders[volume].TryGetValue(frn, out result);
|
||||
return result;
|
||||
}
|
||||
public long FileCount
|
||||
{
|
||||
get { return _volumes_files.Sum(x => x.Value.Count); }
|
||||
}
|
||||
public long FolderCount
|
||||
{
|
||||
get { return _volumes_folders.Sum(x => x.Value.Count); }
|
||||
}
|
||||
public Dictionary<ulong, USNRecord> GetFolderSource(string volume)
|
||||
{
|
||||
Dictionary<ulong, USNRecord> result = null;
|
||||
_volumes_folders.TryGetValue(volume, out result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,165 +0,0 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Wox.Infrastructure.MFTSearch {
|
||||
public class PInvokeWin32
|
||||
{
|
||||
|
||||
public const UInt32 GENERIC_READ = 0x80000000;
|
||||
public const UInt32 GENERIC_WRITE = 0x40000000;
|
||||
public const UInt32 FILE_SHARE_READ = 0x00000001;
|
||||
public const UInt32 FILE_SHARE_WRITE = 0x00000002;
|
||||
public const UInt32 FILE_ATTRIBUTE_DIRECTORY = 0x00000010;
|
||||
public const UInt32 OPEN_EXISTING = 3;
|
||||
public const UInt32 FILE_FLAG_BACKUP_SEMANTICS = 0x02000000;
|
||||
public const Int32 INVALID_HANDLE_VALUE = -1;
|
||||
public const UInt32 FSCTL_QUERY_USN_JOURNAL = 0x000900f4;
|
||||
public const UInt32 FSCTL_ENUM_USN_DATA = 0x000900b3;
|
||||
public const UInt32 FSCTL_CREATE_USN_JOURNAL = 0x000900e7;
|
||||
public const UInt32 FSCTL_READ_USN_JOURNAL = 0x000900bb;
|
||||
|
||||
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern IntPtr CreateFile(string lpFileName, uint dwDesiredAccess,
|
||||
uint dwShareMode, IntPtr lpSecurityAttributes,
|
||||
uint dwCreationDisposition, uint dwFlagsAndAttributes,
|
||||
IntPtr hTemplateFile);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool GetFileInformationByHandle(IntPtr hFile,
|
||||
out BY_HANDLE_FILE_INFORMATION lpFileInformation);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool CloseHandle(IntPtr hObject);
|
||||
|
||||
[DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool DeviceIoControl(IntPtr hDevice,
|
||||
UInt32 dwIoControlCode,
|
||||
IntPtr lpInBuffer, Int32 nInBufferSize,
|
||||
out USN_JOURNAL_DATA lpOutBuffer, Int32 nOutBufferSize,
|
||||
out uint lpBytesReturned, IntPtr lpOverlapped);
|
||||
|
||||
[DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool DeviceIoControl(IntPtr hDevice,
|
||||
UInt32 dwIoControlCode,
|
||||
IntPtr lpInBuffer, Int32 nInBufferSize,
|
||||
IntPtr lpOutBuffer, Int32 nOutBufferSize,
|
||||
out uint lpBytesReturned, IntPtr lpOverlapped);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern void ZeroMemory(IntPtr ptr, Int32 size);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct BY_HANDLE_FILE_INFORMATION {
|
||||
public uint FileAttributes;
|
||||
public FILETIME CreationTime;
|
||||
public FILETIME LastAccessTime;
|
||||
public FILETIME LastWriteTime;
|
||||
public uint VolumeSerialNumber;
|
||||
public uint FileSizeHigh;
|
||||
public uint FileSizeLow;
|
||||
public uint NumberOfLinks;
|
||||
public uint FileIndexHigh;
|
||||
public uint FileIndexLow;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct FILETIME {
|
||||
public uint DateTimeLow;
|
||||
public uint DateTimeHigh;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct USN_JOURNAL_DATA {
|
||||
public UInt64 UsnJournalID;
|
||||
public Int64 FirstUsn;
|
||||
public Int64 NextUsn;
|
||||
public Int64 LowestValidUsn;
|
||||
public Int64 MaxUsn;
|
||||
public UInt64 MaximumSize;
|
||||
public UInt64 AllocationDelta;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct MFT_ENUM_DATA {
|
||||
public UInt64 StartFileReferenceNumber;
|
||||
public Int64 LowUsn;
|
||||
public Int64 HighUsn;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct CREATE_USN_JOURNAL_DATA {
|
||||
public UInt64 MaximumSize;
|
||||
public UInt64 AllocationDelta;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct READ_USN_JOURNAL_DATA {
|
||||
public Int64 StartUsn;
|
||||
public UInt32 ReasonMask;
|
||||
public UInt32 ReturnOnlyOnClose;
|
||||
public UInt64 Timeout;
|
||||
public UInt64 BytesToWaitFor;
|
||||
public UInt64 UsnJournalID;
|
||||
}
|
||||
|
||||
public class USN_RECORD {
|
||||
public UInt32 RecordLength;
|
||||
public UInt16 MajorVersion;
|
||||
public UInt16 MinorVersion;
|
||||
public UInt64 FRN; // 8
|
||||
public UInt64 ParentFRN; // 16
|
||||
public Int64 Usn; // Need be care
|
||||
public UInt64 TimeStamp; // Need Be care
|
||||
public UInt32 Reason;
|
||||
public UInt32 SourceInfo;
|
||||
public UInt32 SecurityId;
|
||||
public UInt32 FileAttributes; // 52
|
||||
public UInt16 FileNameLength;
|
||||
public UInt16 FileNameOffset;
|
||||
public string FileName = string.Empty;
|
||||
|
||||
private const int RecordLength_OFFSET = 0;
|
||||
private const int MajorVersion_OFFSET = 4;
|
||||
private const int MinorVersion_OFFSET = 6;
|
||||
private const int FileReferenceNumber_OFFSET = 8;
|
||||
private const int ParentFileReferenceNumber_OFFSET = 16;
|
||||
private const int Usn_OFFSET = 24;
|
||||
private const int TimeStamp_OFFSET = 32;
|
||||
private const int Reason_OFFSET = 40;
|
||||
private const int SourceInfo_OFFSET = 44;
|
||||
private const int SecurityId_OFFSET = 48;
|
||||
private const int FileAttributes_OFFSET = 52;
|
||||
private const int FileNameLength_OFFSET = 56;
|
||||
private const int FileNameOffset_OFFSET = 58;
|
||||
private const int FileName_OFFSET = 60;
|
||||
|
||||
public USN_RECORD(IntPtr p) {
|
||||
this.RecordLength = (UInt32)Marshal.ReadInt32(p, RecordLength_OFFSET);
|
||||
this.MajorVersion = (UInt16)Marshal.ReadInt16(p, MajorVersion_OFFSET);
|
||||
this.MinorVersion = (UInt16)Marshal.ReadInt16(p, MinorVersion_OFFSET);
|
||||
this.FRN = (UInt64)Marshal.ReadInt64(p, FileReferenceNumber_OFFSET);
|
||||
this.ParentFRN = (UInt64)Marshal.ReadInt64(p, ParentFileReferenceNumber_OFFSET);
|
||||
this.Usn = Marshal.ReadInt64(p, Usn_OFFSET);
|
||||
this.TimeStamp = (UInt64)Marshal.ReadInt64(p, TimeStamp_OFFSET);
|
||||
this.Reason = (UInt32)Marshal.ReadInt32(p, Reason_OFFSET);
|
||||
this.SourceInfo = (UInt32)Marshal.ReadInt32(p, SourceInfo_OFFSET);
|
||||
this.SecurityId = (UInt32)Marshal.ReadInt32(p, SecurityId_OFFSET);
|
||||
this.FileAttributes = (UInt32)Marshal.ReadInt32(p, FileAttributes_OFFSET);
|
||||
this.FileNameLength = (UInt16)Marshal.ReadInt16(p, FileNameLength_OFFSET);
|
||||
this.FileNameOffset = (UInt16)Marshal.ReadInt16(p, FileNameOffset_OFFSET);
|
||||
|
||||
this.FileName = Marshal.PtrToStringUni(new IntPtr(p.ToInt32() + this.FileNameOffset), this.FileNameLength / sizeof(char));
|
||||
}
|
||||
|
||||
public bool IsFolder {
|
||||
get { return 0 != (FileAttributes & PInvokeWin32.FILE_ATTRIBUTE_DIRECTORY); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Wox.Infrastructure.MFTSearch
|
||||
{
|
||||
internal class USNChangeReason
|
||||
{
|
||||
public static Dictionary<string, UInt32> USN_REASONS = new Dictionary<string, UInt32> {
|
||||
{"USN_REASON_DATA_OVERWRITE", 0x00000001},
|
||||
{"USN_REASON_DATA_EXTEND", 0x00000002},
|
||||
{"USN_REASON_DATA_TRUNCATION", 0x00000004},
|
||||
{"USN_REASON_NAMED_DATA_OVERWRITE", 0x00000010},
|
||||
{"USN_REASON_NAMED_DATA_EXTEND", 0x00000020},
|
||||
{"USN_REASON_NAMED_DATA_TRUNCATION", 0x00000040},
|
||||
{"USN_REASON_FILE_CREATE", 0x00000100},
|
||||
{"USN_REASON_FILE_DELETE", 0x00000200},
|
||||
{"USN_REASON_EA_CHANGE", 0x00000400},
|
||||
{"USN_REASON_SECURITY_CHANGE", 0x00000800},
|
||||
{"USN_REASON_RENAME_OLD_NAME", 0x00001000},
|
||||
{"USN_REASON_RENAME_NEW_NAME", 0x00002000},
|
||||
{"USN_REASON_INDEXABLE_CHANGE", 0x00004000},
|
||||
{"USN_REASON_BASIC_INFO_CHANGE", 0x00008000},
|
||||
{"USN_REASON_HARD_LINK_CHANGE", 0x00010000},
|
||||
{"USN_REASON_COMPRESSION_CHANGE", 0x00020000},
|
||||
{"USN_REASON_ENCRYPTION_CHANGE", 0x00040000},
|
||||
{"USN_REASON_OBJECT_ID_CHANGE", 0x00080000},
|
||||
{"USN_REASON_REPARSE_POINT_CHANGE", 0x00100000},
|
||||
{"USN_REASON_STREAM_CHANGE", 0x00200000},
|
||||
{"USN_REASON_TRANSACTED_CHANGE", 0x00400000},
|
||||
{"USN_REASON_CLOSE", 0x80000000}
|
||||
};
|
||||
|
||||
public static string ReasonPrettyFormat(UInt32 rsn)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.Append("[");
|
||||
foreach (var rsnPair in USN_REASONS)
|
||||
{
|
||||
if ((rsnPair.Value & rsn) != 0)
|
||||
sb.Append(rsnPair.Key + " ");
|
||||
}
|
||||
sb.Append("]");
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Wox.Infrastructure.MFTSearch
|
||||
{
|
||||
public class USNRecord
|
||||
{
|
||||
|
||||
public string Name { get; set; }
|
||||
public ulong FRN { get; set; }
|
||||
public UInt64 ParentFrn { get; set; }
|
||||
public string FullPath { get; set; }
|
||||
public bool IsVolumeRoot { get; set; }
|
||||
public bool IsFolder { get; set; }
|
||||
public string VolumeName { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.IsNullOrEmpty(FullPath) ? Name : FullPath;
|
||||
}
|
||||
|
||||
public static USNRecord ParseUSN(string volume, PInvokeWin32.USN_RECORD usn)
|
||||
{
|
||||
return new USNRecord
|
||||
{
|
||||
FRN = usn.FRN,
|
||||
Name = usn.FileName,
|
||||
ParentFrn = usn.ParentFRN,
|
||||
IsFolder = usn.IsFolder,
|
||||
VolumeName = volume
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
namespace Wox.Infrastructure.MFTSearch
|
||||
{
|
||||
internal enum USNRecordType
|
||||
{
|
||||
File,
|
||||
Folder
|
||||
}
|
||||
}
|
||||
@@ -1,158 +0,0 @@
|
||||
//using System;
|
||||
//using System.Collections.Generic;
|
||||
//using System.Linq;
|
||||
//using System.Text;
|
||||
//using System.Runtime.InteropServices;
|
||||
//using System.Threading;
|
||||
//using System.Diagnostics;
|
||||
//using System.IO;
|
||||
//using Wox.Infrastructure.MFTSearch;
|
||||
|
||||
//namespace MyEverything
|
||||
//{
|
||||
// internal class VolumeMonitor
|
||||
// {
|
||||
|
||||
// public Action<USNRecord> RecordAddedEvent;
|
||||
// public Action<USNRecord> RecordDeletedEvent;
|
||||
// public Action<USNRecord, USNRecord> RecordRenameEvent;
|
||||
|
||||
// public void Monitor(List<string> volumes, MFTSearcherCache db)
|
||||
// {
|
||||
// foreach (var volume in volumes)
|
||||
// {
|
||||
// if (string.IsNullOrEmpty(volume)) throw new InvalidOperationException("Volume cant't be null or empty string.");
|
||||
// if (!db.ContainsVolume(volume)) throw new InvalidOperationException(string.Format("Volume {0} must be scaned first."));
|
||||
// Thread th = new Thread(new ParameterizedThreadStart(MonitorThread));
|
||||
// th.Start(new Dictionary<string, object> { { "Volume", volume }, { "MFTSearcherCache", db } });
|
||||
// }
|
||||
// }
|
||||
// private PInvokeWin32.READ_USN_JOURNAL_DATA SetupInputData4JournalRead(string volume, uint reason)
|
||||
// {
|
||||
// IntPtr pMonitorVolume = MFTSearcher.GetVolumeJournalHandle(volume);
|
||||
// uint bytesReturned = 0;
|
||||
// PInvokeWin32.USN_JOURNAL_DATA ujd = new PInvokeWin32.USN_JOURNAL_DATA();
|
||||
// Wox.Infrastructure.MFTSearch.MFTSearcher.QueryUSNJournal(pMonitorVolume, out ujd, out bytesReturned);
|
||||
|
||||
// // 构建输入参数
|
||||
// PInvokeWin32.READ_USN_JOURNAL_DATA rujd = new PInvokeWin32.READ_USN_JOURNAL_DATA();
|
||||
// rujd.StartUsn = ujd.NextUsn;
|
||||
// rujd.ReasonMask = reason;
|
||||
// rujd.ReturnOnlyOnClose = 1;
|
||||
// rujd.Timeout = 0;
|
||||
// rujd.BytesToWaitFor = 1;
|
||||
// rujd.UsnJournalID = ujd.UsnJournalID;
|
||||
|
||||
// return rujd;
|
||||
// }
|
||||
// private void MonitorThread(object param)
|
||||
// {
|
||||
|
||||
// MFTSearcherCache db = (param as Dictionary<string, object>)["MFTSearcherCache"] as MFTSearcherCache;
|
||||
// string volume = (param as Dictionary<string, object>)["Volume"] as string;
|
||||
// IntPtr pbuffer = Marshal.AllocHGlobal(0x1000);
|
||||
// PInvokeWin32.READ_USN_JOURNAL_DATA rujd = SetupInputData4JournalRead(volume, 0xFFFFFFFF);
|
||||
// UInt32 cbRead;
|
||||
// IntPtr prujd;
|
||||
|
||||
// while (true)
|
||||
// {
|
||||
// prujd = Marshal.AllocHGlobal(Marshal.SizeOf(rujd));
|
||||
// PInvokeWin32.ZeroMemory(prujd, Marshal.SizeOf(rujd));
|
||||
// Marshal.StructureToPtr(rujd, prujd, true);
|
||||
|
||||
// Debug.WriteLine(string.Format("\nMoniting on {0}......", volume));
|
||||
// IntPtr pVolume = Wox.Infrastructure.MFTSearch.MFTSearcher.GetVolumeJournalHandle(volume);
|
||||
|
||||
// bool fok = PInvokeWin32.DeviceIoControl(pVolume,
|
||||
// PInvokeWin32.FSCTL_READ_USN_JOURNAL,
|
||||
// prujd, Marshal.SizeOf(typeof(PInvokeWin32.READ_USN_JOURNAL_DATA)),
|
||||
// pbuffer, 0x1000, out cbRead, IntPtr.Zero);
|
||||
|
||||
// IntPtr pRealData = new IntPtr(pbuffer.ToInt32() + Marshal.SizeOf(typeof(Int64)));
|
||||
// uint offset = 0;
|
||||
|
||||
// if (fok)
|
||||
// {
|
||||
// while (offset + Marshal.SizeOf(typeof(Int64)) < cbRead)
|
||||
// {
|
||||
// PInvokeWin32.USN_RECORD usn = new PInvokeWin32.USN_RECORD(new IntPtr(pRealData.ToInt32() + (int)offset));
|
||||
// ProcessUSN(usn, volume, db);
|
||||
// offset += usn.RecordLength;
|
||||
// }
|
||||
// }
|
||||
|
||||
// Marshal.FreeHGlobal(prujd);
|
||||
// rujd.StartUsn = Marshal.ReadInt64(pbuffer);
|
||||
// }
|
||||
// }
|
||||
// private void ProcessUSN(PInvokeWin32.USN_RECORD usn, string volume, MFTSearcherCache db)
|
||||
// {
|
||||
// var dbCached = db.FindByFrn(volume, usn.FRN);
|
||||
// Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, dbCached, db);
|
||||
// Debug.WriteLine(string.Format("------USN[frn={0}]------", usn.FRN));
|
||||
// Debug.WriteLine(string.Format("FileName={0}, USNChangeReason={1}", usn.FileName, USNChangeReason.ReasonPrettyFormat(usn.Reason)));
|
||||
// Debug.WriteLine(string.Format("FileName[Cached]={0}", dbCached == null ? "NoCache" : dbCached.FullPath));
|
||||
// Debug.WriteLine("--------------------------------------");
|
||||
|
||||
// if (MaskEqual(usn.Reason, USNChangeReason.USN_REASONS["USN_REASON_RENAME_NEW_NAME"]))
|
||||
// ProcessRenameNewName(usn, volume, db);
|
||||
// if ((usn.Reason & USNChangeReason.USN_REASONS["USN_REASON_FILE_CREATE"]) != 0)
|
||||
// ProcessFileCreate(usn, volume, db);
|
||||
// if (MaskEqual(usn.Reason, USNChangeReason.USN_REASONS["USN_REASON_FILE_DELETE"]))
|
||||
// ProcessFileDelete(usn, volume, db);
|
||||
// }
|
||||
// private void ProcessFileDelete(PInvokeWin32.USN_RECORD usn, string volume, MFTSearcherCache db)
|
||||
// {
|
||||
// var cached = db.FindByFrn(volume, usn.FRN);
|
||||
// if (cached == null)
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, cached, db);
|
||||
// var deleteok = db.DeleteRecord(volume, usn.FRN);
|
||||
// Debug.WriteLine(string.Format(">>>> File {0} deleted {1}.", cached.FullPath, deleteok ? "successful" : "fail"));
|
||||
// if (RecordDeletedEvent != null)
|
||||
// RecordDeletedEvent(cached);
|
||||
// }
|
||||
// }
|
||||
// private void ProcessRenameNewName(PInvokeWin32.USN_RECORD usn, string volume, MFTSearcherCache db)
|
||||
// {
|
||||
// USNRecord newRecord = USNRecord.ParseUSN(volume, usn);
|
||||
// //string fullpath = newRecord.Name;
|
||||
// //db.FindRecordPath(newRecord, ref fullpath, db.GetFolderSource(volume));
|
||||
// //newRecord.FullPath = fullpath;
|
||||
// var oldRecord = db.FindByFrn(volume, usn.FRN);
|
||||
// Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, oldRecord, db);
|
||||
// Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, newRecord, db);
|
||||
// Debug.WriteLine(string.Format(">>>> RenameFile {0} to {1}", oldRecord.FullPath, newRecord.FullPath));
|
||||
// db.UpdateRecord(volume, newRecord,
|
||||
// usn.IsFolder ? USNRecordType.Folder : USNRecordType.File);
|
||||
// if (RecordRenameEvent != null) RecordRenameEvent(oldRecord, newRecord);
|
||||
// if (newRecord.FullPath.Contains("$RECYCLE.BIN"))
|
||||
// {
|
||||
// Debug.WriteLine(string.Format(">>>> Means {0} moved to recycle.", oldRecord.FullPath));
|
||||
// }
|
||||
// }
|
||||
// private void ProcessFileCreate(PInvokeWin32.USN_RECORD usn, string volume, MFTSearcherCache db)
|
||||
// {
|
||||
// USNRecord record = USNRecord.ParseUSN(volume, usn);
|
||||
// //string fullpath = record.Name;
|
||||
// //db.FindRecordPath(record, ref fullpath, db.GetFolderSource(volume));
|
||||
// //record.FullPath = fullpath;
|
||||
// db.AddRecord(volume, record, usn.IsFolder ? USNRecordType.Folder : USNRecordType.File);
|
||||
// Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, record, db);
|
||||
// Debug.WriteLine(string.Format(">>>> NewFile: {0}", record.FullPath));
|
||||
// if (RecordAddedEvent != null)
|
||||
// RecordAddedEvent(record);
|
||||
// }
|
||||
|
||||
|
||||
// private bool MaskEqual(uint target, uint compare)
|
||||
// {
|
||||
// return (target & compare) != 0;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
@@ -31,7 +31,7 @@
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="log4net, Version=1.2.13.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
|
||||
@@ -57,14 +57,6 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Logger\Log.cs" />
|
||||
<Compile Include="MFTSearch\MFTSearcher.cs" />
|
||||
<Compile Include="MFTSearch\MFTSearcherCache.cs" />
|
||||
<Compile Include="MFTSearch\MFTSearchRecord.cs" />
|
||||
<Compile Include="MFTSearch\USNRecord.cs" />
|
||||
<Compile Include="MFTSearch\USNRecordType.cs" />
|
||||
<Compile Include="MFTSearch\PInvokeWin32.cs" />
|
||||
<Compile Include="MFTSearch\USNChangeReason.cs" />
|
||||
<Compile Include="MFTSearch\VolumeMonitor.cs" />
|
||||
<Compile Include="PeHeaderReader.cs" />
|
||||
<Compile Include="Storage\UserSettings\CustomizedPluginConfig.cs" />
|
||||
<Compile Include="Storage\UserSettings\FolderLink.cs" />
|
||||
|
||||
Reference in New Issue
Block a user