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>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; }
internal static unsafe void Dump(NtfsAttributeListAttribute *from) { _Dump(from, delegate(ListEntry * entry) { entry->Dump(); }); }