/// <summary><see cref="http://msdn.microsoft.com/en-us/library/windows/desktop/aa364563(v=vs.85).aspx"/></summary> public IUSN_RECORD[] FileSystemEnumUsnData() { ulong nextUsn = 0; const int chunkSize = 1 * 1024 * 1024; // 1 MB chunks List <IUSN_RECORD> res = new List <IUSN_RECORD>(); using (UnmanagedMemory mem = new UnmanagedMemory(chunkSize)) { do { MFT_ENUM_DATA_V0 input = new MFT_ENUM_DATA_V0(); input.StartFileReferenceNumber = nextUsn; input.LowUsn = long.MinValue; input.HighUsn = long.MaxValue; int errorCode; byte[] data = DeviceIoControlHelper.InvokeIoControl(Handle, IOControlCode.FsctlEnumUsnData, chunkSize, input, out errorCode); Marshal.Copy(data, 0, mem, data.Length); if (errorCode != 0) { // Exit when theres no more to do break; } nextUsn = BitConverter.ToUInt64(data, 0); int dataOffset = 8; while (dataOffset < data.Length) { int length; IUSN_RECORD rec = ParseUsnRecord(mem, dataOffset, out length); if (length <= 0) { break; } res.Add(rec); // Move to next record dataOffset += length; } // Fetch next chunk } while (true); } return(res.ToArray()); }
/// <summary>Returns an enumerable collection of <see cref="UsnEntry"/> entries that meet specified criteria.</summary> /// <param name="filter">The filter.</param> /// <param name="onlyFiles">If gets only the file entries.</param> public IEnumerable <UsnEntry> EnumerateUsnEntries(string filter, bool?onlyFiles) { var usnState = new USN_JOURNAL_DATA_V0(); if (QueryUsnJournal(ref usnState) != (int)UsnJournalReturnCode.USN_JOURNAL_SUCCESS) { throw new Win32Exception("Failed to query the USN journal on the volume."); } // Set up MFT_ENUM_DATA_V0 structure. var mftData = new MFT_ENUM_DATA_V0 { StartFileReferenceNumber = 0, LowUsn = 0, HighUsn = usnState.NextUsn }; var mftDataSize = Marshal.SizeOf(mftData); var mftDataBuffer = Marshal.AllocHGlobal(mftDataSize); Win32Api.ZeroMemory(mftDataBuffer, mftDataSize); Marshal.StructureToPtr(mftData, mftDataBuffer, true); // Set up the data buffer which receives the USN_RECORD data. const int pDataSize = sizeof(ulong) + 10000; var pData = Marshal.AllocHGlobal(pDataSize); Win32Api.ZeroMemory(pData, pDataSize); // Gather up volume's directories. while (Win32Api.DeviceIoControl( _usnJournalRootHandle, Win32Api.FSCTL_ENUM_USN_DATA, mftDataBuffer, mftDataSize, pData, pDataSize, out var outBytesReturned, IntPtr.Zero)) { var pUsnRecord = new IntPtr(pData.ToInt64() + sizeof(long)); // While there is at least one entry in the USN journal. while (outBytesReturned > 60) { var usnEntry = new UsnEntry(pUsnRecord); switch (onlyFiles) { case true when usnEntry.IsFolder: case false when !usnEntry.IsFolder: { pUsnRecord = new IntPtr(pUsnRecord.ToInt64() + usnEntry.RecordLength); outBytesReturned -= usnEntry.RecordLength; continue; } } if (string.IsNullOrWhiteSpace(filter)) { yield return(usnEntry); } else { var options = new GlobOptions { Evaluation = { CaseInsensitive = true } }; var glob = Glob.Parse(filter, options); if (glob.IsMatch(usnEntry.Name.AsSpan())) { yield return(usnEntry); } } pUsnRecord = new IntPtr(pUsnRecord.ToInt64() + usnEntry.RecordLength); outBytesReturned -= usnEntry.RecordLength; } Marshal.WriteInt64(mftDataBuffer, Marshal.ReadInt64(pData, 0)); } Marshal.FreeHGlobal(pData); }