NtQueryDirectoryObject rewritten.

apps/objdir.c fixed to work under nt4sp6a AND reactos.

svn path=/trunk/; revision=1847
This commit is contained in:
Emanuele Aliberti
2001-05-01 21:43:45 +00:00
parent 1afd43b049
commit 8d5c635a36
2 changed files with 228 additions and 151 deletions
+56 -31
View File
@@ -1,4 +1,4 @@
/* $Id: objdir.c,v 1.5 2000/08/11 17:18:31 ea Exp $
/* $Id: objdir.c,v 1.6 2001/05/01 21:43:45 ea Exp $
*
* DESCRIPTION: Object Manager Simple Explorer
* PROGRAMMER: David Welch
@@ -9,6 +9,10 @@
* 2000-08-11 (ea)
* Added symbolic link expansion.
* (tested under nt4sp4/x86)
* 2001-05-01 (ea)
* Fixed entries counter. Added more
* error codes check. Removed wprintf,
* because it does not work in .17.
*/
#include <ddk/ntddk.h>
@@ -17,9 +21,24 @@
#include <stdio.h>
#include <stdlib.h>
BYTE DirectoryEntry [(2 * MAX_PATH) + sizeof (OBJDIR_INFORMATION)];
BYTE DirectoryEntry [32768];
POBJDIR_INFORMATION pDirectoryEntry = (POBJDIR_INFORMATION) DirectoryEntry;
static
PCHAR
STDCALL
RawUszAsz (
PWCHAR szU,
PCHAR szA
)
{
register PCHAR a = szA;
while (*szU) {*szA++ = (CHAR) (0x00ff & * szU++);}
*szA = '\0';
return a;
}
static
const char *
@@ -40,6 +59,10 @@ StatusToName (NTSTATUS Status)
return "STATUS_OBJECT_NAME_NOT_FOUND";
case STATUS_PATH_SYNTAX_BAD:
return "STATUS_PATH_SYNTAX_BAD";
case STATUS_NO_MORE_ENTRIES:
return "STATUS_NO_MORE_ENTRIES";
case STATUS_UNSUCCESSFUL:
return "STATUS_UNSUCCESSFUL";
}
sprintf (RawValue, "0x%08lx", Status);
return (const char *) RawValue;
@@ -127,7 +150,8 @@ int main(int argc, char* argv[])
OBJECT_ATTRIBUTES ObjectAttributes;
NTSTATUS Status;
HANDLE DirectoryHandle;
ULONG BytesReturned = 0;
ULONG Context = 0;
ULONG ReturnLength = 0;
ULONG EntryCount = 0;
/* For expanding symbolic links */
@@ -187,6 +211,7 @@ int main(int argc, char* argv[])
);
return EXIT_FAILURE;
}
printf ("\n Directory of %s\n\n", argv[1]);
/*
* Enumerate each item in the directory.
*/
@@ -194,10 +219,10 @@ int main(int argc, char* argv[])
DirectoryHandle,
pDirectoryEntry,
sizeof DirectoryEntry,
TRUE,
TRUE,
& BytesReturned,
& EntryCount
FALSE,/* ReturnSingleEntry */
TRUE, /* RestartScan */
& Context,
& ReturnLength
);
if (!NT_SUCCESS(Status))
{
@@ -208,9 +233,12 @@ int main(int argc, char* argv[])
NtClose (DirectoryHandle);
return EXIT_FAILURE;
}
wprintf (L"%d entries:\n", EntryCount);
while (STATUS_NO_MORE_ENTRIES != Status)
while (0 != pDirectoryEntry->ObjectTypeName.Length)
{
CHAR ObjectNameA [MAX_PATH];
CHAR TypeNameA [MAX_PATH];
CHAR TargetNameA [MAX_PATH];
if (0 == wcscmp (L"SymbolicLink", pDirectoryEntry->ObjectTypeName.Buffer))
{
if (TRUE == ExpandSymbolicLink (
@@ -220,40 +248,37 @@ int main(int argc, char* argv[])
)
)
{
wprintf (
L"%-16s %s -> %s\n",
pDirectoryEntry->ObjectTypeName.Buffer,
pDirectoryEntry->ObjectName.Buffer,
TargetObjectName.Buffer
printf (
"%-16s %s -> %s\n",
RawUszAsz (pDirectoryEntry->ObjectTypeName.Buffer, TypeNameA),
RawUszAsz (pDirectoryEntry->ObjectName.Buffer, ObjectNameA),
RawUszAsz (TargetObjectName.Buffer, TargetNameA)
);
}
else
{
wprintf (
L"%-16s %s -> (error!)\n",
pDirectoryEntry->ObjectTypeName.Buffer,
pDirectoryEntry->ObjectName.Buffer
printf (
"%-16s %s -> (error!)\n",
RawUszAsz (pDirectoryEntry->ObjectTypeName.Buffer, TypeNameA),
RawUszAsz (pDirectoryEntry->ObjectName.Buffer, ObjectNameA)
);
}
}
else
{
wprintf (
L"%-16s %s\n",
pDirectoryEntry->ObjectTypeName.Buffer,
pDirectoryEntry->ObjectName.Buffer
printf (
"%-16s %s\n",
RawUszAsz (pDirectoryEntry->ObjectTypeName.Buffer, TypeNameA),
RawUszAsz (pDirectoryEntry->ObjectName.Buffer, ObjectNameA)
);
}
Status = NtQueryDirectoryObject (
DirectoryHandle,
pDirectoryEntry,
sizeof DirectoryEntry,
TRUE,
FALSE,
& BytesReturned,
& EntryCount
);
++ EntryCount;
++ pDirectoryEntry;
}
printf ("\n\t%d object(s)\n", EntryCount);
/*
* Free any resource.
*/
+172 -120
View File
@@ -1,4 +1,4 @@
/* $Id: dirobj.c,v 1.9 2000/10/22 16:36:52 ekohl Exp $
/* $Id: dirobj.c,v 1.10 2001/05/01 21:43:45 ea Exp $
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
@@ -81,29 +81,32 @@ NTSTATUS STDCALL NtOpenDirectoryObject(PHANDLE DirectoryHandle,
* NtQueryDirectoryObject
*
* DESCRIPTION
* Reads information from a namespace directory.
* Reads information from a directory in the system namespace.
*
* ARGUMENTS
* DirObjHandle
* Handle, obtained with NtOpenDirectoryObject(), which
* must grant DIRECTORY_QUERY access to the directory
* object.
*
* DirObjInformation (OUT)
* Buffer to hold the data read.
*
* BufferLength
* Size of the buffer in bytes.
*
* GetNextIndex
* If TRUE then set ObjectIndex to the index of the
* next object.
* If FALSE then set ObjectIndex to the number of
* objects in the directory.
* ReturnSingleEntry
* When TRUE, only 1 entry is written in DirObjInformation;
* otherwise as many as will fit in the buffer.
*
* IgnoreInputIndex
* RestartScan
* If TRUE start reading at index 0.
* If FALSE start reading at the index specified
* by object index.
* by object index *ObjectIndex.
*
* ObjectIndex
* Zero based index into the directory, interpretation
* depends on IgnoreInputIndex and GetNextIndex.
* depends on RestartScan.
*
* DataWritten (OUT)
* Caller supplied storage for the number of bytes
@@ -111,134 +114,183 @@ NTSTATUS STDCALL NtOpenDirectoryObject(PHANDLE DirectoryHandle,
*
* RETURN VALUE
* Status.
*
* REVISIONS
* 2001-05-01 (ea)
* Changed 4th, and 5th parameter names after
* G.Nebbett "WNT/W2k Native API Reference".
* Mostly rewritten.
*/
NTSTATUS STDCALL NtQueryDirectoryObject (IN HANDLE DirObjHandle,
OUT POBJDIR_INFORMATION
DirObjInformation,
IN ULONG BufferLength,
IN BOOLEAN GetNextIndex,
IN BOOLEAN IgnoreInputIndex,
IN BOOLEAN ReturnSingleEntry,
IN BOOLEAN RestartScan,
IN OUT PULONG ObjectIndex,
OUT PULONG DataWritten OPTIONAL)
{
PDIRECTORY_OBJECT dir = NULL;
PLIST_ENTRY current_entry;
POBJECT_HEADER current;
ULONG i = 0;
ULONG EntriesToSkip;
NTSTATUS Status;
ULONG SpaceRequired;
ULONG FirstFree;
DPRINT("NtQueryDirectoryObject(DirObjHandle %x)\n", DirObjHandle);
PDIRECTORY_OBJECT dir = NULL;
PLIST_ENTRY current_entry = NULL;
POBJECT_HEADER current = NULL;
ULONG i = 0;
NTSTATUS Status = STATUS_SUCCESS;
DWORD DirectoryCount = 0;
DWORD DirectorySize = 0;
ULONG SpaceLeft = BufferLength;
ULONG SpaceRequired = 0;
ULONG NameLength = 0;
ULONG TypeNameLength = 0;
POBJDIR_INFORMATION current_odi = DirObjInformation;
PBYTE FirstFree = (PBYTE) DirObjInformation;
Status = ObReferenceObjectByHandle(DirObjHandle,
DPRINT("NtQueryDirectoryObject(DirObjHandle %x)\n", DirObjHandle);
/* FIXME: if previous mode == user, use ProbeForWrite
* on user params. */
/* Reference the DIRECTORY_OBJECT */
Status = ObReferenceObjectByHandle(DirObjHandle,
DIRECTORY_QUERY,
ObDirectoryType,
UserMode,
(PVOID*)&dir,
NULL);
if (!NT_SUCCESS(Status))
{
return(Status);
}
/*
* Optionally, skip over some entries at the start of the directory
*/
if (!IgnoreInputIndex)
{
if (!NT_SUCCESS(Status))
{
return (Status);
}
/* Check ObjectIndex is not NULL */
if (NULL == ObjectIndex)
{
return (STATUS_INVALID_PARAMETER);
}
/*
* Compute the number of directory entries
* and the size of the array (in bytes).
* One more entry marks the end of the array.
*/
for ( current_entry = dir->head.Flink;
(current_entry != & dir->head);
current_entry = current_entry->Flink
)
{
++ DirectoryCount;
}
DirectorySize = (DirectoryCount + 1) * sizeof (OBJDIR_INFORMATION);
if (DirectorySize >= SpaceLeft)
{
return (STATUS_BUFFER_TOO_SMALL);
}
/*
* Optionally, skip over some entries at the start of the directory
* (use *ObjectIndex value)
*/
current_entry = dir->head.Flink;
if (FALSE == RestartScan)
{
/* RestartScan == FALSE */
register ULONG EntriesToSkip = *ObjectIndex;
CHECKPOINT;
EntriesToSkip = *ObjectIndex;
i = 0;
current_entry = dir->head.Flink;
while ((i < EntriesToSkip) && (current_entry != &dir->head))
for ( ;
((EntriesToSkip ++) && (current_entry != & dir->head));
current_entry = current_entry->Flink
);
if ((EntriesToSkip) && (current_entry == & dir->head))
{
current_entry = current_entry->Flink;
i++;
return (STATUS_INVALID_PARAMETER);
}
}
else
{
current_entry = dir->head.Flink;
i = 0;
}
/*
* Check if we have reached the end of the directory
*/
if (current_entry != &dir->head)
{
*DataWritten = 0;
return(STATUS_NO_MORE_ENTRIES);
}
/*
* Read the current entry into the buffer
*/
FirstFree = sizeof(OBJDIR_INFORMATION);
current = CONTAINING_RECORD(current_entry, OBJECT_HEADER, Entry);
SpaceRequired = (wcslen(current->Name.Buffer) + 1) * 2;
SpaceRequired = SpaceRequired +
((wcslen(current->ObjectType->TypeName.Buffer) + 1) * 2);
SpaceRequired = SpaceRequired + sizeof(OBJDIR_INFORMATION);
if (SpaceRequired <= BufferLength)
{
DirObjInformation->ObjectName.Length =
current->Name.Length;
DirObjInformation->ObjectName.MaximumLength =
current->Name.Length;
DirObjInformation->ObjectName.Buffer =
(((PVOID)DirObjInformation) + FirstFree);
FirstFree = FirstFree + (wcslen(current->Name.Buffer + 1) * 2);
wcscpy(DirObjInformation->ObjectName.Buffer,
current->Name.Buffer);
DirObjInformation->ObjectTypeName.Length =
current->ObjectType->TypeName.Length;
DirObjInformation->ObjectTypeName.MaximumLength =
current->ObjectType->TypeName.Length;
DirObjInformation->ObjectName.Buffer =
(((PVOID)DirObjInformation) + FirstFree);
FirstFree = FirstFree +
(wcslen(current->ObjectType->TypeName.Buffer + 1) * 2);
wcscpy(DirObjInformation->ObjectTypeName.Buffer,
current->ObjectType->TypeName.Buffer);
*DataWritten = SpaceRequired;
Status = STATUS_SUCCESS;
}
else
{
Status = STATUS_BUFFER_TOO_SMALL;
}
/*
* Store into ObjectIndex
*/
if (GetNextIndex)
{
*ObjectIndex = i + 1;
}
else
{
i = 0;
current_entry = dir->head.Flink;
while (current_entry != (&dir->head))
{
current_entry = current_entry->Flink;
i++;
}
*ObjectIndex = i;
}
return(STATUS_SUCCESS);
}
/*
* Initialize the array of OBJDIR_INFORMATION.
*/
RtlZeroMemory (FirstFree, DirectorySize);
/*
* Move FirstFree to point to the Unicode strings area
*/
FirstFree += DirectorySize;
/*
* Compute how much space is left after allocating the
* array in the user buffer.
*/
SpaceLeft -= DirectorySize;
/* Scan the directory */
do {
/*
* Check if we reached the end of the directory.
*/
if (current_entry == & dir->head)
{
/* Any data? */
if (i) break; /* DONE */
/* FIXME: better error handling here! */
return (STATUS_NO_MORE_ENTRIES);
}
/*
* Compute the current OBJECT_HEADER memory
* object's address.
*/
current = CONTAINING_RECORD(current_entry, OBJECT_HEADER, Entry);
/*
* Compute the space required in the user buffer to copy
* the data from the current object:
*
* Name (WCHAR) 0 TypeName (WCHAR) 0
*/
NameLength = (wcslen (current->Name.Buffer) * sizeof (WCHAR));
TypeNameLength = (wcslen (current->ObjectType->TypeName.Buffer) * sizeof (WCHAR));
SpaceRequired =
(NameLength + sizeof (WCHAR))
+ (TypeNameLength + sizeof (WCHAR));
/*
* Check for free space in the user buffer.
*/
if (SpaceRequired >= SpaceLeft)
{
return (STATUS_BUFFER_TOO_SMALL);
}
/*
* Copy the current directory entry's data into the buffer
* and update the OBJDIR_INFORMATION entry in the array.
*/
/* --- Object's name --- */
current_odi->ObjectName.Length = NameLength;
current_odi->ObjectName.MaximumLength = (NameLength + sizeof (WCHAR));
current_odi->ObjectName.Buffer = (PWCHAR) FirstFree;
wcscpy ((PWCHAR) FirstFree, current->Name.Buffer);
FirstFree += (current_odi->ObjectName.MaximumLength);
/* --- Object type's name --- */
current_odi->ObjectTypeName.Length = TypeNameLength;
current_odi->ObjectTypeName.MaximumLength = (TypeNameLength + sizeof (WCHAR));
current_odi->ObjectTypeName.Buffer = (PWCHAR) FirstFree;
wcscpy ((PWCHAR) FirstFree, current->ObjectType->TypeName.Buffer);
FirstFree += (current_odi->ObjectTypeName.MaximumLength);
/* Next entry in the array */
++ current_odi;
/* Decrease the space left count */
SpaceLeft -= SpaceRequired;
/* Increase the object index number */
++ i;
/* Next object in the directory */
current_entry = current_entry->Flink;
} while (FALSE == ReturnSingleEntry);
/*
* Store current index in ObjectIndex
*/
*ObjectIndex = i;
/*
* Report to the caller how much bytes
* we wrote in the user buffer.
*/
if (NULL != DataWritten)
{
*DataWritten = (BufferLength - SpaceLeft);
}
return (STATUS_SUCCESS);
}