private void ReadMft(SafeHandle volume) { // ~1MB const int outputBufferSize = 1024 * 1024; var input = SetupMFTEnumData(volume); using (var outBuffer = SafeHGlobalHandle.Alloc(outputBufferSize)) { PInvoke.ZeroMemory(outBuffer, outputBufferSize); using (var inBuffer = SafeHGlobalHandle.Alloc(sizeof(ulong))) { bool hasData; do { Marshal.StructureToPtr(input.StartFileReferenceNumber, inBuffer, true); uint outBytesReturned; hasData = PInvoke.DeviceIoControl( volume.DangerousGetHandle(), DeviceIoControlCode.FsctlEnumUsnData, inBuffer, Marshal.SizeOf <MFT_ENUM_DATA_V0>(), outBuffer, outputBufferSize, out outBytesReturned, IntPtr.Zero ); var pUsnRecord = new IntPtr(outBuffer.DangerousGetHandle().ToInt64() + sizeof(Int64)); //61 is the minimum record length. Less than that is left-over space on the buffer while (outBytesReturned > 60) { var usn = new USN_RECORD(pUsnRecord); if (0 != (usn.FileAttributes & FileAttributeDirectory)) { //Directory _directories.Add(usn.FileReferenceNumber, new UsnRefsAndFileName { FileName = usn.FileName, ParentFileReferenceNumber = usn.ParentFileReferenceNumber, FileReferenceNumber = usn.FileReferenceNumber }); } else { //Files _files.Add(usn.FileReferenceNumber, new UsnRefsAndFileName { FileName = usn.FileName, ParentFileReferenceNumber = usn.ParentFileReferenceNumber, FileReferenceNumber = usn.FileReferenceNumber }); } pUsnRecord = new IntPtr(pUsnRecord.ToInt64() + usn.RecordLength); outBytesReturned -= usn.RecordLength; } input.StartFileReferenceNumber = (ulong)Marshal.ReadInt64(outBuffer, 0); } while (hasData); } ParseFullPath(); } }
unsafe public void EnumerateFiles(IntPtr medBuffer, ref Dictionary <ulong, FileNameAndParentFrn> files, string[] fileExtensions) { IntPtr pData = Marshal.AllocHGlobal(sizeof(UInt64) + 0x10000); try { NativeWrapper.ZeroMemory(pData, sizeof(UInt64) + 0x10000); uint outBytesReturned = 0; while (false != NativeWrapper.DeviceIoControl(_changeJournalRootHandle, NativeWrapper.FSCTL_ENUM_USN_DATA, medBuffer, sizeof(MFT_ENUM_DATA), pData, sizeof(UInt64) + 0x10000, out outBytesReturned, IntPtr.Zero)) { IntPtr pUsnRecord = new IntPtr(pData.ToInt32() + sizeof(Int64)); while (outBytesReturned > 60) { USN_RECORD usn = new USN_RECORD(pUsnRecord); if (0 != (usn.FileAttributes & NativeWrapper.FILE_ATTRIBUTE_DIRECTORY)) { // // handle directories // if (!_directories.ContainsKey(usn.FileReferenceNumber)) { _directories.Add(usn.FileReferenceNumber, new FileNameAndParentFrn(usn.FileName, usn.ParentFileReferenceNumber)); } else { // this is debug code and should be removed when we are certain that // duplicate frn's don't exist on a given drive. To date, this exception has // never been thrown. Removing this code improves performance.... throw new Exception(string.Format("Duplicate FRN: {0} for {1}", usn.FileReferenceNumber, usn.FileName)); } } else { // // handle files // // at this point we could get the * for the extension bool add = true; bool fullpath = false; if (fileExtensions != null && fileExtensions.Length != 0) { if (fileExtensions[0].ToString() == "*") { add = true; fullpath = true; } else { add = false; string s = Path.GetExtension(usn.FileName); foreach (string extension in fileExtensions) { if (0 == string.Compare(s, extension, true)) { add = true; break; } } } } if (add) { if (fullpath) { if (!files.ContainsKey(usn.FileReferenceNumber)) { files.Add(usn.FileReferenceNumber, new FileNameAndParentFrn(usn.FileName, usn.ParentFileReferenceNumber)); } else { FileNameAndParentFrn frn = files[usn.FileReferenceNumber]; if (0 != string.Compare(usn.FileName, frn.Name, true)) { // Log.InfoFormat( // "Attempt to add duplicate file reference number: {0} for file {1}, file from index {2}", // usn.FileReferenceNumber, usn.FileName, frn.Name); throw new Exception(string.Format("Duplicate FRN: {0} for {1}", usn.FileReferenceNumber, usn.FileName)); } } } else { if (!files.ContainsKey(usn.FileReferenceNumber)) { files.Add(usn.FileReferenceNumber, new FileNameAndParentFrn(usn.FileName, usn.ParentFileReferenceNumber)); } else { FileNameAndParentFrn frn = files[usn.FileReferenceNumber]; if (0 != string.Compare(usn.FileName, frn.Name, true)) { // Log.InfoFormat( // "Attempt to add duplicate file reference number: {0} for file {1}, file from index {2}", // usn.FileReferenceNumber, usn.FileName, frn.Name); throw new Exception(string.Format("Duplicate FRN: {0} for {1}", usn.FileReferenceNumber, usn.FileName)); } } } } } pUsnRecord = new IntPtr(pUsnRecord.ToInt32() + usn.RecordLength); outBytesReturned -= usn.RecordLength; } Marshal.WriteInt64(medBuffer, Marshal.ReadInt64(pData, 0)); } } catch (Exception e) { Console.Error.WriteLine(e.Message); Console.Error.WriteLine(e.StackTrace); throw new ApplicationException("Error in EnumerateFiles()", e); } finally { Marshal.FreeHGlobal(pData); } }
internal USNJrnl(byte[] bytes) { USN_RECORD structUSN = new USN_RECORD(bytes); #region UnmaskReason string reason = null; if ((structUSN.Reason & (uint)USN_REASON_BASIC_INFO_CHANGE) == (uint)USN_REASON_BASIC_INFO_CHANGE) { reason = "Basic Info Change"; } if ((structUSN.Reason & (uint)USN_REASON_CLOSE) == (uint)USN_REASON_CLOSE) { reason = "Close"; } if ((structUSN.Reason & (uint)USN_REASON_COMPRESSION_CHANGE) == (uint)USN_REASON_COMPRESSION_CHANGE) { reason = "Compression Change"; } if ((structUSN.Reason & (uint)USN_REASON_DATA_EXTEND) == (uint)USN_REASON_DATA_EXTEND) { reason = "Data Extended"; } if ((structUSN.Reason & (uint)USN_REASON_DATA_OVERWRITE) == (uint)USN_REASON_DATA_OVERWRITE) { reason = "Data Overwrite"; } if ((structUSN.Reason & (uint)USN_REASON_DATA_TRUNCATION) == (uint)USN_REASON_DATA_TRUNCATION) { reason = "Data Truncation"; } if ((structUSN.Reason & (uint)USN_REASON_EA_CHANGE) == (uint)USN_REASON_EA_CHANGE) { reason = "EA Change"; } if ((structUSN.Reason & (uint)USN_REASON_ENCRYPTION_CHANGE) == (uint)USN_REASON_ENCRYPTION_CHANGE) { reason = "Encryption Change"; } if ((structUSN.Reason & (uint)USN_REASON_FILE_CREATE) == (uint)USN_REASON_FILE_CREATE) { reason = "File Create"; } if ((structUSN.Reason & (uint)USN_REASON_FILE_DELETE) == (uint)USN_REASON_FILE_DELETE) { reason = "File Delete"; } if ((structUSN.Reason & (uint)USN_REASON_HARD_LINK_CHANGE) == (uint)USN_REASON_HARD_LINK_CHANGE) { reason = "Hard Link Change"; } if ((structUSN.Reason & (uint)USN_REASON_INDEXABLE_CHANGE) == (uint)USN_REASON_INDEXABLE_CHANGE) { reason = "Indexable Change"; } if ((structUSN.Reason & (uint)USN_REASON_NAMED_DATA_EXTEND) == (uint)USN_REASON_NAMED_DATA_EXTEND) { reason = "Named Data Extend"; } if ((structUSN.Reason & (uint)USN_REASON_NAMED_DATA_OVERWRITE) == (uint)USN_REASON_NAMED_DATA_OVERWRITE) { reason = "Named Data Overwrite"; } if ((structUSN.Reason & (uint)USN_REASON_NAMED_DATA_TRUNCATION) == (uint)USN_REASON_NAMED_DATA_TRUNCATION) { reason = "Named Data Truncation"; } if ((structUSN.Reason & (uint)USN_REASON_OBJECT_ID_CHANGE) == (uint)USN_REASON_OBJECT_ID_CHANGE) { reason = "Object ID Change"; } if ((structUSN.Reason & (uint)USN_REASON_RENAME_NEW_NAME) == (uint)USN_REASON_RENAME_NEW_NAME) { reason = "Rename: New Name"; } if ((structUSN.Reason & (uint)USN_REASON_RENAME_OLD_NAME) == (uint)USN_REASON_RENAME_OLD_NAME) { reason = "Rename: Old Name"; } if ((structUSN.Reason & (uint)USN_REASON_REPARSE_POINT_CHANGE) == (uint)USN_REASON_REPARSE_POINT_CHANGE) { reason = "Reparse Point Change"; } if ((structUSN.Reason & (uint)USN_REASON_SECURITY_CHANGE) == (uint)USN_REASON_SECURITY_CHANGE) { reason = "Security Change"; } if ((structUSN.Reason & (uint)USN_REASON_STREAM_CHANGE) == (uint)USN_REASON_STREAM_CHANGE) { reason = "Stream Change"; } #endregion UnmaskReason #region UnmaskSourceInfo string sourceInfo = null; if ((structUSN.SourceInfo & (uint)USN_SOURCE.AUXILIARY_DATA) == (uint)USN_SOURCE.AUXILIARY_DATA) { sourceInfo = "Auxiliary Data"; } if ((structUSN.SourceInfo & (uint)USN_SOURCE.DATA_MANAGEMENT) == (uint)USN_SOURCE.DATA_MANAGEMENT) { sourceInfo = "Data Management"; } if ((structUSN.SourceInfo & (uint)USN_SOURCE.REPLICATION_MANAGEMENT) == (uint)USN_SOURCE.REPLICATION_MANAGEMENT) { sourceInfo = "Replication Management"; } #endregion UnmaskSourceInfo FileReferenceNumber = structUSN.FileReferenceNumber; ParentFileReferenceNumber = structUSN.ParentFileReferenceNumber; Usn = structUSN.Usn; TimeStamp = DateTime.FromFileTime(structUSN.TimeStamp); Reason = reason; SourceInfo = sourceInfo; SecurityId = structUSN.SecurityId; FileAttributes = structUSN.FileAttributes; FileName = Encoding.Unicode.GetString(structUSN.FileName); }