public static void PrintUsnEntry(IConsole console, UsnJournal usnJournal, UsnEntry usnEntry) { console.WriteLine(); console.WriteLine($"{"USN:",-20}{usnEntry.USN:X}"); console.WriteLine(usnEntry.IsFolder ? $"{"Directory:",-20}{usnEntry.Name}" : $"{"File:",-20}{usnEntry.Name}"); if (usnJournal.TryGetPathFromFileId(usnEntry.ParentFileReferenceNumber, out var path)) { path = $"{usnJournal.VolumeName.TrimEnd('\\')}{path}"; console.WriteLine($"{"Parent:",-20}{path}"); } if (usnEntry.TimeStamp > 0) { console.WriteLine($"{"Timestamp:",-20}{DateTime.FromFileTimeUtc(usnEntry.TimeStamp).ToLocalTime()}"); } console.WriteLine($"{"File ID:",-20}{usnEntry.FileReferenceNumber:X}"); console.WriteLine($"{"Parent File ID:",-20}{usnEntry.ParentFileReferenceNumber:X}"); var reason = ((UsnReason)usnEntry.Reason).ToString().Replace(',', '|'); console.WriteLine($"{"Reason:",-20}{reason}"); var sourceInfo = ((UsnSource)usnEntry.SourceInfo).ToString().Replace(',', '|'); console.WriteLine($"{"Source Info:",-20}{sourceInfo}"); }
public FileAndDirectoryEntry(UsnEntry usnEntry, string path) { this.fileReferenceNumber = usnEntry.FileReferenceNumber; this.parentFileReferenceNumber = usnEntry.ParentFileReferenceNumber; this.fileName = usnEntry.FileName; this.isFolder = usnEntry.IsFolder; this.path = path; }
public FileAndDirectoryEntry(UsnEntry usnEntry, string path) { this.fileReferenceNumber = usnEntry.FileReferenceNumber; this.parentFileReferenceNumber = usnEntry.ParentFileReferenceNumber; this.fileName = usnEntry.FileName; this.isFolder = usnEntry.IsFolder; this.isHidden = usnEntry.IsHidden; this.isNormal = usnEntry.IsNormal; this.isSys = usnEntry.IsSys; this.path = path; }
public static void PrintEntryPath(IConsole console, UsnJournal usnJournal, UsnEntry usnEntry) { console.WriteLine(); console.WriteLine($"{"Name:",-20}{usnEntry.Name}"); console.WriteLine($"{"IsFolder:",-20}{usnEntry.IsFolder}"); if (usnJournal.TryGetPathFromFileId(usnEntry.ParentFileReferenceNumber, out var path)) { path = $"{usnJournal.VolumeName.TrimEnd('\\')}{path}"; console.WriteLine($"{"Parent:",-20}{path}"); } }
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); }