private void QueryUsnJournal_Click(object sender, RoutedEventArgs e)
        {
            e.Handled = true;

            _usnEntryDetail.Visibility = Visibility.Hidden;
            resultsLb.ItemsSource      = null;
            resultsLb.Items.Clear();

            var journalState = new Win32Api.USN_JOURNAL_DATA_V0();
            var rtn          = Journal.GetUsnJournalState(ref journalState);

            FunctionElapsedTime.Content = string.Format(CultureInfo.InvariantCulture, "Query->{0} duration: {1} (ms)", "GetUsnJournalState", NtfsUsnJournal.ElapsedTime.TotalMilliseconds);

            if (rtn == (int)NtfsUsnJournal.UsnJournalReturnCode.USN_JOURNAL_SUCCESS)
            {
                var lbItem = new ListBoxItem
                {
                    Foreground = Brushes.Black,
                    Content    = FormatUsnJournalState(journalState)
                };

                resultsLb.Items.Add(lbItem);
            }

            else
            {
                var lbItem = new ListBoxItem
                {
                    Content    = string.Format(CultureInfo.InvariantCulture, "Query->{0} returned error code: {1}", "GetUsnJournalState", rtn),
                    Foreground = Brushes.Red
                };

                resultsLb.Items.Add(lbItem);
            }
        }
        /// <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;

            var sw = new Stopwatch();

            sw.Start();

            if (bNtfsVolume)
            {
                if (_usnJournalRootHandle.ToInt64() != Win32Api.INVALID_HANDLE_VALUE)
                {
                    var usnJournalCurrentState = new Win32Api.USN_JOURNAL_DATA_V0();
                    var lastError = QueryUsnJournal(ref usnJournalCurrentState);

                    if (lastError == (int)UsnJournalReturnCode.USN_JOURNAL_SUCCESS)
                    {
                        success = true;
                    }
                }
            }

            ElapsedTime = TimeSpan.FromMilliseconds(sw.ElapsedMilliseconds);

            return(success);
        }
        /// <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 Win32Api.USN_JOURNAL_DATA_V0 usnJournalState)
        {
            uint cb;

            Win32Api.DeviceIoControl(_usnJournalRootHandle, Win32Api.FSCTL_QUERY_USN_JOURNAL, IntPtr.Zero, 0, out usnJournalState, Marshal.SizeOf(usnJournalState), out cb, IntPtr.Zero);

            return(Marshal.GetLastWin32Error());
        }
        private static string FormatUsnJournalState(Win32Api.USN_JOURNAL_DATA_V0 _usnCurrentJournalState)
        {
            var sb = new StringBuilder();

            sb.AppendLine(string.Format(CultureInfo.InvariantCulture, "Journal ID: {0}", _usnCurrentJournalState.UsnJournalID.ToString("X", CultureInfo.InvariantCulture)));
            sb.AppendLine(string.Format(CultureInfo.InvariantCulture, " First USN: {0}", _usnCurrentJournalState.FirstUsn.ToString("X", CultureInfo.InvariantCulture)));
            sb.AppendLine(string.Format(CultureInfo.InvariantCulture, "  Next USN: {0}", _usnCurrentJournalState.NextUsn.ToString("X", CultureInfo.InvariantCulture)));
            sb.AppendLine();
            sb.AppendLine(string.Format(CultureInfo.InvariantCulture, "Lowest Valid USN: {0}", _usnCurrentJournalState.LowestValidUsn.ToString("X", CultureInfo.InvariantCulture)));
            sb.AppendLine(string.Format(CultureInfo.InvariantCulture, "         Max USN: {0}", _usnCurrentJournalState.MaxUsn.ToString("X", CultureInfo.InvariantCulture)));
            sb.AppendLine(string.Format(CultureInfo.InvariantCulture, "        Max Size: {0}", _usnCurrentJournalState.MaximumSize.ToString("X", CultureInfo.InvariantCulture)));
            sb.AppendLine(string.Format(CultureInfo.InvariantCulture, "Allocation Delta: {0}", _usnCurrentJournalState.AllocationDelta.ToString("X", CultureInfo.InvariantCulture)));

            return(sb.ToString());
        }
        private void FillListBoxWithUsnEntries(NtfsUsnJournal.UsnJournalReturnCode rtnCode, List <Win32Api.UsnEntry> usnEntries, Win32Api.USN_JOURNAL_DATA_V0 newUsnState)
        {
            FunctionElapsedTime.Content = string.Format(CultureInfo.InvariantCulture, "'View Changes'->{0} duration: {1} (ms)", "GetUsnJournalEntries", NtfsUsnJournal.ElapsedTime.TotalMilliseconds);

            if (rtnCode == NtfsUsnJournal.UsnJournalReturnCode.USN_JOURNAL_SUCCESS)
            {
                if (usnEntries.Count > 0)
                {
                    _entryDetail          = UsnEntryDetail.EntryDetail.UsnEntry;
                    resultsLb.ItemsSource = usnEntries;

                    var updateUsnStateDlg = new UpdateUsnStateDialog(this)
                    {
                        Owner = this
                    };

                    var bRtn = updateUsnStateDlg.ShowDialog();
                    if (bRtn != null && bRtn.Value)
                    {
                        _usnCurrentJournalState = newUsnState;
                    }
                }

                else
                {
                    var lbItem = new ListBoxItem
                    {
                        Content    = "\'View Changes\'-> No Journal entries found",
                        Foreground = Brushes.Red
                    };

                    resultsLb.Items.Add(lbItem);
                }
            }

            else
            {
                var lbItem = new ListBoxItem
                {
                    Content    = string.Format(CultureInfo.InvariantCulture, "'View Changes'->{0} returned error code: {1}", "GetUsnJournalEntries", rtnCode),
                    Foreground = Brushes.Red
                };

                resultsLb.Items.Add(lbItem);
            }

            Cursor = Cursors.Arrow;
        }
        /// <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(Win32Api.USN_JOURNAL_DATA_V0 usnJournalPreviousState)
        {
            var usnJournalState = new Win32Api.USN_JOURNAL_DATA_V0();

            var sw = new Stopwatch();

            sw.Start();

            var success = bNtfsVolume && _usnJournalRootHandle.ToInt64() != Win32Api.INVALID_HANDLE_VALUE &&
                          QueryUsnJournal(ref usnJournalState) == (int)UsnJournalReturnCode.USN_JOURNAL_SUCCESS &&
                          usnJournalPreviousState.UsnJournalID == usnJournalState.UsnJournalID &&
                          usnJournalPreviousState.NextUsn >= usnJournalState.NextUsn;

            ElapsedTime = TimeSpan.FromMilliseconds(sw.ElapsedMilliseconds);

            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 Win32Api.USN_JOURNAL_DATA_V0 usnJournalState)
        {
            var lastError = (int)UsnJournalReturnCode.VOLUME_NOT_NTFS;

            var sw = new Stopwatch();

            sw.Start();

            if (bNtfsVolume)
            {
                lastError = _usnJournalRootHandle.ToInt64() == Win32Api.INVALID_HANDLE_VALUE
               ? (int)UsnJournalReturnCode.INVALID_HANDLE_VALUE
               : QueryUsnJournal(ref usnJournalState);
            }

            ElapsedTime = TimeSpan.FromMilliseconds(sw.ElapsedMilliseconds);

            return(lastError);
        }
        /// <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(Win32Api.USN_JOURNAL_DATA_V0 journalState)
        {
            var lastError = (int)UsnJournalReturnCode.VOLUME_NOT_NTFS;

            var sw = new Stopwatch();

            sw.Start();

            if (bNtfsVolume)
            {
                if (_usnJournalRootHandle.ToInt64() != Win32Api.INVALID_HANDLE_VALUE)
                {
                    uint cb;

                    var dujd = new Win32Api.DELETE_USN_JOURNAL_DATA
                    {
                        UsnJournalID = journalState.UsnJournalID,
                        DeleteFlags  = (uint)Win32Api.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 cb, IntPtr.Zero);

                    lastError = Marshal.GetLastWin32Error();

                    Marshal.FreeHGlobal(dujdBuffer);
                }

                else
                {
                    lastError = (int)UsnJournalReturnCode.INVALID_HANDLE_VALUE;
                }
            }

            ElapsedTime = TimeSpan.FromMilliseconds(sw.ElapsedMilliseconds);

            return(lastError);
        }
        /// <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, Win32Api.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 int GetUsnJournalEntries(Win32Api.USN_JOURNAL_DATA_V0 previousUsnState, uint reasonMask, out List <Win32Api.UsnEntry> usnEntries, out Win32Api.USN_JOURNAL_DATA_V0 newUsnState)
        {
            usnEntries  = new List <Win32Api.UsnEntry>();
            newUsnState = new Win32Api.USN_JOURNAL_DATA_V0();
            var lastError = (int)UsnJournalReturnCode.VOLUME_NOT_NTFS;

            var sw = new Stopwatch();

            sw.Start();

            if (bNtfsVolume)
            {
                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 Win32Api.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)
                        {
                            uint outBytesReturned;

                            var bRtn = Win32Api.DeviceIoControl(_usnJournalRootHandle, Win32Api.FSCTL_READ_USN_JOURNAL, rujdBuffer, sizeRujd, pbData, pbDataSize, out 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 Win32Api.UsnEntry(pUsnRecord);

                                    // Only read until the current usn points beyond the current state's USN.
                                    if (usnEntry.USN >= newUsnState.NextUsn)
                                    {
                                        bReadMore = false;
                                        break;
                                    }

                                    usnEntries.Add(usnEntry);

                                    pUsnRecord        = new IntPtr(pUsnRecord.ToInt64() + usnEntry.RecordLength);
                                    outBytesReturned -= usnEntry.RecordLength;
                                }
                            }

                            else
                            {
                                var lastWin32Error = Marshal.GetLastWin32Error();
                                if (lastWin32Error == (int)Win32Api.GetLastErrorEnum.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;
                }
            }

            ElapsedTime = TimeSpan.FromMilliseconds(sw.ElapsedMilliseconds);

            return(lastError);
        }
        /// <summary>Returns an enumerable collection of <see cref="Win32Api.UsnEntry"/> entries that meet specified criteria.</summary>
        /// <param name="onlyFolders"></param>
        /// <param name="filter">The filter.</param>
        private IEnumerable <Win32Api.UsnEntry> EnumerateUsnEntries(bool?onlyFolders, string filter = null)
        {
            var usnState = new Win32Api.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.");
            }


            if (string.IsNullOrWhiteSpace(filter) || filter.Equals("*", StringComparison.Ordinal))
            {
                filter = null;
            }

            var fileTypes = null != filter?filter.Split(' ', ',', ';') : null;


            // Set up MFT_ENUM_DATA_V0 structure.
            var mftData = new Win32Api.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);


            uint outBytesReturned;

            // Gather up volume's directories.
            while (Win32Api.DeviceIoControl(_usnJournalRootHandle, Win32Api.FSCTL_ENUM_USN_DATA, mftDataBuffer, mftDataSize, pData, pDataSize, out 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 Win32Api.UsnEntry(pUsnRecord);


                    if (null == onlyFolders)
                    {
                        yield return(usnEntry);
                    }

                    else if (usnEntry.IsFolder)
                    {
                        if ((bool)onlyFolders)
                        {
                            yield return(usnEntry);
                        }
                    }

                    else if (!(bool)onlyFolders)
                    {
                        if (null == filter)
                        {
                            yield return(usnEntry);
                        }

                        else
                        {
                            var extension = Path.GetExtension(usnEntry.Name);

                            if (!string.IsNullOrEmpty(extension))
                            {
                                foreach (var fileType in fileTypes)
                                {
                                    if (fileType.Contains("*"))
                                    {
                                        if (extension.IndexOf(fileType.Trim('*'), StringComparison.OrdinalIgnoreCase) >= 0)
                                        {
                                            yield return(usnEntry);
                                        }
                                    }

                                    else if (extension.Equals("." + fileType.TrimStart('.'), StringComparison.OrdinalIgnoreCase))
                                    {
                                        yield return(usnEntry);
                                    }
                                }
                            }
                        }
                    }


                    pUsnRecord        = new IntPtr(pUsnRecord.ToInt64() + usnEntry.RecordLength);
                    outBytesReturned -= usnEntry.RecordLength;
                }

                Marshal.WriteInt64(mftDataBuffer, Marshal.ReadInt64(pData, 0));
            }

            Marshal.FreeHGlobal(pData);
        }
        public MainWindow()
        {
            InitializeComponent();

            _usnCurrentJournalState = new Win32Api.USN_JOURNAL_DATA_V0();
        }