Esempio n. 1
0
        internal static unsafe ulong CountAttributes(NtfsFileRecord *record)
        {
            ulong          result           = 0;
            NtfsAttribute *scannedAttribute = (NtfsAttribute *)((byte *)record + record->AttributesOffset);

            while (!scannedAttribute->IsLast)
            {
                result++;
                scannedAttribute = (NtfsAttribute *)((byte *)scannedAttribute + scannedAttribute->Length);
            }
            return(result);
        }
Esempio n. 2
0
        internal unsafe void BinaryDumpContent()
        {
            Stream attributeDataStream = null;

            try {
                NtfsAttribute *dataAttribute = GetAttribute(NtfsAttributeType.AttributeData,
                                                            out attributeDataStream);
                if (null == dataAttribute)
                {
                    throw new ApplicationException();
                }
                if (dataAttribute->IsResident)
                {
                    NtfsResidentAttribute *realDataAttribute = (NtfsResidentAttribute *)dataAttribute;
                    Helpers.BinaryDump((byte *)realDataAttribute + realDataAttribute->ValueOffset,
                                       realDataAttribute->ValueLength);
                }
                else
                {
                    NtfsNonResidentAttribute *realDataAttribute = (NtfsNonResidentAttribute *)dataAttribute;
                    byte[] localBuffer = new byte[16 * 1024];
                    fixed(byte *pBuffer = localBuffer)
                    {
                        if (null == attributeDataStream)
                        {
                            attributeDataStream = realDataAttribute->OpenDataStream();
                        }
                        while (true)
                        {
                            int readLength = attributeDataStream.Read(localBuffer, 0, localBuffer.Length);
                            if (-1 == readLength)
                            {
                                break;
                            }
                            Helpers.BinaryDump(pBuffer, (uint)readLength);
                            if (readLength < localBuffer.Length)
                            {
                                break;
                            }
                        }
                    }
                }
            }
            finally {
                if (null != attributeDataStream)
                {
                    attributeDataStream.Close();
                }
            }
        }
Esempio n. 3
0
 private unsafe bool HandleData(NtfsAttribute *candidateAttribute, Stream attributeData, out bool retry)
 {
     if (null != attributeData)
     {
         retry = false;
         // Delegate the continuation decision to our caller.
         return(_callback(candidateAttribute, attributeData));
     }
     if ((null != _nameFilter) && !_nameFilter(candidateAttribute))
     {
         // The name filter failed. Go on with next entry.
         retry = false;
         return(true);
     }
     // The caller is interested in the attribute, either because there is no
     // name filter. We want the full data.
     retry = true;
     // We will land in the conditional block above.
     return(true);
 }
Esempio n. 4
0
        /// <summary>Retrieve the Nth attribute of a given kind from a file record.</summary>
        /// <param name="kind">Searched attribute type.</param>
        /// <param name="dataStream">On return this parameter value is a null reference most of
        /// the time. Otherwise for attributes that are retrieved from an
        /// <see cref="NtfsAttributeListAttribute"/> instance, this is a stream that support
        /// attribute data content reading.</param>
        /// <param name="order">Attribute rank. Default is first. This is usefull for some kind of
        /// attributes such as Data one that can appear several times in a record.</param>
        /// <param name="nameFilter">An optional name filter delegate that will sort out those
        /// attributes we want to retrieve based on their name.</param>
        /// <returns>The retrieved attribute or a null reference if not found.</returns>
        internal unsafe NtfsAttribute *GetAttribute(NtfsAttributeType kind, out Stream dataStream,
                                                    uint order = 1, AttributeNameFilterDelegate nameFilter = null)
        {
            NtfsAttribute *result = null;
            Stream         retrievedDataStream = null;

            EnumerateRecordAttributes(delegate(NtfsAttribute * found, Stream attributeDataStream) {
                if (kind == found->AttributeType)
                {
                    if (0 == --order)
                    {
                        result = found;
                        retrievedDataStream = attributeDataStream;
                        return(false);
                    }
                }
                return(true);
            },
                                      kind, nameFilter);
            dataStream = retrievedDataStream;
            return(result);
        }
