diff --git a/Plugins/Wox.Plugin.FindFile/MFTSearch/MFTSearcher.cs b/Plugins/Wox.Plugin.FindFile/MFTSearch/MFTSearcher.cs index dbc31fdee6..317468e885 100644 --- a/Plugins/Wox.Plugin.FindFile/MFTSearch/MFTSearcher.cs +++ b/Plugins/Wox.Plugin.FindFile/MFTSearch/MFTSearcher.cs @@ -9,6 +9,7 @@ using System.Diagnostics; using System.IO; using System.Linq; using System.Runtime.InteropServices; +using MyEverything; namespace Wox.Infrastructure.MFTSearch { diff --git a/Plugins/Wox.Plugin.FindFile/MFTSearch/MFTSearcherCache.cs b/Plugins/Wox.Plugin.FindFile/MFTSearch/MFTSearcherCache.cs index 72fce782e1..87c04aedde 100644 --- a/Plugins/Wox.Plugin.FindFile/MFTSearch/MFTSearcherCache.cs +++ b/Plugins/Wox.Plugin.FindFile/MFTSearch/MFTSearcherCache.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using MyEverything; namespace Wox.Infrastructure.MFTSearch { diff --git a/Plugins/Wox.Plugin.FindFile/MFTSearch/USNRecord.cs b/Plugins/Wox.Plugin.FindFile/MFTSearch/USNRecord.cs index fe9e85ab30..64c0ee05e7 100644 --- a/Plugins/Wox.Plugin.FindFile/MFTSearch/USNRecord.cs +++ b/Plugins/Wox.Plugin.FindFile/MFTSearch/USNRecord.cs @@ -1,4 +1,5 @@ using System; +using MyEverything; namespace Wox.Infrastructure.MFTSearch { diff --git a/Plugins/Wox.Plugin.FindFile/MFTSearch/VolumeMonitor.cs b/Plugins/Wox.Plugin.FindFile/MFTSearch/VolumeMonitor.cs index 772c307b9e..c65cf866d9 100644 --- a/Plugins/Wox.Plugin.FindFile/MFTSearch/VolumeMonitor.cs +++ b/Plugins/Wox.Plugin.FindFile/MFTSearch/VolumeMonitor.cs @@ -1,158 +1,158 @@ -//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; +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 -// { +namespace MyEverything +{ + internal class VolumeMonitor + { -// public Action RecordAddedEvent; -// public Action RecordDeletedEvent; -// public Action RecordRenameEvent; + public Action RecordAddedEvent; + public Action RecordDeletedEvent; + public Action RecordRenameEvent; -// public void Monitor(List 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 { { "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); + public void Monitor(List 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 { { "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; + // 构建输入参数 + 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) -// { + return rujd; + } + private void MonitorThread(object param) + { -// MFTSearcherCache db = (param as Dictionary)["MFTSearcherCache"] as MFTSearcherCache; -// string volume = (param as Dictionary)["Volume"] as string; -// IntPtr pbuffer = Marshal.AllocHGlobal(0x1000); -// PInvokeWin32.READ_USN_JOURNAL_DATA rujd = SetupInputData4JournalRead(volume, 0xFFFFFFFF); -// UInt32 cbRead; -// IntPtr prujd; + MFTSearcherCache db = (param as Dictionary)["MFTSearcherCache"] as MFTSearcherCache; + string volume = (param as Dictionary)["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); + 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); + 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); + 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; + 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; -// } -// } + 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("--------------------------------------"); + 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); -// } + 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; -// } -// } -//} + private bool MaskEqual(uint target, uint compare) + { + return (target & compare) != 0; + } + } +} diff --git a/Wox.Test/MFTSearcherTest.cs b/Wox.Test/MFTSearcherTest.cs index a496a18ce2..6008788a6d 100644 --- a/Wox.Test/MFTSearcherTest.cs +++ b/Wox.Test/MFTSearcherTest.cs @@ -34,6 +34,7 @@ namespace Wox.Test { long oldWorkingSet = System.Diagnostics.Process.GetCurrentProcess().WorkingSet64; MFTSearcher.IndexAllVolumes(); + GC.Collect(); long newWorkingSet = System.Diagnostics.Process.GetCurrentProcess().WorkingSet64; Console.WriteLine(string.Format("Index: {0}M", (newWorkingSet - oldWorkingSet)/(1024*1024)));