Exemple #1
0
        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();
        }
Exemple #2
0
        /// <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);
Exemple #4
0
#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;
        }
Exemple #5
0
 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}");
 }
Exemple #6
0
        /// <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);
        }
Exemple #7
0
        /// <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);
        }
Exemple #8
0
        /// <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);
        }
Exemple #9
0
        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);
        }
Exemple #12
0
        /// <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());
        }
Exemple #13
0
        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;
                }
            }
        }
Exemple #14
0
        /// <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);
        }
Exemple #15
0
        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);
            }
        }
Exemple #16
0
        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);
                }
            }
        }