- Fix definition of OBJECT_DIRECTORY_INFORMATION

- Implement most of NtQueryDirectoryObject. It lacks the last step of converting the absolute buffer to a relative one. I have no idea why the old code was re-implemented in a recent commit when I clearly said I would fix this tonight.

svn path=/trunk/; revision=23112
This commit is contained in:
Alex Ionescu 2006-07-17 03:16:15 +00:00
parent 8baa71bb63
commit 96722f7c02
9 changed files with 158 additions and 215 deletions

View file

@ -257,11 +257,11 @@ ListDirectory (
CHAR TypeNameA [MAX_PATH]; CHAR TypeNameA [MAX_PATH];
CHAR TargetNameA [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 ( if (TRUE == ExpandSymbolicLink (
DirectoryNameW, DirectoryNameW,
& pDirectoryEntry->ObjectName, & pDirectoryEntry->Name,
& TargetObjectName & TargetObjectName
) )
) )
@ -269,8 +269,8 @@ ListDirectory (
printf ( printf (
"%-16s %s -> %s\n", "%-16s %s -> %s\n",
RawUszAsz (pDirectoryEntry->ObjectTypeName.Buffer, TypeNameA), RawUszAsz (pDirectoryEntry->TypeName.Buffer, TypeNameA),
RawUszAsz (pDirectoryEntry->ObjectName.Buffer, ObjectNameA), RawUszAsz (pDirectoryEntry->Name.Buffer, ObjectNameA),
RawUszAsz (TargetObjectName.Buffer, TargetNameA) RawUszAsz (TargetObjectName.Buffer, TargetNameA)
); );
} }
@ -278,8 +278,8 @@ ListDirectory (
{ {
printf ( printf (
"%-16s %s -> (error!)\n", "%-16s %s -> (error!)\n",
RawUszAsz (pDirectoryEntry->ObjectTypeName.Buffer, TypeNameA), RawUszAsz (pDirectoryEntry->TypeName.Buffer, TypeNameA),
RawUszAsz (pDirectoryEntry->ObjectName.Buffer, ObjectNameA) RawUszAsz (pDirectoryEntry->Name.Buffer, ObjectNameA)
); );
} }
} }
@ -287,8 +287,8 @@ ListDirectory (
{ {
printf ( printf (
"%-16s %s\n", "%-16s %s\n",
RawUszAsz (pDirectoryEntry->ObjectTypeName.Buffer, TypeNameA), RawUszAsz (pDirectoryEntry->TypeName.Buffer, TypeNameA),
RawUszAsz (pDirectoryEntry->ObjectName.Buffer, ObjectNameA) RawUszAsz (pDirectoryEntry->Name.Buffer, ObjectNameA)
); );
} }
++ pDirectoryEntry; ++ pDirectoryEntry;
@ -306,9 +306,9 @@ ListDirectory (
if (FALSE != Recurse) if (FALSE != Recurse)
{ {
pDirectoryEntry = (POBJECT_DIRECTORY_INFORMATION) DirectoryEntry; 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]; WCHAR CurrentName [MAX_PATH];
UNICODE_STRING CurrentDirectory; UNICODE_STRING CurrentDirectory;
@ -319,7 +319,7 @@ ListDirectory (
{ {
wcscat (CurrentName, L"\\"); wcscat (CurrentName, L"\\");
} }
wcscat (CurrentName, pDirectoryEntry->ObjectName.Buffer); wcscat (CurrentName, pDirectoryEntry->Name.Buffer);
RtlInitUnicodeString (& CurrentDirectory, CurrentName); RtlInitUnicodeString (& CurrentDirectory, CurrentName);
ListDirectory (& CurrentDirectory, Recurse); ListDirectory (& CurrentDirectory, Recurse);
} }

View file

@ -470,12 +470,12 @@ ScmCheckDriver(PSERVICE Service)
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
break; break;
DPRINT("Comparing: '%S' '%wZ'\n", Service->lpServiceName, &DirInfo->ObjectName); DPRINT("Comparing: '%S' '%wZ'\n", Service->lpServiceName, &DirInfo->Name);
if (_wcsicmp(Service->lpServiceName, DirInfo->ObjectName.Buffer) == 0) if (_wcsicmp(Service->lpServiceName, DirInfo->Name.Buffer) == 0)
{ {
DPRINT("Found: '%S' '%wZ'\n", DPRINT("Found: '%S' '%wZ'\n",
Service->lpServiceName, &DirInfo->ObjectName); Service->lpServiceName, &DirInfo->Name);
/* Mark service as 'running' */ /* Mark service as 'running' */
Service->Status.dwCurrentState = SERVICE_RUNNING; Service->Status.dwCurrentState = SERVICE_RUNNING;

View file

@ -140,12 +140,12 @@ ScmGetDriverStatus(PSERVICE lpService,
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
break; break;
DPRINT("Comparing: '%S' '%wZ'\n", lpService->lpServiceName, &DirInfo->ObjectName); DPRINT("Comparing: '%S' '%wZ'\n", lpService->lpServiceName, &DirInfo->Name);
if (_wcsicmp(lpService->lpServiceName, DirInfo->ObjectName.Buffer) == 0) if (_wcsicmp(lpService->lpServiceName, DirInfo->Name.Buffer) == 0)
{ {
DPRINT1("Found: '%S' '%wZ'\n", DPRINT1("Found: '%S' '%wZ'\n",
lpService->lpServiceName, &DirInfo->ObjectName); lpService->lpServiceName, &DirInfo->Name);
bFound = TRUE; bFound = TRUE;
break; break;

View file

@ -298,11 +298,11 @@ QueryDosDeviceW(
break; break;
} }
if (!wcscmp (DirInfo->ObjectTypeName.Buffer, L"SymbolicLink")) if (!wcscmp (DirInfo->TypeName.Buffer, L"SymbolicLink"))
{ {
DPRINT ("Name: '%wZ'\n", &DirInfo->ObjectName); DPRINT ("Name: '%wZ'\n", &DirInfo->Name);
NameLength = DirInfo->ObjectName.Length / sizeof(WCHAR); NameLength = DirInfo->Name.Length / sizeof(WCHAR);
if (Length + NameLength + 1 >= ucchMax) if (Length + NameLength + 1 >= ucchMax)
{ {
Length = 0; Length = 0;
@ -311,8 +311,8 @@ QueryDosDeviceW(
} }
memcpy (Ptr, memcpy (Ptr,
DirInfo->ObjectName.Buffer, DirInfo->Name.Buffer,
DirInfo->ObjectName.Length); DirInfo->Name.Length);
Ptr += NameLength; Ptr += NameLength;
Length += NameLength; Length += NameLength;
*Ptr = UNICODE_NULL; *Ptr = UNICODE_NULL;

View file

@ -261,8 +261,8 @@ typedef struct _OBJECT_HANDLE_ATTRIBUTE_INFORMATION
typedef struct _OBJECT_DIRECTORY_INFORMATION typedef struct _OBJECT_DIRECTORY_INFORMATION
{ {
UNICODE_STRING ObjectName; UNICODE_STRING Name;
UNICODE_STRING ObjectTypeName; UNICODE_STRING TypeName;
} OBJECT_DIRECTORY_INFORMATION, *POBJECT_DIRECTORY_INFORMATION; } OBJECT_DIRECTORY_INFORMATION, *POBJECT_DIRECTORY_INFORMATION;
#ifndef NTOS_MODE_USER #ifndef NTOS_MODE_USER

View file

@ -513,12 +513,12 @@ xHalpGetRDiskCount(VOID)
if (NT_SUCCESS(Status)) if (NT_SUCCESS(Status))
{ {
Count = 0; Count = 0;
while (DirectoryInfo[Count].ObjectName.Buffer) while (DirectoryInfo[Count].Name.Buffer)
{ {
DPRINT("Count %x\n", Count); DPRINT("Count %x\n", Count);
DirectoryInfo[Count].ObjectName.Buffer[DirectoryInfo[Count].ObjectName.Length / sizeof(WCHAR)] = 0; DirectoryInfo[Count].Name.Buffer[DirectoryInfo[Count].Name.Length / sizeof(WCHAR)] = 0;
ArcNameBuffer = DirectoryInfo[Count].ObjectName.Buffer; ArcNameBuffer = DirectoryInfo[Count].Name.Buffer;
if (DirectoryInfo[Count].ObjectName.Length >= sizeof(L"multi(0)disk(0)rdisk(0)") - sizeof(WCHAR) && if (DirectoryInfo[Count].Name.Length >= sizeof(L"multi(0)disk(0)rdisk(0)") - sizeof(WCHAR) &&
!_wcsnicmp(ArcNameBuffer, L"multi(0)disk(0)rdisk(", (sizeof(L"multi(0)disk(0)rdisk(") - sizeof(WCHAR)) / sizeof(WCHAR))) !_wcsnicmp(ArcNameBuffer, L"multi(0)disk(0)rdisk(", (sizeof(L"multi(0)disk(0)rdisk(") - sizeof(WCHAR)) / sizeof(WCHAR)))
{ {
DPRINT("%S\n", ArcNameBuffer); DPRINT("%S\n", ArcNameBuffer);

View file

@ -414,6 +414,15 @@ NtQueryDirectoryObject(IN HANDLE DirectoryHandle,
ULONG NextEntry = 0; ULONG NextEntry = 0;
ULONG CopyBytes = 0; ULONG CopyBytes = 0;
NTSTATUS Status = STATUS_SUCCESS; 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(); PAGED_CODE();
/* Check if we need to do any probing */ /* Check if we need to do any probing */
@ -447,6 +456,14 @@ NtQueryDirectoryObject(IN HANDLE DirectoryHandle,
SkipEntries = *Context; 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 */ /* Get a reference to directory */
Status = ObReferenceObjectByHandle(DirectoryHandle, Status = ObReferenceObjectByHandle(DirectoryHandle,
DIRECTORY_QUERY, DIRECTORY_QUERY,
@ -454,199 +471,125 @@ NtQueryDirectoryObject(IN HANDLE DirectoryHandle,
PreviousMode, PreviousMode,
(PVOID*)&Directory, (PVOID*)&Directory,
NULL); NULL);
if (NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
PVOID TemporaryBuffer = ExAllocatePool(NonPagedPool, /* Free the buffer and fail */
BufferLength); ExFreePool(LocalBuffer);
if(TemporaryBuffer != NULL) return Status;
{ }
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;
/* Start at position 0 */
DirectoryInfo = (POBJECT_DIRECTORY_INFORMATION)LocalBuffer;
TotalLength = sizeof(OBJECT_DIRECTORY_INFORMATION);
/* Start with 0 entries */
Count = 0;
CurrentEntry = 0;
/* Set default status and start looping */
Status = STATUS_NO_MORE_ENTRIES; Status = STATUS_NO_MORE_ENTRIES;
for (Hash = 0; Hash < 37; Hash++)
KeEnterCriticalRegion();
ExAcquireResourceSharedLite(&Directory->Lock, TRUE);
for (i = 0; i < NUMBER_HASH_BUCKETS && !StopIt; i++)
{ {
DirectoryEntry = Directory->HashBuckets[i]; /* Get this entry and loop all of them */
while (DirectoryEntry) Entry = Directory->HashBuckets[Hash];
while (Entry)
{ {
NextEntry++; /* Check if we should process this entry */
if (SkipEntries == 0) if (SkipEntries == CurrentEntry++)
{ {
PUNICODE_STRING Name, Type; /* Get the header data */
ULONG EntrySize; ObjectHeader = OBJECT_TO_OBJECT_HEADER(Entry->Object);
ObjectNameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
EntryHeader = OBJECT_TO_OBJECT_HEADER(DirectoryEntry->Object); /* Get the object name */
if (ObjectNameInfo)
/* 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 /* Use the one we have */
been much easier if the strings were directly appended to the Name = ObjectNameInfo->Name;
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 else
{ {
/* Otherwise, use an empty one */
RtlInitEmptyUnicodeString(&Name, NULL, 0);
}
/* Calculate the length for this entry */
Length = sizeof(OBJECT_DIRECTORY_INFORMATION) +
Name.Length + sizeof(UNICODE_NULL) +
ObjectHeader->Type->Name.Length + sizeof(UNICODE_NULL);
/* Make sure this entry won't overflow */
if ((TotalLength + Length) > BufferLength)
{
/* Check if the caller wanted only an entry */
if (ReturnSingleEntry) if (ReturnSingleEntry)
{ {
/* The buffer is too small, so return the number of bytes that /* Then we'll fail and ask for more buffer */
would've been required for this query */ TotalLength += Length;
RequiredSize += EntrySize;
Status = STATUS_BUFFER_TOO_SMALL; 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 else
{ {
/* Skip the entry */ /* Otherwise, we'll say we're done for now */
SkipEntries--;
}
DirectoryEntry = DirectoryEntry->ChainLink;
}
}
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; Status = STATUS_MORE_ENTRIES;
else }
for (; i < NUMBER_HASH_BUCKETS; i++)
if (Directory->HashBuckets[i]) /* Decrease the entry since we didn't process */
{ CurrentEntry--;
Status = STATUS_MORE_ENTRIES; goto Quickie;
break; }
/* 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++;
} }
} }
if (NT_SUCCESS(Status) && nDirectories > 0) /* Move to the next directory */
{ Entry = Entry->ChainLink;
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, Quickie:
DirInfo->ObjectTypeName.Buffer, /* Make sure we got success */
DirInfo->ObjectTypeName.Length); if (NT_SUCCESS(Status))
/* 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);
}
}
ExReleaseResourceLite(&Directory->Lock);
KeLeaveCriticalRegion();
ObDereferenceObject(Directory);
if (NT_SUCCESS(Status) || ReturnSingleEntry)
{
_SEH_TRY
{
if (CopyBytes != 0)
{
RtlCopyMemory(Buffer,
TemporaryBuffer,
CopyBytes);
}
*Context = NextEntry;
if(ReturnLength != NULL)
{
*ReturnLength = RequiredSize;
}
}
_SEH_HANDLE
{
Status = _SEH_GetExceptionCode();
}
_SEH_END;
}
ExFreePool(TemporaryBuffer);
}
else
{ {
/* We need to parse all the entries and convert absolute to relative */
DPRINT1("NOT FULLY IMPLEMENTED\n");
Status = STATUS_INSUFFICIENT_RESOURCES; 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 to caller */
return Status; return Status;

View file

@ -94,14 +94,14 @@ CsrPopulateDosDevicesDirectory(IN HANDLE hDosDevicesDirectory,
if (NT_SUCCESS(Status)) if (NT_SUCCESS(Status))
{ {
/* Make sure it has a name */ /* Make sure it has a name */
if (!QueryBuffer->ObjectName.Buffer[0]) continue; if (!QueryBuffer->Name.Buffer[0]) continue;
/* Check if it's actually a symbolic link */ /* Check if it's actually a symbolic link */
if (wcscmp(QueryBuffer->ObjectTypeName.Buffer, SYMLINK_NAME)) if (wcscmp(QueryBuffer->TypeName.Buffer, SYMLINK_NAME))
{ {
/* It is, open it */ /* It is, open it */
InitializeObjectAttributes(&ObjectAttributes, InitializeObjectAttributes(&ObjectAttributes,
&QueryBuffer->ObjectName, &QueryBuffer->Name,
OBJ_CASE_INSENSITIVE, OBJ_CASE_INSENSITIVE,
NULL, NULL,
hDirectory); hDirectory);

View file

@ -1235,10 +1235,10 @@ BuildWindowStationNameList(
*/ */
ReturnLength = sizeof(DWORD); ReturnLength = sizeof(DWORD);
EntryCount = 0; EntryCount = 0;
for (DirEntry = (POBJECT_DIRECTORY_INFORMATION) Buffer; 0 != DirEntry->ObjectName.Length; for (DirEntry = (POBJECT_DIRECTORY_INFORMATION) Buffer; 0 != DirEntry->Name.Length;
DirEntry++) DirEntry++)
{ {
ReturnLength += DirEntry->ObjectName.Length + sizeof(WCHAR); ReturnLength += DirEntry->Name.Length + sizeof(WCHAR);
EntryCount++; EntryCount++;
} }
DPRINT("Required size: %d Entry count: %d\n", ReturnLength, EntryCount); DPRINT("Required size: %d Entry count: %d\n", ReturnLength, EntryCount);
@ -1282,10 +1282,10 @@ BuildWindowStationNameList(
lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(DWORD)); lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(DWORD));
NullWchar = L'\0'; NullWchar = L'\0';
for (DirEntry = (POBJECT_DIRECTORY_INFORMATION) Buffer; 0 != DirEntry->ObjectName.Length; for (DirEntry = (POBJECT_DIRECTORY_INFORMATION) Buffer; 0 != DirEntry->Name.Length;
DirEntry++) DirEntry++)
{ {
Status = MmCopyToCaller(lpBuffer, DirEntry->ObjectName.Buffer, DirEntry->ObjectName.Length); Status = MmCopyToCaller(lpBuffer, DirEntry->Name.Buffer, DirEntry->Name.Length);
if (! NT_SUCCESS(Status)) if (! NT_SUCCESS(Status))
{ {
if (Buffer != InitialBuffer) if (Buffer != InitialBuffer)
@ -1294,7 +1294,7 @@ BuildWindowStationNameList(
} }
return Status; return Status;
} }
lpBuffer = (PVOID) ((PCHAR) lpBuffer + DirEntry->ObjectName.Length); lpBuffer = (PVOID) ((PCHAR) lpBuffer + DirEntry->Name.Length);
Status = MmCopyToCaller(lpBuffer, &NullWchar, sizeof(WCHAR)); Status = MmCopyToCaller(lpBuffer, &NullWchar, sizeof(WCHAR));
if (! NT_SUCCESS(Status)) if (! NT_SUCCESS(Status))
{ {