CHAR TypeNameA [MAX_PATH];
CHAR TargetNameA [MAX_PATH];
- if (0 == wcscmp (L"SymbolicLink", pDirectoryEntry->ObjectTypeName.Buffer))
+ if (0 == wcscmp (L"SymbolicLink", pDirectoryEntry->TypeName.Buffer))
{
if (TRUE == ExpandSymbolicLink (
DirectoryNameW,
- & pDirectoryEntry->ObjectName,
+ & pDirectoryEntry->Name,
& TargetObjectName
)
)
printf (
"%-16s %s -> %s\n",
- RawUszAsz (pDirectoryEntry->ObjectTypeName.Buffer, TypeNameA),
- RawUszAsz (pDirectoryEntry->ObjectName.Buffer, ObjectNameA),
+ RawUszAsz (pDirectoryEntry->TypeName.Buffer, TypeNameA),
+ RawUszAsz (pDirectoryEntry->Name.Buffer, ObjectNameA),
RawUszAsz (TargetObjectName.Buffer, TargetNameA)
);
}
{
printf (
"%-16s %s -> (error!)\n",
- RawUszAsz (pDirectoryEntry->ObjectTypeName.Buffer, TypeNameA),
- RawUszAsz (pDirectoryEntry->ObjectName.Buffer, ObjectNameA)
+ RawUszAsz (pDirectoryEntry->TypeName.Buffer, TypeNameA),
+ RawUszAsz (pDirectoryEntry->Name.Buffer, ObjectNameA)
);
}
}
{
printf (
"%-16s %s\n",
- RawUszAsz (pDirectoryEntry->ObjectTypeName.Buffer, TypeNameA),
- RawUszAsz (pDirectoryEntry->ObjectName.Buffer, ObjectNameA)
+ RawUszAsz (pDirectoryEntry->TypeName.Buffer, TypeNameA),
+ RawUszAsz (pDirectoryEntry->Name.Buffer, ObjectNameA)
);
}
++ pDirectoryEntry;
if (FALSE != Recurse)
{
pDirectoryEntry = (POBJECT_DIRECTORY_INFORMATION) DirectoryEntry;
- while (0 != pDirectoryEntry->ObjectTypeName.Length)
+ while (0 != pDirectoryEntry->TypeName.Length)
{
- if (0 == wcscmp (L"Directory", pDirectoryEntry->ObjectTypeName.Buffer))
+ if (0 == wcscmp (L"Directory", pDirectoryEntry->TypeName.Buffer))
{
WCHAR CurrentName [MAX_PATH];
UNICODE_STRING CurrentDirectory;
{
wcscat (CurrentName, L"\\");
}
- wcscat (CurrentName, pDirectoryEntry->ObjectName.Buffer);
+ wcscat (CurrentName, pDirectoryEntry->Name.Buffer);
RtlInitUnicodeString (& CurrentDirectory, CurrentName);
ListDirectory (& CurrentDirectory, Recurse);
}
ULONG NextEntry = 0;
ULONG CopyBytes = 0;
NTSTATUS Status = STATUS_SUCCESS;
+ PVOID LocalBuffer;
+ POBJECT_DIRECTORY_INFORMATION DirectoryInfo;
+ ULONG Length, TotalLength;
+ ULONG Count, CurrentEntry;
+ ULONG Hash;
+ POBJECT_DIRECTORY_ENTRY Entry;
+ POBJECT_HEADER ObjectHeader;
+ POBJECT_HEADER_NAME_INFO ObjectNameInfo;
+ UNICODE_STRING Name;
PAGED_CODE();
/* Check if we need to do any probing */
SkipEntries = *Context;
}
+ /* Allocate a buffer */
+ LocalBuffer = ExAllocatePoolWithTag(PagedPool,
+ sizeof(OBJECT_DIRECTORY_INFORMATION) +
+ BufferLength,
+ OB_NAME_TAG);
+ if (!LocalBuffer) return STATUS_INSUFFICIENT_RESOURCES;
+ RtlZeroMemory(LocalBuffer, BufferLength);
+
/* Get a reference to directory */
Status = ObReferenceObjectByHandle(DirectoryHandle,
DIRECTORY_QUERY,
PreviousMode,
(PVOID*)&Directory,
NULL);
- if (NT_SUCCESS(Status))
+ if (!NT_SUCCESS(Status))
{
- PVOID TemporaryBuffer = ExAllocatePool(NonPagedPool,
- BufferLength);
- if(TemporaryBuffer != NULL)
- {
- POBJECT_HEADER EntryHeader;
- ULONG RequiredSize = sizeof(OBJECT_DIRECTORY_INFORMATION);
- ULONG nDirectories = 0;
- POBJECT_DIRECTORY_INFORMATION DirInfo = (POBJECT_DIRECTORY_INFORMATION)TemporaryBuffer;
- POBJECT_DIRECTORY_ENTRY DirectoryEntry;
- ULONG i;
- BOOLEAN StopIt = FALSE;
+ /* Free the buffer and fail */
+ ExFreePool(LocalBuffer);
+ return Status;
+ }
- Status = STATUS_NO_MORE_ENTRIES;
+ /* Start at position 0 */
+ DirectoryInfo = (POBJECT_DIRECTORY_INFORMATION)LocalBuffer;
+ TotalLength = sizeof(OBJECT_DIRECTORY_INFORMATION);
- KeEnterCriticalRegion();
- ExAcquireResourceSharedLite(&Directory->Lock, TRUE);
+ /* Start with 0 entries */
+ Count = 0;
+ CurrentEntry = 0;
- for (i = 0; i < NUMBER_HASH_BUCKETS && !StopIt; i++)
+ /* Set default status and start looping */
+ Status = STATUS_NO_MORE_ENTRIES;
+ for (Hash = 0; Hash < 37; Hash++)
+ {
+ /* Get this entry and loop all of them */
+ Entry = Directory->HashBuckets[Hash];
+ while (Entry)
+ {
+ /* Check if we should process this entry */
+ if (SkipEntries == CurrentEntry++)
{
- DirectoryEntry = Directory->HashBuckets[i];
- while (DirectoryEntry)
+ /* Get the header data */
+ ObjectHeader = OBJECT_TO_OBJECT_HEADER(Entry->Object);
+ ObjectNameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
+
+ /* Get the object name */
+ if (ObjectNameInfo)
{
- NextEntry++;
- if (SkipEntries == 0)
- {
- PUNICODE_STRING Name, Type;
- ULONG EntrySize;
-
- EntryHeader = OBJECT_TO_OBJECT_HEADER(DirectoryEntry->Object);
-
- /* Calculate the size of the required buffer space for this entry */
- Name = (OBJECT_HEADER_TO_NAME_INFO(EntryHeader)->Name.Length != 0 ? &OBJECT_HEADER_TO_NAME_INFO(EntryHeader)->Name : NULL);
- Type = &EntryHeader->Type->Name;
- EntrySize = sizeof(OBJECT_DIRECTORY_INFORMATION) +
- ((Name != NULL) ? ((ULONG)Name->Length + sizeof(WCHAR)) : 0) +
- (ULONG)EntryHeader->Type->Name.Length + sizeof(WCHAR);
-
- if (RequiredSize + EntrySize <= BufferLength)
- {
- /* The buffer is large enough to receive this entry. It would've
- been much easier if the strings were directly appended to the
- OBJECT_DIRECTORY_INFORMATION structured written into the buffer */
- if (Name != NULL && Name->Length > 0)
- DirInfo->ObjectName = *Name;
- else
- {
- DirInfo->ObjectName.Length = DirInfo->ObjectName.MaximumLength = 0;
- DirInfo->ObjectName.Buffer = NULL;
- }
- DirInfo->ObjectTypeName = *Type;
-
- nDirectories++;
- RequiredSize += EntrySize;
-
- Status = STATUS_SUCCESS;
-
- if (ReturnSingleEntry)
- {
- /* We're only supposed to query one entry, so bail and copy the
- strings to the buffer */
- StopIt = TRUE;
- break;
- }
- DirInfo++;
- }
- else
- {
- if (ReturnSingleEntry)
- {
- /* The buffer is too small, so return the number of bytes that
- would've been required for this query */
- RequiredSize += EntrySize;
- Status = STATUS_BUFFER_TOO_SMALL;
- }
-
- /* We couldn't query this entry, so leave the index that will be stored
- in Context to this entry so the caller can query it the next time
- he queries (hopefully with a buffer that is large enough then...) */
- NextEntry--;
-
- /* Just copy the entries that fit into the buffer */
- StopIt = TRUE;
- break;
- }
- }
- else
- {
- /* Skip the entry */
- SkipEntries--;
- }
- DirectoryEntry = DirectoryEntry->ChainLink;
+ /* Use the one we have */
+ Name = ObjectNameInfo->Name;
}
- }
-
- if (!ReturnSingleEntry)
- {
- /* Check if there are more entries to enumerate but the buffer is already
- full. Only tell this to the user if he queries multiple entries */
- if (DirectoryEntry)
- Status = STATUS_MORE_ENTRIES;
else
- for (; i < NUMBER_HASH_BUCKETS; i++)
- if (Directory->HashBuckets[i])
- {
- Status = STATUS_MORE_ENTRIES;
- break;
- }
- }
-
- if (NT_SUCCESS(Status) && nDirectories > 0)
- {
- PWSTR strbuf = (PWSTR)((POBJECT_DIRECTORY_INFORMATION)TemporaryBuffer + nDirectories + 1);
- PWSTR deststrbuf = (PWSTR)((POBJECT_DIRECTORY_INFORMATION)Buffer + nDirectories + 1);
- memset((POBJECT_DIRECTORY_INFORMATION)TemporaryBuffer + nDirectories, 0, sizeof(OBJECT_DIRECTORY_INFORMATION));
-
- CopyBytes = (nDirectories + 1) * sizeof(OBJECT_DIRECTORY_INFORMATION);
-
- /* Copy the names from the objects and append them to the list of the
- objects. copy to the temporary buffer only because the directory
- lock can't be released and the buffer might be pagable memory! */
- for (DirInfo = (POBJECT_DIRECTORY_INFORMATION)TemporaryBuffer;
- nDirectories > 0;
- nDirectories--, DirInfo++)
{
- ULONG NameLength;
-
- if (DirInfo->ObjectName.Length > 0)
- {
- RtlCopyMemory(strbuf,
- DirInfo->ObjectName.Buffer,
- DirInfo->ObjectName.Length);
- /* Change the buffer pointer to the buffer */
- DirInfo->ObjectName.Buffer = deststrbuf;
- NameLength = DirInfo->ObjectName.Length / sizeof(WCHAR);
- /* NULL-terminate the string */
- strbuf[NameLength] = L'\0';
- strbuf += NameLength + 1;
- deststrbuf += NameLength + 1;
-
- CopyBytes += (NameLength + 1) * sizeof(WCHAR);
- }
-
- RtlCopyMemory(strbuf,
- DirInfo->ObjectTypeName.Buffer,
- DirInfo->ObjectTypeName.Length);
- /* Change the buffer pointer to the buffer */
- DirInfo->ObjectTypeName.Buffer = deststrbuf;
- NameLength = DirInfo->ObjectTypeName.Length / sizeof(WCHAR);
- /* NULL-terminate the string */
- strbuf[NameLength] = L'\0';
- strbuf += NameLength + 1;
- deststrbuf += NameLength + 1;
-
- CopyBytes += (NameLength + 1) * sizeof(WCHAR);
+ /* Otherwise, use an empty one */
+ RtlInitEmptyUnicodeString(&Name, NULL, 0);
}
- }
- ExReleaseResourceLite(&Directory->Lock);
- KeLeaveCriticalRegion();
- ObDereferenceObject(Directory);
+ /* Calculate the length for this entry */
+ Length = sizeof(OBJECT_DIRECTORY_INFORMATION) +
+ Name.Length + sizeof(UNICODE_NULL) +
+ ObjectHeader->Type->Name.Length + sizeof(UNICODE_NULL);
- if (NT_SUCCESS(Status) || ReturnSingleEntry)
- {
- _SEH_TRY
+ /* Make sure this entry won't overflow */
+ if ((TotalLength + Length) > BufferLength)
{
- if (CopyBytes != 0)
+ /* Check if the caller wanted only an entry */
+ if (ReturnSingleEntry)
{
- RtlCopyMemory(Buffer,
- TemporaryBuffer,
- CopyBytes);
+ /* Then we'll fail and ask for more buffer */
+ TotalLength += Length;
+ Status = STATUS_BUFFER_TOO_SMALL;
}
- *Context = NextEntry;
- if(ReturnLength != NULL)
+ else
{
- *ReturnLength = RequiredSize;
+ /* Otherwise, we'll say we're done for now */
+ Status = STATUS_MORE_ENTRIES;
}
+
+ /* Decrease the entry since we didn't process */
+ CurrentEntry--;
+ goto Quickie;
}
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
- }
- ExFreePool(TemporaryBuffer);
- }
- else
- {
- Status = STATUS_INSUFFICIENT_RESOURCES;
+ /* Now fill in the buffer */
+ DirectoryInfo->Name.Length = Name.Length;
+ DirectoryInfo->Name.MaximumLength = Name.Length +
+ sizeof(UNICODE_NULL);
+ DirectoryInfo->Name.Buffer = Name.Buffer;
+ DirectoryInfo->TypeName.Length = ObjectHeader->
+ Type->Name.Length;
+ DirectoryInfo->TypeName.MaximumLength = ObjectHeader->
+ Type->Name.Length +
+ sizeof(UNICODE_NULL);
+ DirectoryInfo->TypeName.Buffer = ObjectHeader->
+ Type->Name.Buffer;
+
+ /* Increase statistics */
+ TotalLength += Length;
+ DirectoryInfo++;
+ Count++;
+
+ /* If the caller only wanted an entry, bail out */
+ if (ReturnSingleEntry) goto Quickie;
+
+ /* Increase the key by one */
+ SkipEntries++;
+ }
}
+
+ /* Move to the next directory */
+ Entry = Entry->ChainLink;
}
+Quickie:
+ /* Make sure we got success */
+ if (NT_SUCCESS(Status))
+ {
+ /* We need to parse all the entries and convert absolute to relative */
+ DPRINT1("NOT FULLY IMPLEMENTED\n");
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+
+ /* Copy the buffer */
+ RtlMoveMemory(Buffer,
+ LocalBuffer,
+ (TotalLength <= BufferLength) ?
+ TotalLength : BufferLength);
+
+ /* Check if the caller requested the return length and return it*/
+ if (ReturnLength) *ReturnLength = TotalLength;
+ }
+
+ /* Dereference the directory and free our buffer */
+ ObDereferenceObject(Directory);
+ ExFreePool(LocalBuffer);
+
/* Return status to caller */
return Status;
}