-/* $Id: dirobj.c,v 1.9 2000/10/22 16:36:52 ekohl Exp $
+/* $Id: dirobj.c,v 1.14 2002/03/17 17:51:33 hbirr Exp $
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* 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
*
* 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;
+
+
+ DPRINT("NtQueryDirectoryObject(DirObjHandle %x)\n", DirObjHandle);
- Status = ObReferenceObjectByHandle(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.
+ */
+ if (FALSE == ReturnSingleEntry)
+ {
+ for ( current_entry = dir->head.Flink;
+ (current_entry != & dir->head);
+ current_entry = current_entry->Flink
+ )
+ {
+ ++ DirectoryCount;
+ }
+ }
+ else
+ {
+ DirectoryCount = 1;
+ }
+ // count is DirectoryCount + one null entry
+ 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_NO_MORE_ENTRIES);
}
- }
- 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);
-
+ }
+ /*
+ * 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);
-
- 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);
+ /*
+ * 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 + 1) * sizeof (WCHAR)
+ + (TypeNameLength + 1) * 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 += DirectoryCount;
+ /*
+ * Report to the caller how much bytes
+ * we wrote in the user buffer.
+ */
+ if (NULL != DataWritten)
+ {
+ *DataWritten = (BufferLength - SpaceLeft);
+ }
+ return (STATUS_SUCCESS);
}
* RETURN VALUE
* Status.
*/
-NTSTATUS STDCALL NtCreateDirectoryObject (PHANDLE DirectoryHandle,
- ACCESS_MASK DesiredAccess,
- POBJECT_ATTRIBUTES ObjectAttributes)
+NTSTATUS STDCALL
+NtCreateDirectoryObject(PHANDLE DirectoryHandle,
+ ACCESS_MASK DesiredAccess,
+ POBJECT_ATTRIBUTES ObjectAttributes)
{
PDIRECTORY_OBJECT dir;
DirectoryHandle, DesiredAccess, ObjectAttributes,
ObjectAttributes->ObjectName);
- dir = ObCreateObject(DirectoryHandle,
- DesiredAccess,
- ObjectAttributes,
- ObDirectoryType);
- return(STATUS_SUCCESS);
+ return(ObCreateObject(DirectoryHandle,
+ DesiredAccess,
+ ObjectAttributes,
+ ObDirectoryType,
+ (PVOID*)&dir));
}
/* EOF */