public UsnJournalReturnCode MonitorUsnJournalEntries(UInt32 reasonMask) { var state = new Win32.USN_JOURNAL_DATA(); if (!IsNtfsVolume) { return UsnJournalReturnCode.VOLUME_NOT_NTFS; } if (_usnJournalRootHandle.ToInt32() == Win32.INVALID_HANDLE_VALUE) { return UsnJournalReturnCode.INVALID_HANDLE_VALUE; } var returnCode = QueryUsnJournal(ref state); if (returnCode != UsnJournalReturnCode.USN_JOURNAL_SUCCESS) { return returnCode; } const int pbDataSize = sizeof (UInt64)*0x4000; IntPtr pbData = Marshal.AllocHGlobal(pbDataSize); Win32.ZeroMemory(pbData, pbDataSize); var rujd = new Win32.READ_USN_JOURNAL_DATA { StartUsn = state.NextUsn, ReasonMask = reasonMask, ReturnOnlyOnClose = 0, Timeout = 1, bytesToWaitFor = 1, UsnJournalId = state.UsnJournalID }; int sizeRujd = Marshal.SizeOf(rujd); IntPtr rujdBuffer = Marshal.AllocHGlobal(sizeRujd); Win32.ZeroMemory(rujdBuffer, sizeRujd); Marshal.StructureToPtr(rujd, rujdBuffer, true); _readMore = true; // Read USN journal entries while (_readMore) { uint bytesReturned; bool returnValue = Win32.DeviceIoControl( _usnJournalRootHandle, Win32.FSCTL_READ_USN_JOURNAL, rujdBuffer, sizeRujd, pbData, pbDataSize, out bytesReturned, IntPtr.Zero); if (!returnValue) { var lastWin32Error = (Win32.GetLastErrorEnum) Marshal.GetLastWin32Error(); Marshal.FreeHGlobal(rujdBuffer); Marshal.FreeHGlobal(pbData); return lastWin32Error == Win32.GetLastErrorEnum.ERROR_HANDLE_EOF ? UsnJournalReturnCode.USN_JOURNAL_SUCCESS : ConvertWin32ErrorToUsnError(lastWin32Error); } var usnEntryPointer = new IntPtr(pbData.ToInt32() + sizeof (UInt64)); // While there are at least one entry in the usn journal // XXX: Why magic number 60? while (bytesReturned > 60) { var usnEntry = new Win32.UsnEntry(usnEntryPointer); OnNewUsnRecord(new NewUsnRecordEventArgs(usnEntry)); usnEntryPointer = new IntPtr(usnEntryPointer.ToInt32() + usnEntry.RecordLength); bytesReturned -= usnEntry.RecordLength; } var nextUsn = Marshal.ReadInt64(pbData, 0); Marshal.WriteInt64(rujdBuffer, nextUsn); } Marshal.FreeHGlobal(rujdBuffer); Marshal.FreeHGlobal(pbData); return returnCode; }
/// <summary> /// GetNtfsVolumeFolders() reads the Master File Table to find all of the folders on a volume /// and returns them in a SortedList<UInt64, Win32.UsnEntry> folders out parameter. /// </summary> /// <param name="folders">A SortedList<string, UInt64> list where string is /// the filename and UInt64 is the parent folder's file reference number /// </param> /// <returns> /// USN_JOURNAL_SUCCESS GetNtfsVolumeFolders() 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 UsnJournalReturnCode GetNtfsVolumeFolders(out List<Win32.UsnEntry> folders) { folders = new List<Win32.UsnEntry>(); var returnCode = UsnJournalReturnCode.VOLUME_NOT_NTFS; if (IsNtfsVolume) { if (_usnJournalRootHandle.ToInt32() != Win32.INVALID_HANDLE_VALUE) { /* returnCode = UsnJournalReturnCode.USN_JOURNAL_SUCCESS; */ var usnState = new Win32.USN_JOURNAL_DATA(); returnCode = QueryUsnJournal(ref usnState); if (returnCode == UsnJournalReturnCode.USN_JOURNAL_SUCCESS) { // // set up MFT_ENUM_DATA structure // Win32.MFT_ENUM_DATA med; med.StartFileReferenceNumber = 0; med.LowUsn = 0; med.HighUsn = usnState.NextUsn; Int32 sizeMftEnumData = Marshal.SizeOf(med); IntPtr medBuffer = Marshal.AllocHGlobal(sizeMftEnumData); Win32.ZeroMemory(medBuffer, sizeMftEnumData); Marshal.StructureToPtr(med, medBuffer, true); // // set up the data buffer which receives the USN_RECORD data // const int pDataSize = sizeof(UInt64) + 10000; IntPtr pData = Marshal.AllocHGlobal(pDataSize); Win32.ZeroMemory(pData, pDataSize); uint outBytesReturned; // // Gather up volume's directories // while (Win32.DeviceIoControl( _usnJournalRootHandle, Win32.FSCTL_ENUM_USN_DATA, medBuffer, sizeMftEnumData, pData, pDataSize, out outBytesReturned, IntPtr.Zero)) { var pUsnRecord = new IntPtr(pData.ToInt32() + sizeof(Int64)); while (outBytesReturned > 60) { var usnEntry = new Win32.UsnEntry(pUsnRecord); // check for directory entries if (usnEntry.IsFolder) { folders.Add(usnEntry); } pUsnRecord = new IntPtr(pUsnRecord.ToInt32() + usnEntry.RecordLength); outBytesReturned -= usnEntry.RecordLength; } Marshal.WriteInt64(medBuffer, Marshal.ReadInt64(pData, 0)); } Marshal.FreeHGlobal(pData); returnCode = ConvertWin32ErrorToUsnError((Win32.GetLastErrorEnum)Marshal.GetLastWin32Error()); if (returnCode == UsnJournalReturnCode.ERROR_HANDLE_EOF) { returnCode = UsnJournalReturnCode.USN_JOURNAL_SUCCESS; } } } else { returnCode = UsnJournalReturnCode.INVALID_HANDLE_VALUE; } } folders.Sort(); return returnCode; }
/// <summary> /// Given a previous state, GetUsnJournalEntries() determines if the USN Journal is active and /// no USN Journal entries have been lost (i.e. USN Journal is valid), then /// it loads a SortedList<UInt64, Win32.UsnEntry> list and returns it as the out parameter 'usnEntries'. /// If GetUsnJournalChanges returns anything but USN_JOURNAL_SUCCESS, the usnEntries list will /// be empty. /// </summary> /// <param name="previousUsnState">The USN Journal state the last time volume /// changes were requested.</param> /// <param name="reasonMask"></param> /// <param name="usnEntries"></param> /// <param name="newUsnState"></param> /// <returns> /// USN_JOURNAL_SUCCESS GetUsnJournalChanges() 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 UsnJournalReturnCode GetUsnJournalEntries(Win32.USN_JOURNAL_DATA previousUsnState, UInt32 reasonMask, out List<Win32.UsnEntry> usnEntries, out Win32.USN_JOURNAL_DATA newUsnState) { usnEntries = new List<Win32.UsnEntry>(); newUsnState = new Win32.USN_JOURNAL_DATA(); UsnJournalReturnCode returnCode = UsnJournalReturnCode.VOLUME_NOT_NTFS; if (IsNtfsVolume) { if (_usnJournalRootHandle.ToInt32() != Win32.INVALID_HANDLE_VALUE) { // get current usn journal state returnCode = QueryUsnJournal(ref newUsnState); if (returnCode == UsnJournalReturnCode.USN_JOURNAL_SUCCESS) { bool bReadMore = true; // sequentially process the usn journal looking for image file entries int pbDataSize = sizeof(UInt64) * 0x4000; IntPtr pbData = Marshal.AllocHGlobal(pbDataSize); Win32.ZeroMemory(pbData, pbDataSize); Win32.READ_USN_JOURNAL_DATA rujd = new Win32.READ_USN_JOURNAL_DATA(); rujd.StartUsn = previousUsnState.NextUsn; rujd.ReasonMask = reasonMask; rujd.ReturnOnlyOnClose = 0; rujd.Timeout = 0; rujd.bytesToWaitFor = 0; rujd.UsnJournalId = previousUsnState.UsnJournalID; int sizeRujd = Marshal.SizeOf(rujd); IntPtr rujdBuffer = Marshal.AllocHGlobal(sizeRujd); Win32.ZeroMemory(rujdBuffer, sizeRujd); Marshal.StructureToPtr(rujd, rujdBuffer, true); // // read usn journal entries // while (bReadMore) { uint outBytesReturned; bool bRtn = Win32.DeviceIoControl( _usnJournalRootHandle, Win32.FSCTL_READ_USN_JOURNAL, rujdBuffer, sizeRujd, pbData, pbDataSize, out outBytesReturned, IntPtr.Zero); if (bRtn) { var pUsnRecord = new IntPtr(pbData.ToInt32() + sizeof(UInt64)); while (outBytesReturned > 60) // while there are at least one entry in the usn journal { var usnEntry = new Win32.UsnEntry(pUsnRecord); if (usnEntry.USN >= newUsnState.NextUsn) // only read until the current usn points beyond the current state's usn { bReadMore = false; break; } usnEntries.Add(usnEntry); pUsnRecord = new IntPtr(pUsnRecord.ToInt32() + usnEntry.RecordLength); outBytesReturned -= usnEntry.RecordLength; } } else { var lastWin32Error = (Win32.GetLastErrorEnum)Marshal.GetLastWin32Error(); if (lastWin32Error == Win32.GetLastErrorEnum.ERROR_HANDLE_EOF) { returnCode = UsnJournalReturnCode.USN_JOURNAL_SUCCESS; } else { returnCode = ConvertWin32ErrorToUsnError(lastWin32Error); } break; } Int64 nextUsn = Marshal.ReadInt64(pbData, 0); if (nextUsn >= newUsnState.NextUsn) { break; } Marshal.WriteInt64(rujdBuffer, nextUsn); } Marshal.FreeHGlobal(rujdBuffer); Marshal.FreeHGlobal(pbData); } } else { returnCode = UsnJournalReturnCode.INVALID_HANDLE_VALUE; } } return returnCode; }
public UsnJournalReturnCode GetFilesMatchingFilter(string filter, out List<Win32.UsnEntry> files) { filter = filter.ToLower(); files = new List<Win32.UsnEntry>(); string[] fileTypes = filter.Split(' ', ',', ';'); if (!IsNtfsVolume) { return UsnJournalReturnCode.VOLUME_NOT_NTFS; } if (_usnJournalRootHandle.ToInt32() == Win32.INVALID_HANDLE_VALUE) { return UsnJournalReturnCode.INVALID_HANDLE_VALUE; } var usnState = new Win32.USN_JOURNAL_DATA(); var returnCode = QueryUsnJournal(ref usnState); if (returnCode != UsnJournalReturnCode.USN_JOURNAL_SUCCESS) { return returnCode; } // set up MFT_ENUM_DATA structure Win32.MFT_ENUM_DATA med; med.StartFileReferenceNumber = 0; med.LowUsn = 0; med.HighUsn = usnState.NextUsn; Int32 sizeMftEnumData = Marshal.SizeOf(med); IntPtr medBuffer = Marshal.AllocHGlobal(sizeMftEnumData); Win32.ZeroMemory(medBuffer, sizeMftEnumData); Marshal.StructureToPtr(med, medBuffer, true); // set up the data buffer which receives the USN_RECORD data const int pDataSize = sizeof (UInt64) + 10000; IntPtr pData = Marshal.AllocHGlobal(pDataSize); Win32.ZeroMemory(pData, pDataSize); uint bytesReturned; // Gather up volume's directories while (Win32.DeviceIoControl( _usnJournalRootHandle, Win32.FSCTL_ENUM_USN_DATA, medBuffer, sizeMftEnumData, pData, pDataSize, out bytesReturned, IntPtr.Zero)) { var usnEntryPointer = new IntPtr(pData.ToInt32() + sizeof (Int64)); while (bytesReturned > 60) { var usnEntry = new Win32.UsnEntry(usnEntryPointer); // check for directory entries if (usnEntry.IsFile) { string extension = Path.GetExtension(usnEntry.Name).ToLower(); if (0 == string.Compare(filter, "*")) { files.Add(usnEntry); } else if (!string.IsNullOrEmpty(extension)) { files.AddRange(from fileType in fileTypes where extension.Contains(fileType) select usnEntry); } } usnEntryPointer = new IntPtr(usnEntryPointer.ToInt32() + usnEntry.RecordLength); bytesReturned -= usnEntry.RecordLength; } Marshal.WriteInt64(medBuffer, Marshal.ReadInt64(pData, 0)); } Marshal.FreeHGlobal(pData); returnCode = ConvertWin32ErrorToUsnError((Win32.GetLastErrorEnum) Marshal.GetLastWin32Error()); if (returnCode == UsnJournalReturnCode.ERROR_HANDLE_EOF) { returnCode = UsnJournalReturnCode.USN_JOURNAL_SUCCESS; } files.Sort(); return returnCode; }