internal unsafe IPartitionClusterData GetData() { using (Stream input = OpenDataClusterStream()) { NonResidentDataStream dataStream = (NonResidentDataStream)input; long length = dataStream.Length; if (uint.MaxValue < length) { throw new ApplicationException(); } IPartitionClusterData result = NtfsPartition.Current.GetBuffer((uint)length); byte *rawResult = result.Data; IPartitionClusterData inputData; while (null != (inputData = ((IClusterStream)dataStream).ReadNextCluster())) { try { uint inputDataLength = inputData.DataSize; if (int.MaxValue < inputDataLength) { throw new ApplicationException(); } Helpers.Memcpy(inputData.Data, rawResult, (int)inputDataLength); rawResult += inputDataLength; } finally { inputData.Dispose(); } } return(result); } }
private static unsafe void _Dump(NtfsAttributeListAttribute *from, DumpCallbackDelegate callback) { if (null == from) { throw new ArgumentNullException(); } if (NtfsAttributeType.AttributeAttributeList != from->Header.AttributeType) { throw new ArgumentException(); } IPartitionClusterData disposableData = null; ListEntry * listBase = null; uint listLength; try { if (from->Header.IsResident) { NtfsResidentAttribute *listAttribute = (NtfsResidentAttribute *)from; listBase = (ListEntry *)((byte *)from + listAttribute->ValueOffset); listLength = listAttribute->ValueLength; } else { NtfsNonResidentAttribute *listAttribute = (NtfsNonResidentAttribute *)from; disposableData = listAttribute->GetData(); if (null == disposableData) { throw new ApplicationException(); } listBase = (ListEntry *)disposableData.Data; ulong candidateLength = listAttribute->DataSize; if (uint.MaxValue < candidateLength) { throw new ApplicationException(); } listLength = (uint)candidateLength; } if (null == listBase) { throw new ApplicationException(); } uint offset = 0; while (offset < listLength) { ListEntry *entry = (ListEntry *)((byte *)listBase + offset); callback(entry); offset += entry->EntryLength; } } finally { if (null != disposableData) { disposableData.Dispose(); } } }
/// <summary>Discover partitions</summary> internal unsafe void Discover() { VolumePartition fakePartition = new VolumePartition(_rawHandle, 0, 16); using (IPartitionClusterData rawData = fakePartition.ReadSectors(0)) { uint minSector = uint.MaxValue; uint maxSector = 0; byte *masterBootRecord = rawData.Data; if (0x55 != masterBootRecord[510]) { throw new ApplicationException(); } if (0xAA != masterBootRecord[511]) { throw new ApplicationException(); } // From http://thestarman.pcministry.com/asm/mbr/PartTables.htm // TODO : This is suitable for a Master Boot Record. Other types of boot records exist such // as the ExtendedBoot Record format. for (uint partitionIndex = 0; partitionIndex < 4; partitionIndex++) { IntPtr partitionHandle; if (!Natives.DuplicateHandle(new IntPtr(-1), _rawHandle, new IntPtr(-1), out partitionHandle, 0 /* ignored because same access */, false, 2 /*DUPLICATE_SAME_ACCESS*/)) { throw new ApplicationException(); } GenericPartition newPartition = GenericPartition.Create(partitionHandle, masterBootRecord, 446 + (16 * partitionIndex)); if (null == newPartition) { Natives.CloseHandle(partitionHandle); } else { // TODO : This algorithm doesn't let us witness the extra sectors after the last partition. if (minSector > newPartition.StartSector) { minSector = newPartition.StartSector; } if (maxSector < (newPartition.StartSector + newPartition.SectorCount - 1)) { maxSector = newPartition.StartSector + newPartition.SectorCount - 1; } _partitions.Add(newPartition); } } Console.WriteLine("Found {0} partitions.", _partitions.Count); if (maxSector < minSector) { throw new ApplicationException(); } _volumePartition = new VolumePartition(_rawHandle, minSector, maxSector - minSector); return; } }
internal static uint GetChainLength(this IPartitionClusterData data) { uint result = 0; for (IPartitionClusterData scannedData = data; null != scannedData; scannedData = scannedData.NextInChain) { result += scannedData.DataSize; } return(result); }
internal static uint GetChainItemsCount(this IPartitionClusterData data) { uint result = 0; for (IPartitionClusterData scannedData = data; null != scannedData; scannedData = scannedData.NextInChain) { result++; } return(result); }
private void HandlePartitionClusterDataDisposal(IPartitionClusterData disposed) { if (_disposing) { return; } if (!_storage.Remove(disposed)) { throw new ArgumentException(); } }
/// <summary>Read some number of sectors.</summary> /// <param name="logicalSectorId">Logical identifier of the first sector to be read.</param> /// <param name="sectorsCount">Number of sectors to read.</param> /// <returns>Buffer address.</returns> internal unsafe IPartitionClusterData ReadSectors(ulong logicalSectorId, uint sectorsCount = 1) { IPartitionClusterData result = GetClusterBufferChain(sectorsCount * BytesPerSector); try { return(ReadSectors(result, 0, logicalSectorId, sectorsCount)); } catch { if (null != result) { result.Dispose(); } throw; } }
internal static unsafe NtfsFileRecord *Create(ulong fileId) { if ((0xFFFFFFFFFFFF & fileId) != fileId) { throw new ArgumentException(); } NtfsPartition partition = NtfsPartition.Current; ulong mftEntrySize = partition.ClusterSize / partition.MFTEntryPerCluster; ulong clusterId = fileId / partition.MFTEntryPerCluster; ulong inClusterOffset = (fileId % partition.MFTEntryPerCluster) * mftEntrySize; IPartitionClusterData clusterData = partition.ReadSectors(clusterId * partition.SectorsPerCluster, partition.SectorsPerCluster); return((NtfsFileRecord *)(clusterData.Data + inClusterOffset)); }
internal void Register(IPartitionClusterData data) { if (null == data) { throw new ArgumentNullException(); } data.Disposed += _dispositionHandler; _storage.Add(data, 0); if (FeaturesContext.DataPoolChecksEnabled) { if (StorageCountAlert < _storage.Count) { throw new ApplicationException(); } } }
internal unsafe void EnumerateRecordAttributes(NtfsPartition owner, ulong recordLBA, ref byte *buffer, RecordAttributeEnumeratorCallbackDelegate callback, NtfsAttributeType searchedType = NtfsAttributeType.Any, AttributeNameFilterDelegate nameFilter = null) { using (IPartitionClusterData data = owner.ReadSectors(recordLBA)) { buffer = data.Data; NtfsFileRecord *header = (NtfsFileRecord *)buffer; header->AssertRecordType(); if (1024 < header->BytesAllocated) { throw new NotImplementedException(); } EnumerateRecordAttributes(header, callback, searchedType, nameFilter); } }
private unsafe void _Run() { NtfsPartition partition = Partition; IPartitionClusterData clusterData = null; try { NtfsFileRecord *fileRecord = partition.GetFileRecord( NtfsWellKnownMetadataFiles.LogFile, out clusterData); fileRecord->AssertRecordType(); throw new NotImplementedException(); } finally { if (null != clusterData) { clusterData.Dispose(); } } }
IPartitionClusterData IClusterStream.ReadNextCluster() { if (!_clusterStreamBehavior) { throw new NotSupportedException("Not a cluster stream."); } bool success = _ReadNextCluster(); IPartitionClusterData result = _clusterData; _clusterData = null; if (!success) { if (null != result) { result.Dispose(); } return(null); } return(result); }
/// <summary>Read some number of sectors.</summary> /// <param name="into">Pre-allocated buffer.</param> /// <param name="logicalSectorId">Logical identifier of the first sector to be read.</param> /// <param name="sectorsCount">Number of sectors to read.</param> /// <returns>Buffer address.</returns> internal unsafe IPartitionClusterData ReadSectors(IPartitionClusterData into, long atOffset, ulong logicalSectorId, uint sectorsCount = 1) { uint bytesPerSector = PartitionManager.Singleton.Geometry.BytesPerSector; uint expectedCount = sectorsCount * bytesPerSector; if (null == into) { throw new ArgumentNullException(); } if (0 > atOffset) { throw new ArgumentException(); } if ((into.DataSize - atOffset) < expectedCount) { throw new ArgumentException(); } if (FeaturesContext.DataPoolChecksEnabled) { if (expectedCount > into.DataSize) { throw new ApplicationException(); } } ulong offset = (logicalSectorId + StartSector) * bytesPerSector; uint totalBytesRead = 0; // Prevent concurrent reads on this partition. lock (_ioLock) { if (!Natives.SetFilePointerEx(_handle, (long)offset, out offset, Natives.FILE_BEGIN)) { int error = Marshal.GetLastWin32Error(); throw new ApplicationException(); } uint chainItemsCount = into.GetChainItemsCount(); uint chainLength = into.GetChainLength(); if (chainLength < expectedCount) { throw new ApplicationException(); } uint remainingExpectation = expectedCount; for (IPartitionClusterData currentData = into; null != currentData; currentData = currentData.NextInChain) { uint readSize = remainingExpectation; if (readSize > into.DataSize) { readSize = into.DataSize; } uint effectiveReadSize; if (!Natives.ReadFile(_handle, into.Data + atOffset, readSize, out effectiveReadSize, IntPtr.Zero)) { int error = Marshal.GetLastWin32Error(); throw new ApplicationException(); } atOffset += effectiveReadSize; totalBytesRead += effectiveReadSize; remainingExpectation -= effectiveReadSize; } } if (totalBytesRead != expectedCount) { throw new ApplicationException(); } return(into); }
public static unsafe int Main(string[] args) { InstallExceptionHandlers(); using (PartitionDataDisposableBatch mainBatch = PartitionDataDisposableBatch.CreateNew()) { DisplayVersion(); IntPtr handle = IntPtr.Zero; int nativeError; DiskGeometry geometry = new DiskGeometry(); try { handle = Natives.CreateFile2(@"\\.\PhysicalDrive0", 0x80000000 /* GENERIC_READ */, 0x02 /* FILE_SHARE_WRITE */, 3 /* OPEN_EXISTING */, IntPtr.Zero); nativeError = Marshal.GetLastWin32Error(); if ((IntPtr.Zero == handle) || (0 != nativeError)) { Console.WriteLine("Physical drive opening failed. Error 0x{0:X8}", nativeError); return(1); } geometry.Acquire(handle); _partitionManager = new PartitionManager(handle, geometry); _partitionManager.Discover(); InterpretActivePartitions(); if (FeaturesContext.InvariantChecksEnabled) { NtfsMFTFileRecord.AssertMFTRecordCachingInvariance(_partitionManager); } // TODO : Configure TrackedPartitionIndex from command line arguments. foreach (GenericPartition partition in _partitionManager.EnumeratePartitions()) { if (!partition.ShouldCapture) { continue; } NtfsPartition ntfsPartition = partition as NtfsPartition; NtfsPartition.Current = ntfsPartition; // Basic functionnality tests. Don't remove. //ntfsPartition.CountFiles(); //ntfsPartition.MonitorBadClusters(); //ntfsPartition.ReadBitmap(); // Dump bad clusters. ntfsPartition.DumpBadClusters(); // Dump UsnJournal PrototypeUsnJournal(); new NtfsUsnJournalReader(ntfsPartition).Run(); // Dump LogFile // new NtfsLogFileReader(ntfsPartition).Run(); // Locate file. // string fileName = @"TEMP\AsciiTes.txt"; string fileName = @"$Extend\$UsnJrnl"; NtfsIndexEntryHeader *fileDescriptor = ntfsPartition.FindFile(fileName); if (null == fileDescriptor) { throw new System.IO.FileNotFoundException(fileName); } IPartitionClusterData fileData = null; NtfsFileRecord * usnJournalFileRecord = ntfsPartition.GetFileRecord(fileDescriptor->FileReference, ref fileData); if ((null == usnJournalFileRecord) || (null == fileData)) { throw new ApplicationException(); } try { usnJournalFileRecord->EnumerateRecordAttributes( delegate(NtfsAttribute * attribute, Stream dataStream) { attribute->Dump(); return(true); }); // For debugging purpose. // fileRecord->BinaryDumpContent(); // TODO : Do something with the file. } finally { if (null != fileData) { fileData.Dispose(); } } } return(0); } finally { if (IntPtr.Zero == handle) { Natives.CloseHandle(handle); handle = IntPtr.Zero; } } } }
private static unsafe void PrototypeUsnJournal() { List <Tuple <uint, ulong> > records = new List <Tuple <uint, ulong> >() { new Tuple <uint, ulong>(0x00000000, 0x10000000417F8), new Tuple <uint, ulong>(0x00831030, 0x133000000030345), new Tuple <uint, ulong>(0x00835CE0, 0x79200000000288E), new Tuple <uint, ulong>(0x00839E60, 0x16C0000000059EB), new Tuple <uint, ulong>(0x00842DE0, 0x7340000000057C6), new Tuple <uint, ulong>(0x00844160, 0x600000018405F), new Tuple <uint, ulong>(0x0084A215, 0x8F000000036956), new Tuple <uint, ulong>(0x0084EF80, 0x2B0000000020AD), new Tuple <uint, ulong>(0x00852F71, 0x3D00000000024B8), new Tuple <uint, ulong>(0x00857E50, 0x50B000000007274), new Tuple <uint, ulong>(0x00858DB0, 0x235000000000705), new Tuple <uint, ulong>(0x0085CD90, 0xD20000000086D7), new Tuple <uint, ulong>(0x00860A90, 0x7900000000840C), new Tuple <uint, ulong>(0x00862160, 0x6E500000002FC3E), new Tuple <uint, ulong>(0x00868190, 0x7F000000004050), new Tuple <uint, ulong>(0x0086C570, 0x49E000000003C3E), new Tuple <uint, ulong>(0x0086D8F0, 0x160000000F353D), new Tuple <uint, ulong>(0x00871DB0, 0x9D000000004053), new Tuple <uint, ulong>(0x00875B90, 0x19F000000001DD5), new Tuple <uint, ulong>(0x00877B0C, 0x387000000031EA2), new Tuple <uint, ulong>(0x0087BE50, 0x840000000041B7), new Tuple <uint, ulong>(0x00883CC0, 0x2C4000000006741), new Tuple <uint, ulong>(0x00888210, 0x93000000007190), new Tuple <uint, ulong>(0x00889710, 0xF30000000DD118), new Tuple <uint, ulong>(0x0089759B, 0xA2B000000006C37), new Tuple <uint, ulong>(0x0089F050, 0xD400000002EF59), new Tuple <uint, ulong>(0x008A3480, 0x4000000030266), new Tuple <uint, ulong>(0x008A4780, 0x3D000000122430), new Tuple <uint, ulong>(0x008A8FF0, 0x4A0000000F8276), new Tuple <uint, ulong>(0x008ACDF0, 0x7000000030267), new Tuple <uint, ulong>(0x008B1FF0, 0xF000000030265), new Tuple <uint, ulong>(0x008B32F2, 0x10000001E9963), new Tuple <uint, ulong>(0x008B7272, 0x5000000030269), new Tuple <uint, ulong>(0x008BB022, 0x6000000030268), new Tuple <uint, ulong>(0x008BC2A0, 0xC000000121FED), new Tuple <uint, ulong>(0x008C4B70, 0x3700000016AC1D), new Tuple <uint, ulong>(0x008CEDF0, 0x5000000184830), new Tuple <uint, ulong>(0x008DEAD0, 0x1D0000000004401), new Tuple <uint, ulong>(0x008E2D20, 0x3B400000000157B), new Tuple <uint, ulong>(0x008E4120, 0x3DC0000000045DC), new Tuple <uint, ulong>(0x008E8FC0, 0x2800000000E8AE), new Tuple <uint, ulong>(0x008F123D, 0x52F0000000010F0), new Tuple <uint, ulong>(0x008F72F0, 0x147000000033E17), new Tuple <uint, ulong>(0x008FB610, 0x5A0000000305FD), new Tuple <uint, ulong>(0x008FCA00, 0x144000000003871), new Tuple <uint, ulong>(0x00901140, 0x1E2000000033E33), new Tuple <uint, ulong>(0x009054B0, 0x29000000033E34), new Tuple <uint, ulong>(0x00906AB0, 0x3420000000035B2), new Tuple <uint, ulong>(0x0090B250, 0xD7000000004C47), new Tuple <uint, ulong>(0x0090F710, 0xA9000000005C58), new Tuple <uint, ulong>(0x00913660, 0xC9000000002451), new Tuple <uint, ulong>(0x0091A1E0, 0xA8000000004E3B), new Tuple <uint, ulong>(0x009280D4, 0x2920000000DD0CA), new Tuple <uint, ulong>(0x0092C280, 0x276000000031B0A), new Tuple <uint, ulong>(0x00934D30, 0x6F0000000F179E), new Tuple <uint, ulong>(0x0093B220, 0xB20000000D3A3F), new Tuple <uint, ulong>(0x0093F0C4, 0x5400000002BC62), new Tuple <uint, ulong>(0x00940380, 0xA7000000004A8C), new Tuple <uint, ulong>(0x00945C6F, 0x6F000000008D46), new Tuple <uint, ulong>(0x0094C310, 0x3A0000000D9AA7), new Tuple <uint, ulong>(0x00954910, 0x4C0000000D9A91) }; NtfsPartition partition = NtfsPartition.Current; ulong mftEntrySize = partition.ClusterSize / partition.MFTEntryPerCluster; IPartitionClusterData data = null; try { ulong baseFileRecord = 0; foreach (Tuple <uint, ulong> record in records) { ulong fileReference = record.Item2; NtfsFileRecord *fileRecord = partition.GetFileRecord(fileReference, ref data); if (0 == baseFileRecord) { baseFileRecord = fileRecord->BaseFileRecord; } if (fileRecord->BaseFileRecord != baseFileRecord) { fileRecord->BinaryDump(); fileRecord->Dump(); throw new ApplicationException(); } fileRecord->EnumerateRecordAttributes(delegate(NtfsAttribute * value, Stream attributeDataStream) { if (null != attributeDataStream) { throw new NotSupportedException(); } if (value->IsResident) { throw new NotSupportedException(); } IClusterStream dataStream = (IClusterStream)((NtfsNonResidentAttribute *)value)->OpenDataClusterStream(); dataStream.SeekToNextNonEmptyCluster(); NtfsUsnJournalReader.UsnRecordV2 *currentUsnRecord = null; while (true) { using (IPartitionClusterData clusterData = dataStream.ReadNextCluster()) { if (null == clusterData) { // Done with this stream. return(true); } for (uint offset = 0; offset < clusterData.DataSize; offset += currentUsnRecord->RecordLength) { currentUsnRecord = (NtfsUsnJournalReader.UsnRecordV2 *)(clusterData.Data + offset); if (0 == currentUsnRecord->RecordLength) { break; } if (2 != currentUsnRecord->MajorVersion) { Helpers.BinaryDump((byte *)currentUsnRecord, (uint)Marshal.SizeOf <NtfsUsnJournalReader.UsnRecordV2>()); throw new NotSupportedException(); } if (0 != currentUsnRecord->MinorVersion) { throw new NotSupportedException(); } currentUsnRecord->Dump(); } } } }, NtfsAttributeType.AttributeData, null); fileRecord->DumpAttributes(); } return; } finally { if (null != data) { data.Dispose(); } } }
/// <summary></summary> /// <param name="from">The NtfsAttributeListAttribute to be used for enumeration.</param> /// <param name="searchedAttributeType">The type of the searched attribute or /// <see cref="NtfsAttributeType.Any"/> if the caller is interested in all kinds of /// attributes.</param> /// <param name="listEntryHandler">A callback to be invoked on each entry matching /// the attribute type selection criteria.</param> /// <remarks>WARNING : This might seems counterintuitive to have this method at a class /// level instead of making it an instance one. This is because we absolutely don't want /// it to be invoked on an object reference that is subject to being moved in memory by /// the GC. Forcing the caller to provide a pointer makes her responsible for enforcing /// the pinning requirements.</remarks> internal static unsafe void EnumerateEntries(NtfsAttribute *from, NtfsAttributeType searchedAttributeType, EntryEnumeratorCallbackDelegate listEntryHandler) { if (null == from) { throw new ArgumentNullException(); } if (NtfsAttributeType.AttributeAttributeList != from->AttributeType) { throw new ArgumentException(); } IPartitionClusterData listAttributeData = null; // Address of first ListeEntry item for this attribute. ListEntry *listBase = null; uint listLength; try { if (from->IsResident) { NtfsResidentAttribute *listAttribute = (NtfsResidentAttribute *)from; listBase = (ListEntry *)((byte *)from + listAttribute->ValueOffset); listLength = listAttribute->ValueLength; } else { NtfsNonResidentAttribute *listAttribute = (NtfsNonResidentAttribute *)from; listAttributeData = listAttribute->GetData(); if (null == listAttributeData) { throw new ApplicationException(); } listBase = (ListEntry *)listAttributeData.Data; ulong candidateLength = listAttribute->DataSize; if (uint.MaxValue < candidateLength) { throw new ApplicationException(); } listLength = (uint)candidateLength; } if (null == listBase) { throw new ApplicationException(); } NtfsAttributeType currentAttributeType = NtfsAttributeType.Any; ushort currentAttributeNumber = ushort.MaxValue; ListEntry * scannedEntry; for (uint offset = 0; offset < listLength; offset += scannedEntry->EntryLength) { scannedEntry = (ListEntry *)((byte *)listBase + offset); if ((currentAttributeNumber == scannedEntry->AttributeNumber) && (currentAttributeType == scannedEntry->AttributeType)) { // The entry is a continuation of the previous one. Ignore it. It should // have been processed by a previous loop if required. continue; } currentAttributeNumber = scannedEntry->AttributeNumber; currentAttributeType = scannedEntry->AttributeType; if ((NtfsAttributeType.Any != searchedAttributeType) && (scannedEntry->AttributeType != searchedAttributeType)) { // This entry doesn't match the search criteria on attribute type. continue; } EntryListReferencedAttributeHandlerDelegate attributeDataHandler; bool includeData; if (!listEntryHandler(scannedEntry, out attributeDataHandler, out includeData)) { // The callback doesn't wish to continue with other list entries. return; } if (null == attributeDataHandler) { // The callback doesn't wish to retrieve the attribute itself for the // currently scanned entry. continue; } // The last callback invocation decided it needs some data from the attribute // itself before deciding what to do. if (!HandleEntryReferencedAttribute(scannedEntry, listLength - offset, attributeDataHandler, includeData)) { return; } } } finally { if (null != listAttributeData) { listAttributeData.Dispose(); } } }
/// <summary>The caller enumerating entries might be interested in the content of /// the currently scanned entry. This might be either for additional filtering at /// attribute level (including attribute name) or for full attribute data processing. /// </summary> /// <param name="entry">The scanned list entry of interest. Should a single /// attribute span several entries, this one is guaranteed to be the first one for the /// attribute.</param> /// <param name="remainingBytesInList">Number of bytes remaining in list, relatively to the /// entry address.</param> /// <param name="entryReferencedAttributeHandler">The callback that will be invoked /// with the referenced attribute with or without full attribute data depending on /// the value of <paramref name="dataIncluded"/></param> /// <param name="dataIncluded"></param> /// <returns>true if caller should continue process data, false if it should stop.</returns> private static unsafe bool HandleEntryReferencedAttribute(ListEntry *entry, uint remainingBytesInList, EntryListReferencedAttributeHandlerDelegate entryReferencedAttributeHandler, bool dataIncluded) { ushort currentAttributeNumber = entry->AttributeNumber; NtfsAttributeType currentAttributeType = entry->AttributeType; byte * baseAddress = (byte *)entry; uint relativeOffset = 0; // The last callback invocation decided it needs some more data before deciding // what to do. IPartitionClusterData clusterData = null; NtfsPartition currentPartition = NtfsPartition.Current; using (PartitionDataDisposableBatch batch = PartitionDataDisposableBatch.CreateNew()) { while (true) { ListEntry * scannedEntry = (ListEntry *)baseAddress; ulong mainFileReferenceNumber = entry->FileReferenceNumber; List <ulong> entries = new List <ulong>(); Stream dataStream = null; if (dataIncluded) { // Read each record and prepare for data retrieval. while (true) { entries.Add(scannedEntry->FileReferenceNumber); relativeOffset += scannedEntry->EntryLength; if (relativeOffset >= remainingBytesInList) { // Take care not to go further than the end of the list. break; } scannedEntry = (ListEntry *)(baseAddress + relativeOffset); if ((currentAttributeNumber != scannedEntry->AttributeNumber) || (currentAttributeType != scannedEntry->AttributeType)) { break; } } dataStream = new MultiRecordAttributeDataStream(entries); } // Retrieve attribute itself. NtfsFileRecord *mainFileRecord = currentPartition.GetFileRecord(mainFileReferenceNumber, ref clusterData); if (null == mainFileRecord) { throw new ApplicationException(); } NtfsAttribute *retrievedAttribute = (NtfsAttribute *)((byte *)mainFileRecord + mainFileRecord->AttributesOffset); // Invoke callback. bool retry; if (!entryReferencedAttributeHandler(retrievedAttribute, dataStream, out retry)) { // After attribute has been processed, it has been decided no other list // entry should be performed. return(false); } if (!retry) { // After attribute has been processed, it has been decided that no // additional data from this attribute is required. However the enumeration // of other list entries should continue. return(true); } if (dataIncluded) { throw new InvalidOperationException(); } // Attribute has been processed, however not enough data was available for a // final decision. We loop and include all data now. dataIncluded = true; } } }
private unsafe void _Run() { NtfsPartition partition = Partition; IPartitionClusterData clusterData = null; try { // Note : We could also use the NtfsWellKnownMetadataFiles.Extend entry to // locate the directory, then find the $UsnJrnl entry directly from there. string fileName = @"$UsnJrnl"; NtfsIndexEntryHeader *fileDescriptor = partition.FindFile(fileName, NtfsWellKnownMetadataFiles.Extend); if (null == fileDescriptor) { throw new System.IO.FileNotFoundException(fileName); } IPartitionClusterData fileData = null; try { NtfsFileRecord *fileRecord = partition.GetFileRecord(fileDescriptor->FileReference, ref fileData); fileRecord->AssertRecordType(); // We retrieve the first attribute here. Stream dataStream; NtfsAttribute *jAttribute = fileRecord->GetAttribute(NtfsAttributeType.AttributeData, out dataStream, 1, _isDollarJAttributeNameFilter); if (null == jAttribute) { throw new ApplicationException(); } if (jAttribute->IsResident) { // Seems this is never the case. throw new NotSupportedException("CODE REVIEW REQUIRED"); } NtfsNonResidentAttribute *jNrAttribute = (NtfsNonResidentAttribute *)jAttribute; jNrAttribute->Dump(); byte[] buffer = new byte[NtfsPartition.Current.ClusterSize]; DateTime sparseReadStartTime = DateTime.UtcNow; TimeSpan sparseReadDuration; if (null == dataStream) { dataStream = jNrAttribute->OpenDataStream(); throw new ApplicationException("CODE REVIEW REQUIRED"); } int totalReads = 0; bool nonNullByteFound = false; while (true) { int readCount = dataStream.Read(buffer, 0, buffer.Length); if (-1 == readCount) { sparseReadDuration = DateTime.UtcNow - sparseReadStartTime; break; } if (nonNullByteFound) { for (int index = 0; index < readCount; index++) { if (0 == buffer[index]) { continue; } sparseReadDuration = DateTime.UtcNow - sparseReadStartTime; Console.WriteLine("{0} null leading bytes found after {1} secs.", totalReads + index, (int)sparseReadDuration.TotalSeconds); nonNullByteFound = true; break; } } totalReads += readCount; if (nonNullByteFound) { Helpers.BinaryDump(buffer, (uint)readCount); } } if (!nonNullByteFound) { sparseReadDuration = DateTime.UtcNow - sparseReadStartTime; Console.WriteLine("{0} null leading bytes found after {1} secs.", totalReads, (int)sparseReadDuration.TotalSeconds); } throw new NotImplementedException(); NtfsAttribute *rawAttribute = fileRecord->GetAttribute(NtfsAttributeType.AttributeData, out dataStream, 1); if (null == rawAttribute) { throw new ApplicationException(); } if ("$Max" != rawAttribute->Name) { throw new ApplicationException(); } if (rawAttribute->IsResident) { NtfsResidentAttribute *reMaxAttribute = (NtfsResidentAttribute *)rawAttribute; if (FeaturesContext.InvariantChecksEnabled) { if (0x20 != reMaxAttribute->ValueLength) { throw new ApplicationException(); } } MaxAttribute *maxAttribute = (MaxAttribute *)((byte *)reMaxAttribute + reMaxAttribute->ValueOffset); } else { throw new NotSupportedException(); } rawAttribute = fileRecord->GetAttribute(NtfsAttributeType.AttributeData, out dataStream, 2); if (null == rawAttribute) { throw new ApplicationException(); } if ("$J" != rawAttribute->Name) { throw new ApplicationException(); } throw new NotImplementedException(); } finally { if (null != fileData) { fileData.Dispose(); } } } finally { if (null != clusterData) { clusterData.Dispose(); } } }