public IEnumerable<PInvokeWin32.USN_RECORD> ReadUSN(ulong USNJournalID, Int64 lowUsn, uint ReasonMask, ulong TimeOut, ulong ByteToWait) { int buffersize = sizeof(UInt64) + 65535; // Set READ_USN_JOURNAL_DATA PInvokeWin32.READ_USN_JOURNAL_DATA Rujd; /// Document: /// http://www.microsoft.com/msj/0999/journal/journal.aspx /// http://www.microsoft.com/msj/1099/journal2/journal2.aspx /// /// Timeout: /// Timeout is a value for use with the BytesToWaitFor member. /// It does not guarantee that DeviceIoControl will return after /// the specified timeout, but rather it specifies how often the /// system should check whether requested data is available. /// This member is not like other conventional Win32¨ timeout /// parameters that use milliseconds. Instead, this member uses /// the same resolution as the Win32 FILETIME structure /// (100-nanosecond intervals—one second has ten million intervals). /// A value of zero specifies no timeout (or infinite). /// A fixed timeout is specified using negative values /// (even though this is an unsigned variable). /// For example, a timeout of 25 seconds can be expressed as /// (DWORDLONG)(-2500000000). /// The Timeout member is ignored if DeviceIoControl is /// called with an asynchronous request. /// BytesToWaitFor: /// Don't confuse the BytesToWaitFor member with the output buffer /// size or the count of bytes returned by DeviceIoControl. /// If this member is set to zero, the function will return immediately, /// even if it found no matching records in the journal. If this member /// is nonzero, the system will not return until it has found at least /// one record to return. BytesToWaitFor specifies how often the system /// will recheck the journal to see whether any matching records have been /// created. For example, if you specify 16384, the system will only examine /// the journal for new records after a new 16KB block of raw data has been /// added. This prevents a process from using too many resources when many /// records are being added. If the Timeout and BytesToWaitFor members are /// both nonzero, the system also checks records if the timeout period expires /// before the journal has grown by the specified number of bytes. /// If BytesToWaitFor is nonzero, but records are found that match the user's /// request, the DeviceIoControl function will return immediately; that is, the /// BytesToWaitFor and TimeOut members only have an effect when there are not any /// existing records that fulfill the ReasonMask/ReturnOnlyOnClose requirements. Rujd.StartUSN = lowUsn; Rujd.ReasonMask = ReasonMask; Rujd.UsnJournalID = USNJournalID; Rujd.BytesToWaitFor = ByteToWait; /// Set to 0 for no waiting, otherwise it will notice new record Rujd.Timeout = TimeOut; /// When BytesToWaitfor is 0, the timeout is ignore Rujd.ReturnOnlyOnClose = 0; IntPtr UsnBuffer = IntPtr.Zero; IntPtr pData = IntPtr.Zero; try { // Set User Buffer UsnBuffer = Marshal.AllocHGlobal(PInvokeWin32.SIZEOF_READ_USN_JOURNAL_DATA); PInvokeWin32.ZeroMemory(UsnBuffer, PInvokeWin32.SIZEOF_READ_USN_JOURNAL_DATA); Marshal.StructureToPtr(Rujd, UsnBuffer, true); // Set Output Buffer pData = Marshal.AllocHGlobal(buffersize); PInvokeWin32.ZeroMemory(pData, buffersize); uint outBytesReturned = 0; Int64 startUsn = lowUsn; while (true) { Rujd.StartUSN = startUsn; Rujd.ReasonMask = ReasonMask; Rujd.UsnJournalID = USNJournalID; Marshal.StructureToPtr(Rujd, UsnBuffer, true); var retOK = PInvokeWin32.DeviceIoControl(ChangeJournalRootHandle, PInvokeWin32.FSCTL_READ_USN_JOURNAL, UsnBuffer, PInvokeWin32.SIZEOF_READ_USN_JOURNAL_DATA, pData, buffersize, out outBytesReturned, IntPtr.Zero); if (retOK == false) { throw new Win32Exception(Marshal.GetLastWin32Error()); } /// the first returned USN record /// The first Int64 are next usn number!! /// If there are no more record, it is the next usn startUsn = Marshal.ReadInt64(pData); CurUsn = startUsn; IntPtr pUsnRecord = new IntPtr(pData.ToInt32() + sizeof(Int64)); PInvokeWin32.USN_RECORD p = null; while (outBytesReturned > 60) { p = new PInvokeWin32.USN_RECORD(pUsnRecord); pUsnRecord = new IntPtr(pUsnRecord.ToInt32() + p.RecordLength); outBytesReturned -= p.RecordLength; yield return p; } if (p == null || startUsn == p.Usn) break; } } finally { if (pData != IntPtr.Zero) Marshal.FreeHGlobal(pData); if (UsnBuffer != IntPtr.Zero) Marshal.FreeHGlobal(UsnBuffer); } yield break; }
public IEnumerable<PInvokeWin32.USN_RECORD> EnumVolume(Int64 lowUsn, Int64 highUsn) { PInvokeWin32.MFT_ENUM_DATA med; med.StartFileReferenceNumber = 0; med.LowUsn = lowUsn; med.HighUsn = highUsn; IntPtr medBuffer = IntPtr.Zero; IntPtr pData = IntPtr.Zero; try { medBuffer = Marshal.AllocHGlobal(PInvokeWin32.SIZEOF_MFT_ENUM_DATA); PInvokeWin32.ZeroMemory(medBuffer, PInvokeWin32.SIZEOF_MFT_ENUM_DATA); Marshal.StructureToPtr(med, medBuffer, true); int buffersize = sizeof(UInt64) + 0x10000; pData = Marshal.AllocHGlobal(buffersize); PInvokeWin32.ZeroMemory(pData, buffersize); uint outBytesReturned = 0; while (true) { bool stOK = PInvokeWin32.DeviceIoControl( ChangeJournalRootHandle, // VolumHandler PInvokeWin32.FSCTL_ENUM_USN_DATA, // Command medBuffer, // Command Block, inputer buffer PInvokeWin32.SIZEOF_MFT_ENUM_DATA, // Command Block Size pData, // Output buffer buffersize, // size of output buffer out outBytesReturned, // Return Value (Error Message) IntPtr.Zero); if (stOK == false) break; IntPtr pUsnRecord = new IntPtr(pData.ToInt32() + sizeof(Int64)); while (outBytesReturned > PInvokeWin32.SIZEOF_USN_RECORD) { PInvokeWin32.USN_RECORD usn = new PInvokeWin32.USN_RECORD(pUsnRecord); yield return usn; pUsnRecord = new IntPtr(pUsnRecord.ToInt32() + usn.RecordLength); outBytesReturned -= usn.RecordLength; } /// Write the new StartFileReferenceNumber Marshal.WriteInt64(medBuffer, Marshal.ReadInt64(pData, 0)); } } finally { if (medBuffer != IntPtr.Zero) Marshal.FreeHGlobal(medBuffer); if (pData != IntPtr.Zero) Marshal.FreeHGlobal(pData); } yield break; }