* PROJECT: ReactOS kernel
* FILE: ntoskrnl/ob/dirobj.c
* PURPOSE: Interface functions to directory object
- *
+ *
* PROGRAMMERS: David Welch (welch@mcmail.com)
*/
*
* DESCRIPTION
* Opens a namespace directory object.
- *
+ *
* ARGUMENTS
* DirectoryHandle (OUT)
* Variable which receives the directory handle.
- *
+ *
* DesiredAccess
* Desired access to the directory.
- *
+ *
* ObjectAttributes
* Structure describing the directory.
- *
+ *
* RETURN VALUE
* Status.
- *
+ *
* NOTES
* Undocumented.
*/
HANDLE hDirectory;
KPROCESSOR_MODE PreviousMode;
NTSTATUS Status = STATUS_SUCCESS;
-
+
+ PAGED_CODE();
+
PreviousMode = ExGetPreviousMode();
-
+
if(PreviousMode != KernelMode)
{
_SEH_TRY
{
- ProbeForWrite(DirectoryHandle,
- sizeof(HANDLE),
- sizeof(ULONG));
+ ProbeForWriteHandle(DirectoryHandle);
}
_SEH_HANDLE
{
Status = _SEH_GetExceptionCode();
}
_SEH_END;
-
+
if(!NT_SUCCESS(Status))
{
DPRINT1("NtOpenDirectoryObject failed, Status: 0x%x\n", Status);
return Status;
}
}
-
+
Status = ObOpenObjectByName(ObjectAttributes,
ObDirectoryType,
NULL,
}
_SEH_END;
}
-
+
return Status;
}
/**********************************************************************
* NAME EXPORTED
* NtQueryDirectoryObject
- *
+ *
* DESCRIPTION
* Reads information from a directory in the system namespace.
- *
+ *
* ARGUMENTS
* DirectoryHandle
* Handle, obtained with NtOpenDirectoryObject(), which
* must grant DIRECTORY_QUERY access to the directory
* object.
- *
+ *
* Buffer (OUT)
* Buffer to hold the data read.
- *
+ *
* BufferLength
* Size of the buffer in bytes.
- *
+ *
* ReturnSingleEntry
* When TRUE, only 1 entry is written in DirObjInformation;
* otherwise as many as will fit in the buffer.
- *
+ *
* RestartScan
* If TRUE start reading at index 0.
* If FALSE start reading at the index specified
* by object index *ObjectIndex.
- *
+ *
* Context
* Zero based index into the directory, interpretation
* depends on RestartScan.
- *
+ *
* ReturnLength (OUT)
* Caller supplied storage for the number of bytes
* written (or NULL).
KPROCESSOR_MODE PreviousMode;
ULONG SkipEntries = 0;
ULONG NextEntry = 0;
+ ULONG CopyBytes = 0;
NTSTATUS Status = STATUS_SUCCESS;
-
+
+ PAGED_CODE();
+
PreviousMode = ExGetPreviousMode();
if(PreviousMode != KernelMode)
ProbeForWrite(Buffer,
BufferLength,
sizeof(WCHAR));
- ProbeForWrite(Context,
- sizeof(ULONG),
- sizeof(ULONG));
+ ProbeForWriteUlong(Context);
if(!RestartScan)
{
SkipEntries = *Context;
}
if(ReturnLength != NULL)
{
- ProbeForWrite(ReturnLength,
- sizeof(ULONG),
- sizeof(ULONG));
+ ProbeForWriteUlong(ReturnLength);
}
}
_SEH_HANDLE
{
SkipEntries = *Context;
}
-
+
Status = ObReferenceObjectByHandle(DirectoryHandle,
DIRECTORY_QUERY,
ObDirectoryType,
NULL);
if(NT_SUCCESS(Status))
{
- PVOID TemporaryBuffer = ExAllocatePool(PagedPool,
+ PVOID TemporaryBuffer = ExAllocatePool(NonPagedPool,
BufferLength);
if(TemporaryBuffer != NULL)
{
POBJECT_HEADER EntryHeader;
PLIST_ENTRY ListEntry;
KIRQL OldLevel;
- ULONG RequiredSize = 0;
+ ULONG RequiredSize = sizeof(OBJECT_DIRECTORY_INFORMATION);
ULONG nDirectories = 0;
POBJECT_DIRECTORY_INFORMATION DirInfo = (POBJECT_DIRECTORY_INFORMATION)TemporaryBuffer;
-
+
Status = STATUS_NO_MORE_ENTRIES;
KeAcquireSpinLock(&Directory->Lock, &OldLevel);
EntryHeader = CONTAINING_RECORD(ListEntry, OBJECT_HEADER, Entry);
/* calculate the size of the required buffer space for this entry */
- Name = (EntryHeader->Name.Length != 0 ? &EntryHeader->Name : NULL);
- Type = &EntryHeader->ObjectType->TypeName;
+ Name = (HEADER_TO_OBJECT_NAME(EntryHeader)->Name.Length != 0 ? &HEADER_TO_OBJECT_NAME(EntryHeader)->Name : NULL);
+ Type = &EntryHeader->Type->Name;
EntrySize = sizeof(OBJECT_DIRECTORY_INFORMATION) +
((Name != NULL) ? ((ULONG)Name->Length + sizeof(WCHAR)) : 0) +
- (ULONG)EntryHeader->ObjectType->TypeName.Length + sizeof(WCHAR);
+ (ULONG)EntryHeader->Type->Name.Length + sizeof(WCHAR);
if(RequiredSize + EntrySize <= BufferLength)
{
nDirectories++;
RequiredSize += EntrySize;
-
+
Status = STATUS_SUCCESS;
if(ReturnSingleEntry)
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 */
break;
}
SkipEntries--;
}
}
-
+
if(!ReturnSingleEntry && ListEntry != &Directory->head)
{
/* there are more entries to enumerate but the buffer is already full.
Status = STATUS_MORE_ENTRIES;
}
- if(NT_SUCCESS(Status))
+ if(NT_SUCCESS(Status) && nDirectories > 0)
{
- if(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++)
{
- _SEH_TRY
- {
- POBJECT_DIRECTORY_INFORMATION DestDirInfo = (POBJECT_DIRECTORY_INFORMATION)Buffer;
- PWSTR strbuf = (PWSTR)((POBJECT_DIRECTORY_INFORMATION)Buffer + nDirectories);
-
- /* copy all OBJECT_DIRECTORY_INFORMATION structures to the buffer and
- just append all strings (whose pointers are stored in the buffer!)
- and replace the pointers */
- for(DirInfo = (POBJECT_DIRECTORY_INFORMATION)TemporaryBuffer;
- nDirectories > 0;
- nDirectories--, DirInfo++, DestDirInfo++)
- {
- if(DirInfo->ObjectName.Length > 0)
- {
- DestDirInfo->ObjectName.Length = DirInfo->ObjectName.Length;
- DestDirInfo->ObjectName.MaximumLength = DirInfo->ObjectName.MaximumLength;
- DestDirInfo->ObjectName.Buffer = strbuf;
- RtlCopyMemory(strbuf,
- DirInfo->ObjectName.Buffer,
- DirInfo->ObjectName.Length);
- /* NULL-terminate the string */
- strbuf[DirInfo->ObjectName.Length / sizeof(WCHAR)] = L'\0';
- strbuf += (DirInfo->ObjectName.Length / sizeof(WCHAR)) + 1;
- }
-
- DestDirInfo->ObjectTypeName.Length = DirInfo->ObjectTypeName.Length;
- DestDirInfo->ObjectTypeName.MaximumLength = DirInfo->ObjectTypeName.MaximumLength;
- DestDirInfo->ObjectTypeName.Buffer = strbuf;
- RtlCopyMemory(strbuf,
- DirInfo->ObjectTypeName.Buffer,
- DirInfo->ObjectTypeName.Length);
- /* NULL-terminate the string */
- strbuf[DirInfo->ObjectTypeName.Length / sizeof(WCHAR)] = L'\0';
- strbuf += (DirInfo->ObjectTypeName.Length / sizeof(WCHAR)) + 1;
- }
- }
- _SEH_HANDLE
+ ULONG NameLength;
+
+ if(DirInfo->ObjectName.Length > 0)
{
- Status = _SEH_GetExceptionCode();
+ 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);
}
- _SEH_END;
+
+ 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);
}
}
KeReleaseSpinLock(&Directory->Lock, OldLevel);
ObDereferenceObject(Directory);
-
- ExFreePool(TemporaryBuffer);
if(NT_SUCCESS(Status) || ReturnSingleEntry)
{
_SEH_TRY
{
+ if(CopyBytes != 0)
+ {
+ RtlCopyMemory(Buffer,
+ TemporaryBuffer,
+ CopyBytes);
+ }
*Context = NextEntry;
if(ReturnLength != NULL)
{
}
_SEH_END;
}
+
+ ExFreePool(TemporaryBuffer);
}
else
{
Status = STATUS_INSUFFICIENT_RESOURCES;
}
}
-
+
return Status;
}
/**********************************************************************
* NAME (EXPORTED as Zw)
* NtCreateDirectoryObject
- *
+ *
* DESCRIPTION
* Creates or opens a directory object (a container for other
* objects).
- *
+ *
* ARGUMENTS
* DirectoryHandle (OUT)
- * Caller supplied storage for the handle of the
+ * Caller supplied storage for the handle of the
* directory.
- *
+ *
* DesiredAccess
* Access desired to the directory.
- *
+ *
* ObjectAttributes
* Object attributes initialized with
* InitializeObjectAttributes.
- *
+ *
* RETURN VALUE
* Status.
*/
HANDLE hDirectory;
KPROCESSOR_MODE PreviousMode;
NTSTATUS Status = STATUS_SUCCESS;
-
+
+ PAGED_CODE();
+
DPRINT("NtCreateDirectoryObject(DirectoryHandle %x, "
- "DesiredAccess %x, ObjectAttributes %x\n",
- DirectoryHandle, DesiredAccess, ObjectAttributes);
+ "DesiredAccess %x, ObjectAttributes %x\n",
+ DirectoryHandle, DesiredAccess, ObjectAttributes);
PreviousMode = ExGetPreviousMode();
{
_SEH_TRY
{
- ProbeForWrite(DirectoryHandle,
- sizeof(HANDLE),
- sizeof(ULONG));
+ ProbeForWriteHandle(DirectoryHandle);
}
_SEH_HANDLE
{
0,
0,
(PVOID*)&Directory);
+
if(NT_SUCCESS(Status))
{
Status = ObInsertObject((PVOID)Directory,
0,
NULL,
&hDirectory);
+ if (!NT_SUCCESS(Status))
+ {
+ ObMakeTemporaryObject(Directory);
+ }
ObDereferenceObject(Directory);
if(NT_SUCCESS(Status))