/// <summary><see cref="http://msdn.microsoft.com/en-us/library/windows/desktop/aa364563(v=vs.85).aspx"/></summary>
        public IUSN_RECORD[] FileSystemEnumUsnData()
        {
            ulong     nextUsn   = 0;
            const int chunkSize = 1 * 1024 * 1024;      // 1 MB chunks

            List <IUSN_RECORD> res = new List <IUSN_RECORD>();

            using (UnmanagedMemory mem = new UnmanagedMemory(chunkSize))
            {
                do
                {
                    MFT_ENUM_DATA_V0 input = new MFT_ENUM_DATA_V0();
                    input.StartFileReferenceNumber = nextUsn;
                    input.LowUsn  = long.MinValue;
                    input.HighUsn = long.MaxValue;

                    int    errorCode;
                    byte[] data = DeviceIoControlHelper.InvokeIoControl(Handle, IOControlCode.FsctlEnumUsnData, chunkSize, input, out errorCode);
                    Marshal.Copy(data, 0, mem, data.Length);

                    if (errorCode != 0)
                    {
                        // Exit when theres no more to do
                        break;
                    }

                    nextUsn = BitConverter.ToUInt64(data, 0);

                    int dataOffset = 8;

                    while (dataOffset < data.Length)
                    {
                        int         length;
                        IUSN_RECORD rec = ParseUsnRecord(mem, dataOffset, out length);

                        if (length <= 0)
                        {
                            break;
                        }

                        res.Add(rec);

                        // Move to next record
                        dataOffset += length;
                    }

                    // Fetch next chunk
                } while (true);
            }

            return(res.ToArray());
        }
Ejemplo n.º 2
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);
        }