Пример #1
0
        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;
        }
Пример #2
0
        /// <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;
        }