+static
+NTSTATUS
+InternalReadNonResidentAttributes(PFIND_ATTR_CONTXT Context)
+{
+ ULONGLONG ListSize;
+ PNTFS_ATTR_RECORD Attribute;
+ PNTFS_ATTR_CONTEXT ListContext;
+
+ DPRINT("InternalReadNonResidentAttributes(%p)\n", Context);
+
+ Attribute = Context->CurrAttr;
+ ASSERT(Attribute->Type == AttributeAttributeList);
+
+ if (Context->OnlyResident)
+ {
+ Context->NonResidentStart = NULL;
+ Context->NonResidentEnd = NULL;
+ return STATUS_SUCCESS;
+ }
+
+ if (Context->NonResidentStart != NULL)
+ {
+ return STATUS_FILE_CORRUPT_ERROR;
+ }
+
+ ListContext = PrepareAttributeContext(Attribute);
+ ListSize = AttributeDataLength(&ListContext->Record);
+ if (ListSize > 0xFFFFFFFF)
+ {
+ ReleaseAttributeContext(ListContext);
+ return STATUS_BUFFER_OVERFLOW;
+ }
+
+ Context->NonResidentStart = ExAllocatePoolWithTag(NonPagedPool, (ULONG)ListSize, TAG_NTFS);
+ if (Context->NonResidentStart == NULL)
+ {
+ ReleaseAttributeContext(ListContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ if (ReadAttribute(Context->Vcb, ListContext, 0, (PCHAR)Context->NonResidentStart, (ULONG)ListSize) != ListSize)
+ {
+ ExFreePoolWithTag(Context->NonResidentStart, TAG_NTFS);
+ Context->NonResidentStart = NULL;
+ ReleaseAttributeContext(ListContext);
+ return STATUS_FILE_CORRUPT_ERROR;
+ }
+
+ ReleaseAttributeContext(ListContext);
+ Context->NonResidentEnd = (PNTFS_ATTR_RECORD)((PCHAR)Context->NonResidentStart + ListSize);
+ return STATUS_SUCCESS;
+}
+
+static
+PNTFS_ATTR_RECORD
+InternalGetNextAttribute(PFIND_ATTR_CONTXT Context)
+{
+ if (Context->CurrAttr == (PVOID)-1)
+ {
+ return NULL;
+ }
+
+ if (Context->CurrAttr >= Context->FirstAttr &&
+ Context->CurrAttr < Context->LastAttr)
+ {
+ if (Context->CurrAttr->Length == 0)
+ {
+ DPRINT1("Broken length!\n");
+ Context->CurrAttr = (PVOID)-1;
+ return NULL;
+ }
+
+ Context->CurrAttr = (PNTFS_ATTR_RECORD)((ULONG_PTR)Context->CurrAttr + Context->CurrAttr->Length);
+ if (Context->CurrAttr < Context->LastAttr &&
+ Context->CurrAttr->Type != AttributeEnd)
+ {
+ return Context->CurrAttr;
+ }
+ }
+
+ if (Context->NonResidentStart == NULL)
+ {
+ Context->CurrAttr = (PVOID)-1;
+ return NULL;
+ }
+
+ if (Context->CurrAttr < Context->NonResidentStart ||
+ Context->CurrAttr >= Context->NonResidentEnd)
+ {
+ Context->CurrAttr = Context->NonResidentStart;
+ }
+ else if (Context->CurrAttr->Length != 0)
+ {
+ Context->CurrAttr = (PNTFS_ATTR_RECORD)((ULONG_PTR)Context->CurrAttr + Context->CurrAttr->Length);
+ }
+ else
+ {
+ DPRINT1("Broken length!\n");
+ Context->CurrAttr = (PVOID)-1;
+ return NULL;
+ }
+
+ if (Context->CurrAttr < Context->NonResidentEnd &&
+ Context->CurrAttr->Type != AttributeEnd)
+ {
+ return Context->CurrAttr;
+ }
+
+ Context->CurrAttr = (PVOID)-1;
+ return NULL;
+}
+
+NTSTATUS
+FindFirstAttribute(PFIND_ATTR_CONTXT Context,
+ PDEVICE_EXTENSION Vcb,
+ PFILE_RECORD_HEADER FileRecord,
+ BOOLEAN OnlyResident,
+ PNTFS_ATTR_RECORD * Attribute)
+{
+ NTSTATUS Status;
+
+ DPRINT("FindFistAttribute(%p, %p, %p, %p, %u, %p)\n", Context, Vcb, FileRecord, OnlyResident, Attribute);
+
+ Context->Vcb = Vcb;
+ Context->OnlyResident = OnlyResident;
+ Context->FirstAttr = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->AttributeOffset);
+ Context->CurrAttr = Context->FirstAttr;
+ Context->LastAttr = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->BytesInUse);
+ Context->NonResidentStart = NULL;
+ Context->NonResidentEnd = NULL;
+
+ if (Context->FirstAttr->Type == AttributeEnd)
+ {
+ Context->CurrAttr = (PVOID)-1;
+ return STATUS_END_OF_FILE;
+ }
+ else if (Context->FirstAttr->Type == AttributeAttributeList)
+ {
+ Status = InternalReadNonResidentAttributes(Context);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ *Attribute = InternalGetNextAttribute(Context);
+ if (*Attribute == NULL)
+ {
+ return STATUS_END_OF_FILE;
+ }
+ }
+ else
+ {
+ *Attribute = Context->CurrAttr;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+FindNextAttribute(PFIND_ATTR_CONTXT Context,
+ PNTFS_ATTR_RECORD * Attribute)
+{
+ NTSTATUS Status;
+
+ DPRINT("FindNextAttribute(%p, %p)\n", Context, Attribute);
+
+ *Attribute = InternalGetNextAttribute(Context);
+ if (*Attribute == NULL)
+ {
+ return STATUS_END_OF_FILE;
+ }
+
+ if (Context->CurrAttr->Type != AttributeAttributeList)
+ {
+ return STATUS_SUCCESS;
+ }
+
+ Status = InternalReadNonResidentAttributes(Context);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ *Attribute = InternalGetNextAttribute(Context);
+ if (*Attribute == NULL)
+ {
+ return STATUS_END_OF_FILE;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+VOID
+FindCloseAttribute(PFIND_ATTR_CONTXT Context)
+{
+ if (Context->NonResidentStart != NULL)
+ {
+ ExFreePoolWithTag(Context->NonResidentStart, TAG_NTFS);
+ Context->NonResidentStart = NULL;
+ }
+}