private static void ExampleUsnJournal() { const string drive = @"\\.\C:"; Console.WriteLine(@"## Exmaple on {0} ##", drive); SafeFileHandle hddHandle = CreateFile(drive, FileAccess.Read, FileShare.ReadWrite, IntPtr.Zero, FileMode.Open, FileAttributes.Normal, IntPtr.Zero); if (hddHandle.IsInvalid) { int lastError = Marshal.GetLastWin32Error(); Console.WriteLine(@"!! Invalid {0}; Error ({1}): {2}", drive, lastError, new Win32Exception(lastError).Message); Console.WriteLine(); return; } using (UsnDeviceWrapper usnIo = new UsnDeviceWrapper(hddHandle, true)) { USN_JOURNAL_DATA_V0 data = usnIo.FileSystemQueryUsnJournal(); Console.WriteLine("UsnJournalID: {0:N0}", data.UsnJournalID); Console.WriteLine("FirstUsn #: {0:N0}", data.FirstUsn.Usn); Console.WriteLine("NextUsn #: {0:N0}", data.NextUsn.Usn); Console.WriteLine("LowestValidUsn #: {0:N0}", data.LowestValidUsn.Usn); Console.WriteLine("MaxUsn #: {0:N0}", data.MaxUsn.Usn); Console.WriteLine("MaximumSize: {0:N0}", data.MaximumSize); Console.WriteLine("AllocationDelta: {0:N0}", data.AllocationDelta); } Console.WriteLine(); }
/// <summary> /// DeleteUsnJournal() deletes a USN journal on the volume. If no USN journal exists, this /// function simply returns success. /// </summary> /// <param name="journalState">USN_JOURNAL_DATA object for this volume</param> /// <returns>a UsnJournalReturnCode /// USN_JOURNAL_SUCCESS DeleteUsnJournal() function succeeded. /// VOLUME_NOT_NTFS volume is not an NTFS volume. /// INVALID_HANDLE_VALUE NtfsUsnJournal object failed initialization. /// USN_JOURNAL_NOT_ACTIVE USN journal is not active on volume. /// ERROR_ACCESS_DENIED accessing the USN journal requires admin rights, see remarks. /// ERROR_INVALID_FUNCTION error generated by DeviceIoControl() call. /// ERROR_FILE_NOT_FOUND error generated by DeviceIoControl() call. /// ERROR_PATH_NOT_FOUND error generated by DeviceIoControl() call. /// ERROR_TOO_MANY_OPEN_FILES error generated by DeviceIoControl() call. /// ERROR_INVALID_HANDLE error generated by DeviceIoControl() call. /// ERROR_INVALID_DATA error generated by DeviceIoControl() call. /// ERROR_NOT_SUPPORTED error generated by DeviceIoControl() call. /// ERROR_INVALID_PARAMETER error generated by DeviceIoControl() call. /// ERROR_JOURNAL_DELETE_IN_PROGRESS USN journal delete is in progress. /// ERROR_INVALID_USER_BUFFER error generated by DeviceIoControl() call. /// USN_JOURNAL_ERROR unspecified USN journal error. /// </returns> /// <remarks> /// If function returns ERROR_ACCESS_DENIED you need to run application as an Administrator. /// </remarks> public int DeleteUsnJournal(USN_JOURNAL_DATA_V0 journalState) { var lastError = (int)UsnJournalReturnCode.VOLUME_NOT_NTFS; if (_isNtfsVolume) { if (_usnJournalRootHandle.ToInt64() != Win32Api.INVALID_HANDLE_VALUE) { var dujd = new DELETE_USN_JOURNAL_DATA { UsnJournalID = journalState.UsnJournalID, DeleteFlags = (uint)UsnJournalDeleteFlags.USN_DELETE_FLAG_DELETE }; var sizeDujd = Marshal.SizeOf(dujd); var dujdBuffer = Marshal.AllocHGlobal(sizeDujd); Win32Api.ZeroMemory(dujdBuffer, sizeDujd); Marshal.StructureToPtr(dujd, dujdBuffer, true); Win32Api.DeviceIoControl(_usnJournalRootHandle, Win32Api.FSCTL_DELETE_USN_JOURNAL, dujdBuffer, sizeDujd, IntPtr.Zero, 0, out _, IntPtr.Zero); lastError = Marshal.GetLastWin32Error(); Marshal.FreeHGlobal(dujdBuffer); } else { lastError = (int)UsnJournalReturnCode.INVALID_HANDLE_VALUE; } } return(lastError); }
public static extern bool DeviceIoControl( IntPtr hDevice, uint dwIoControlCode, IntPtr lpInBuffer, int nInBufferSize, out USN_JOURNAL_DATA_V0 lpOutBuffer, int nOutBufferSize, out uint lpBytesReturned, IntPtr lpOverlapped);
#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member internal UsnJournalData(USN_JOURNAL_DATA_V0 data) { UsnJournalID = data.UsnJournalID; FirstUsn = data.FirstUsn; NextUsn = data.NextUsn; LowestValidUsn = data.LowestValidUsn; MaxUsn = data.MaxUsn; MaximumSize = data.MaximumSize; AllocationDelta = data.AllocationDelta; }
private static void PrintUsnJournalState(IConsole console, USN_JOURNAL_DATA_V0 usnData) { console.WriteLine($"{"Journal ID:",-20}{usnData.UsnJournalID:X}"); console.WriteLine($"{"First USN:",-20}{usnData.FirstUsn:X}"); console.WriteLine($"{"Next USN:",-20}{usnData.NextUsn:X}"); console.WriteLine($"{"Lowest Valid USN:",-20}{usnData.LowestValidUsn:X}"); console.WriteLine($"{"Max USN:",-20}{usnData.MaxUsn:X}"); console.WriteLine($"{"Max Size:",-20}{usnData.MaximumSize:X}"); console.WriteLine($"{"Allocation Delta:",-20}{usnData.AllocationDelta:X}"); }
/// <summary>Tests to see if there is a USN journal on this volume and if there is determines whether any journal entries have been lost.</summary> /// <returns>true if the USN journal is active and if the JournalId's are the same /// and if all the USN journal entries expected by the previous state are available /// from the current state. false if not. /// </returns> public bool IsUsnJournalValid(USN_JOURNAL_DATA_V0 usnJournalPreviousState) { var usnJournalState = new USN_JOURNAL_DATA_V0(); var success = _isNtfsVolume && _usnJournalRootHandle.ToInt64() != Win32Api.INVALID_HANDLE_VALUE && QueryUsnJournal(ref usnJournalState) == (int)UsnJournalReturnCode.USN_JOURNAL_SUCCESS && usnJournalPreviousState.UsnJournalID == usnJournalState.UsnJournalID && usnJournalPreviousState.NextUsn >= usnJournalState.NextUsn; return(success); }
/// <summary>GetUsnJournalState() gets the current state of the USN journal if it is active.</summary> /// <param name="usnJournalState"> /// Reference to USN journal data object filled with the current USN journal state. /// </param> /// <param name="elapsedTime">The elapsed time for the GetUsnJournalState() function call.</param> /// <returns> /// USN_JOURNAL_SUCCESS GetUsnJournalState() function succeeded. /// VOLUME_NOT_NTFS volume is not an NTFS volume. /// INVALID_HANDLE_VALUE NtfsUsnJournal object failed initialization. /// USN_JOURNAL_NOT_ACTIVE USN journal is not active on volume. /// ERROR_ACCESS_DENIED accessing the USN journal requires admin rights, see remarks. /// ERROR_INVALID_FUNCTION error generated by DeviceIoControl() call. /// ERROR_FILE_NOT_FOUND error generated by DeviceIoControl() call. /// ERROR_PATH_NOT_FOUND error generated by DeviceIoControl() call. /// ERROR_TOO_MANY_OPEN_FILES error generated by DeviceIoControl() call. /// ERROR_INVALID_HANDLE error generated by DeviceIoControl() call. /// ERROR_INVALID_DATA error generated by DeviceIoControl() call. /// ERROR_NOT_SUPPORTED error generated by DeviceIoControl() call. /// ERROR_INVALID_PARAMETER error generated by DeviceIoControl() call. /// ERROR_JOURNAL_DELETE_IN_PROGRESS USN journal delete is in progress. /// ERROR_INVALID_USER_BUFFER error generated by DeviceIoControl() call. /// USN_JOURNAL_ERROR unspecified USN journal error. /// </returns> /// <remarks> /// If function returns ERROR_ACCESS_DENIED you need to run application as an Administrator. /// </remarks> public int GetUsnJournalState(ref USN_JOURNAL_DATA_V0 usnJournalState) { var lastError = (int)UsnJournalReturnCode.VOLUME_NOT_NTFS; if (_isNtfsVolume) { lastError = _usnJournalRootHandle.ToInt64() == Win32Api.INVALID_HANDLE_VALUE ? (int)UsnJournalReturnCode.INVALID_HANDLE_VALUE : QueryUsnJournal(ref usnJournalState); } return(lastError); }
/// <summary>Tests to see if the USN journal is active on the volume.</summary> /// <returns>true if USN journal is active, false if no USN journal on volume</returns> public bool IsUsnJournalActive() { var success = false; if (_isNtfsVolume) { if (_usnJournalRootHandle.ToInt64() != Win32Api.INVALID_HANDLE_VALUE) { var usnJournalCurrentState = new USN_JOURNAL_DATA_V0(); var lastError = QueryUsnJournal(ref usnJournalCurrentState); if (lastError == (int)UsnJournalReturnCode.USN_JOURNAL_SUCCESS) { success = true; } } } return(success); }
private static void ReadHistoryUsnJournals(IConsole console, UsnJournal journal, ulong usnJournalId, string filter, bool?onlyFiles, CancellationToken token) { var usnReadState = new USN_JOURNAL_DATA_V0 { NextUsn = 0, UsnJournalID = usnJournalId }; var usnEntries = journal.ReadUsnEntries(usnReadState, 0xFFFFFFFF, filter, onlyFiles); foreach (var entry in usnEntries) { if (token.IsCancellationRequested) { break; } PrintUsnEntry(console, journal, entry); } }
/// <summary><see cref="https://msdn.microsoft.com/en-us/library/windows/desktop/aa364586(v=vs.85).aspx"/></summary> public IUSN_RECORD[] FileSystemReadUsnJournal(UsnJournalReasonMask reasonMask, USN firstUsn, int bytesToWaitFor = 0, int timeout = 0) { USN_JOURNAL_DATA_V0 usnQuery = FileSystemQueryUsnJournal(); return(FileSystemReadUsnJournal(usnQuery.UsnJournalID, reasonMask, firstUsn, bytesToWaitFor, timeout)); }
/// <summary><see cref="https://msdn.microsoft.com/en-us/library/windows/desktop/aa364583(v=vs.85).aspx"/></summary> public USN_JOURNAL_DATA_V0 FileSystemQueryUsnJournal() { USN_JOURNAL_DATA_V0 res = DeviceIoControlHelper.InvokeIoControl <USN_JOURNAL_DATA_V0>(Handle, IOControlCode.FsctlQueryUsnJournal); return(res); }
/// <summary>This function queries the USN journal on the volume.</summary> /// <param name="usnJournalState">the USN_JOURNAL_DATA object that is associated with this volume</param> private int QueryUsnJournal(ref USN_JOURNAL_DATA_V0 usnJournalState) { Win32Api.DeviceIoControl(_usnJournalRootHandle, Win32Api.FSCTL_QUERY_USN_JOURNAL, IntPtr.Zero, 0, out usnJournalState, Marshal.SizeOf(usnJournalState), out _, IntPtr.Zero); return(Marshal.GetLastWin32Error()); }
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; } } }
/// <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); }
private void OnExecute() { var console = PhysicalConsole.Singleton; var cts = new CancellationTokenSource(); console.CancelKeyPress += (o, e) => { console.WriteLine("Keyboard interrupt, exiting..."); cts.Cancel(); }; if (!OperatingSystem.IsWindows()) { console.PrintError($"This tool only support Windows OS."); return; } if (!HasAdministratorPrivilege()) { console.PrintError($"You must have system administrator privileges to access the change journal of \"{Volume}\"."); return; } bool?onlyFiles; if (FileOnly) { onlyFiles = true; } else if (DirectoryOnly) { onlyFiles = false; } else { onlyFiles = null; } try { var driveInfo = new DriveInfo(Volume); var journal = new UsnJournal(driveInfo); var usnState = new USN_JOURNAL_DATA_V0(); var retCode = journal.GetUsnJournalState(ref usnState); if (retCode != 0) { console.PrintError($"FSCTL_QUERY_USN_JOURNAL failed with {retCode}"); return; } PrintUsnJournalState(console, usnState); if (Read) { MonitorRealTimeUsnJournal(console, journal, usnState, Filter, onlyFiles, cts.Token); } else if (Search) { SearchMasterFileTable(console, journal, Filter, onlyFiles, cts.Token); } else { ReadHistoryUsnJournals(console, journal, usnState.UsnJournalID, Filter, onlyFiles, cts.Token); } } catch (Exception ex) { console.PrintError(ex.Message); } }
private static void MonitorRealTimeUsnJournal(IConsole console, UsnJournal journal, USN_JOURNAL_DATA_V0 usnState, string filter, bool?onlyFiles, CancellationToken token) { while (true) { if (token.IsCancellationRequested) { return; } var usnEntries = journal.GetUsnJournalEntries(usnState, 0xFFFFFFFF, filter, onlyFiles, out usnState); foreach (var entry in usnEntries) { PrintUsnEntry(console, journal, entry); } } }