public static extern bool DeviceIoControl( SafeFileHandle hDevice, FsCtl IoControlCode, [In] READ_USN_JOURNAL_DATA_V0 InBuffer, uint nInBufferSize, [In] IntPtr OutBuffer, uint nOutBufferSize, ref uint pBytesReturned, [In] IntPtr overlapped //[In] ref System.Threading.NativeOverlapped Overlapped );
private bool Read() { const int CurrentUSNLength = sizeof(long); var readData = new READ_USN_JOURNAL_DATA_V0 { StartUsn = _currentUSN, ReasonMask = Options.ReasonFilter, UsnJournalID = ChangeJournal.Data.ID, ReturnOnlyOnClose = Options.ReturnOnlyOnClose ? (uint)1 : 0, Timeout = (ulong)Options.Timeout.TotalSeconds, }; var handle = ChangeJournal.ChangeJournalHandle; var entryData = Win32DeviceControl.ControlWithInput(handle, Win32ControlCode.ReadUsnJournal, ref readData, BufferSize); if (entryData.Length > CurrentUSNLength) // There are more data than just data currentUSN. { var bufferHandle = GCHandle.Alloc(entryData, GCHandleType.Pinned); var bufferPointer = bufferHandle.AddrOfPinnedObject(); _currentUSN = Marshal.ReadInt64(entryData, 0); // Enumerate entries _entries.Clear(); var offset = CurrentUSNLength; // Skip currentUSN field while (offset < entryData.Length) { var entry = GetBufferedEntry(bufferPointer, offset); offset += entry.Length; _entries.Add(entry); } bufferHandle.Free(); _currentIndex = 0; return(true); } else { _eof = true; return(false); } }
/// <summary><see cref="https://msdn.microsoft.com/en-us/library/windows/desktop/aa364586(v=vs.85).aspx"/></summary> public IUSN_RECORD[] FileSystemReadUsnJournal(long volumeJournalId, UsnJournalReasonMask reasonMask, USN firstUsn, int bytesToWaitFor = 0, int timeout = 0) { READ_USN_JOURNAL_DATA_V0 input = new READ_USN_JOURNAL_DATA_V0(); input.StartUsn = firstUsn; input.UsnJournalId = volumeJournalId; input.ReasonMask = reasonMask; input.BytesToWaitFor = bytesToWaitFor; input.Timeout = timeout; int errorCode; byte[] data = DeviceIoControlHelper.InvokeIoControl(Handle, IOControlCode.FsctlReadUsnJournal, 1024 * 1024, input, out errorCode); List <IUSN_RECORD> res = new List <IUSN_RECORD>(); using (UnmanagedMemory mem = new UnmanagedMemory(data)) { 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; } } return(res.ToArray()); }
public IEnumerable <UsnEntry> ReadUsnEntries(USN_JOURNAL_DATA_V0 previousUsnState, uint reasonMask, string filter, bool?onlyFiles) { var newUsnState = new USN_JOURNAL_DATA_V0(); var lastError = (int)UsnJournalReturnCode.VOLUME_NOT_NTFS; if (_isNtfsVolume) { if (_usnJournalRootHandle.ToInt64() != Win32Api.INVALID_HANDLE_VALUE) { // Get current USN journal state. lastError = QueryUsnJournal(ref newUsnState); if (lastError == (int)UsnJournalReturnCode.USN_JOURNAL_SUCCESS) { var bReadMore = true; // Sequentially process the USN journal looking for image file entries. const int pbDataSize = sizeof(ulong) * 16384; var pbData = Marshal.AllocHGlobal(pbDataSize); Win32Api.ZeroMemory(pbData, pbDataSize); var rujd = new READ_USN_JOURNAL_DATA_V0 { StartUsn = (ulong)previousUsnState.NextUsn, ReasonMask = reasonMask, ReturnOnlyOnClose = 0, Timeout = 0, BytesToWaitFor = 0, UsnJournalId = previousUsnState.UsnJournalID }; var sizeRujd = Marshal.SizeOf(rujd); var rujdBuffer = Marshal.AllocHGlobal(sizeRujd); Win32Api.ZeroMemory(rujdBuffer, sizeRujd); Marshal.StructureToPtr(rujd, rujdBuffer, true); // Read USN journal entries. while (bReadMore) { var bRtn = Win32Api.DeviceIoControl(_usnJournalRootHandle, Win32Api.FSCTL_READ_USN_JOURNAL, rujdBuffer, sizeRujd, pbData, pbDataSize, out var outBytesReturned, IntPtr.Zero); if (bRtn) { var pUsnRecord = new IntPtr(pbData.ToInt64() + sizeof(ulong)); // While there is at least one entry in the USN journal. while (outBytesReturned > 60) { var usnEntry = new UsnEntry(pUsnRecord); // Only read until the current usn points beyond the current state's USN. if (usnEntry.USN >= newUsnState.NextUsn) { bReadMore = false; break; } 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; } } else { var lastWin32Error = Marshal.GetLastWin32Error(); if (lastWin32Error == (int)Win32Errors.ERROR_HANDLE_EOF) { lastError = (int)UsnJournalReturnCode.USN_JOURNAL_SUCCESS; } break; } var nextUsn = Marshal.ReadInt64(pbData, 0); if (nextUsn >= newUsnState.NextUsn) { break; } Marshal.WriteInt64(rujdBuffer, nextUsn); } Marshal.FreeHGlobal(rujdBuffer); Marshal.FreeHGlobal(pbData); } } else { lastError = (int)UsnJournalReturnCode.INVALID_HANDLE_VALUE; } } }