Example #1
0
        /// <summary>
        /// Retrieves a USN_RECORD_V2 by file reference number (FRN, not USN!)
        /// </summary>
        /// <param name="frn">File reference number</param>
        /// <returns>Returned entry if successful; null otherwise</returns>
        private Record GetRecordByFileRef(ulong frn)
        {
            var enumData = new Win32USN.MFT_ENUM_DATA
            {
                StartFileReferenceNumber = frn,
                LowUsn  = 0,
                HighUsn = m_journal.NextUsn
            };

            var bufferSize = 512;

            byte[] entryData;
            while (!Win32USN.ControlWithInput(m_volumeHandle, Win32USN.FsCtl.EnumUSNData,
                                              ref enumData, bufferSize, out entryData))
            {
                var e = Marshal.GetLastWin32Error();
                if (e != Win32USN.ERROR_INSUFFICIENT_BUFFER)
                {
                    return(null);
                }

                // retry, increasing buffer size
                bufferSize *= 2;
            }

            // not really a foreach: we only check the first record
            foreach (var rec in EnumerateRecords(entryData))
            {
                if (rec.UsnRecord.FileReferenceNumber == frn)
                {
                    return(rec);
                }
                break;
            }

            return(null);
        }
Example #2
0
        /// <summary>
        /// Returns collection of USN records, starting at startUSN
        /// </summary>
        /// <param name="startUsn">The USN number to start the list from, set to zero to get all</param>
        /// <returns>A list of files and folders changed since the USN</returns>
        private ICollection <Record> GetRawRecords(long startUsn)
        {
            var records = new List <Record>();

            var readData = new Win32USN.READ_USN_JOURNAL_DATA_V0
            {
                StartUsn   = Math.Max(startUsn, m_journal.LowestValidUsn),
                ReasonMask = Win32USN.USNReason.USN_REASON_BASIC_INFO_CHANGE |
                             Win32USN.USNReason.USN_REASON_DATA_EXTEND |
                             Win32USN.USNReason.USN_REASON_DATA_OVERWRITE |
                             Win32USN.USNReason.USN_REASON_DATA_TRUNCATION |
                             Win32USN.USNReason.USN_REASON_EA_CHANGE |
                             Win32USN.USNReason.USN_REASON_FILE_CREATE |
                             Win32USN.USNReason.USN_REASON_FILE_DELETE |
                             Win32USN.USNReason.USN_REASON_HARD_LINK_CHANGE |
                             Win32USN.USNReason.USN_REASON_NAMED_DATA_EXTEND |
                             Win32USN.USNReason.USN_REASON_NAMED_DATA_OVERWRITE |
                             Win32USN.USNReason.USN_REASON_NAMED_DATA_TRUNCATION |
                             Win32USN.USNReason.USN_REASON_RENAME_NEW_NAME |
                             Win32USN.USNReason.USN_REASON_RENAME_OLD_NAME |
                             Win32USN.USNReason.USN_REASON_REPARSE_POINT_CHANGE |
                             Win32USN.USNReason.USN_REASON_SECURITY_CHANGE |
                             Win32USN.USNReason.USN_REASON_STREAM_CHANGE,
                ReturnOnlyOnClose = 0,
                Timeout           = 0,
                BytesToWaitFor    = 0,
                UsnJournalID      = m_journal.UsnJournalID
            };

            var bufferSize = 4096; // larger buffer returns more record, but pervents user from cancelling operation for a longer time

            while (readData.StartUsn < m_journal.NextUsn)
            {
                if (!Win32USN.ControlWithInput(m_volumeHandle, Win32USN.FsCtl.ReadUSNJournal,
                                               ref readData, bufferSize, out var entryData))
                {
                    var e = Marshal.GetLastWin32Error();
                    if (e == Win32USN.ERROR_HANDLE_EOF || e == Win32USN.ERROR_SUCCESS)
                    {
                        break;
                    }

                    if (e == Win32USN.ERROR_INSUFFICIENT_BUFFER)
                    {
                        bufferSize = bufferSize * 2;
                        continue;
                    }

                    if (e == Win32USN.ERROR_JOURNAL_ENTRY_DELETED)
                    {
                        throw new UsnJournalSoftFailureException(Strings.USNHelper.JournalEntriesDeleted, new Win32Exception(e));
                    }

                    throw new Win32Exception(e);
                }

                records.AddRange(EnumerateRecords(entryData).TakeWhile(rec => rec.UsnRecord.Usn >= startUsn && rec.UsnRecord.Usn < m_journal.NextUsn));
                readData.StartUsn = Marshal.ReadInt64(entryData, 0);
            }

            return(records);
        }