Esempio n. 5
0
        /// <summary>Enumerate attributes bound to this <see cref="NtfsFileRecord"/>, optionally filtering
        /// on attribute name.</summary>
        /// <param name="header">The file record.</param>
        /// <param name="callback"></param>
        /// <param name="searchedAttributeType"></param>
        /// <param name="nameFilter">An optional name filter that will be provided with the basic attribute
        /// properties (including name) in order to decide if data should be retrieved. This is especially
        /// usefull for <see cref="NtfsAttributeListAttribute"/> attributes that may reference lengthy
        /// attributes data which are expensive to retrieve.</param>
        internal static unsafe void EnumerateRecordAttributes(NtfsFileRecord *header,
                                                              RecordAttributeEnumeratorCallbackDelegate callback, NtfsAttributeType searchedAttributeType,
                                                              AttributeNameFilterDelegate nameFilter)
        {
            // Walk attributes, seeking for the searched one.
            NtfsAttribute *currentAttribute = (NtfsAttribute *)((byte *)header + header->AttributesOffset);
            NtfsAttributeListAttribute *pendingAttributeList = null;

            NtfsAttribute *[] candidates = new NtfsAttribute *[MaxAttributeCount];
            int candidatesCount          = 0;

            for (int attributeIndex = 0; attributeIndex < header->NextAttributeNumber; attributeIndex++)
            {
                if (currentAttribute->IsLast)
                {
                    break;
                }
                if (header->BytesInUse < ((byte *)currentAttribute - (byte *)header))
                {
                    break;
                }
                if (NtfsAttributeType.EndOfListMarker == currentAttribute->AttributeType)
                {
                    break;
                }
                // If we found an AttributeListAttribute, we must go one level deeper to
                // complete the enumeration.
                if (NtfsAttributeType.AttributeAttributeList == currentAttribute->AttributeType)
                {
                    if (null != pendingAttributeList)
                    {
                        // No more than one attribute of this kind per file record.
                        throw new ApplicationException();
                    }
                    if (NtfsAttributeType.AttributeAttributeList == searchedAttributeType)
                    {
                        if (!callback(currentAttribute, null))
                        {
                            return;
                        }
                    }
                    // Defer handling
                    pendingAttributeList = (NtfsAttributeListAttribute *)currentAttribute;
                    break;
                }
                if (candidatesCount >= MaxAttributeCount)
                {
                    throw new ApplicationException();
                }
                if ((NtfsAttributeType.Any == searchedAttributeType) ||
                    (currentAttribute->AttributeType == searchedAttributeType))
                {
                    candidates[candidatesCount++] = currentAttribute;
                }
                currentAttribute = (NtfsAttribute *)((byte *)currentAttribute + currentAttribute->Length);
            }
            if (NtfsAttributeType.AttributeAttributeList == searchedAttributeType)
            {
                // Either we already found one such attribute and invoked the callback or found none and
                // we can return immediately. Should we have found several such attributes we would have
                // risen an exception.
                return;
            }
            if (null == pendingAttributeList)
            {
                // We already walked every attributes and captured those that matched the type filter if
                // any. Invoke callbak on each such attribute.
                for (int candidateIndex = 0; candidateIndex < candidatesCount; candidateIndex++)
                {
                    if (!callback(candidates[candidateIndex], null))
                    {
                        return;
                    }
                }
                // We are done.
                return;
            }
            NtfsAttributeListAttribute.Dump(pendingAttributeList);
            // HandleAttributeListAttributeEntry
            // We have an attribute list attribute. Delegate him the enumeration.
            NtfsPartition currentPartition = NtfsPartition.Current;

            NtfsAttributeListAttribute.EnumerateEntries((NtfsAttribute *)pendingAttributeList, searchedAttributeType,
                                                        new ListEntryHandler(searchedAttributeType, nameFilter, callback).HandleListEntry);
            return;
        }
        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();
                }
            }
        }
        private static unsafe bool IsDollarJAttribute(NtfsAttribute *candidate)
        {
            bool isJAttribute = "$J" == candidate->Name;

            return(isJAttribute);
        }
        /// <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;
                }
            }
        }
        /// <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();
                }
            }
        }