mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 16:43:04 +00:00
[KERNEL32] Reduce QueryDosDeviceA memory footprint
by using TEB static unicode string (which is already preallocated). Also, properly handle RtlUnicodeStringToAnsiString failures. Finally, make sure output buffer is properly 0 terminated.
This commit is contained in:
parent
1ed7f27466
commit
8d128aa441
1 changed files with 87 additions and 37 deletions
|
@ -261,62 +261,112 @@ QueryDosDeviceA(
|
||||||
DWORD ucchMax
|
DWORD ucchMax
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
UNICODE_STRING DeviceNameU;
|
NTSTATUS Status;
|
||||||
|
USHORT CurrentPosition;
|
||||||
|
ANSI_STRING AnsiString;
|
||||||
UNICODE_STRING TargetPathU;
|
UNICODE_STRING TargetPathU;
|
||||||
ANSI_STRING TargetPathA;
|
PUNICODE_STRING DeviceNameU;
|
||||||
DWORD Length;
|
DWORD RetLength, CurrentLength, Length;
|
||||||
DWORD CurrentLength;
|
PWSTR DeviceNameBuffer, TargetPathBuffer;
|
||||||
PWCHAR Buffer;
|
|
||||||
|
|
||||||
if (lpDeviceName)
|
/* If we want a specific device name, convert it */
|
||||||
|
if (lpDeviceName != NULL)
|
||||||
{
|
{
|
||||||
if (!RtlCreateUnicodeStringFromAsciiz(&DeviceNameU,
|
/* Convert DeviceName using static unicode string */
|
||||||
(LPSTR)lpDeviceName))
|
RtlInitAnsiString(&AnsiString, lpDeviceName);
|
||||||
|
DeviceNameU = &NtCurrentTeb()->StaticUnicodeString;
|
||||||
|
Status = RtlAnsiStringToUnicodeString(DeviceNameU, &AnsiString, FALSE);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
/*
|
||||||
return 0;
|
* If the static unicode string is too small,
|
||||||
|
* it's because the name is too long...
|
||||||
|
* so, return appropriate status!
|
||||||
|
*/
|
||||||
|
if (Status == STATUS_BUFFER_OVERFLOW)
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_FILENAME_EXCED_RANGE);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseSetLastNTError(Status);
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DeviceNameBuffer = DeviceNameU->Buffer;
|
||||||
}
|
}
|
||||||
Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, ucchMax * sizeof(WCHAR));
|
else
|
||||||
if (Buffer == NULL)
|
{
|
||||||
|
DeviceNameBuffer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate the output buffer for W call */
|
||||||
|
TargetPathBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, ucchMax * sizeof(WCHAR));
|
||||||
|
if (TargetPathBuffer == NULL)
|
||||||
{
|
{
|
||||||
if (lpDeviceName)
|
|
||||||
{
|
|
||||||
RtlFreeHeap(RtlGetProcessHeap(), 0, DeviceNameU.Buffer);
|
|
||||||
}
|
|
||||||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Length = QueryDosDeviceW(lpDeviceName ? DeviceNameU.Buffer : NULL,
|
/* Call W */
|
||||||
Buffer, ucchMax);
|
Length = QueryDosDeviceW(DeviceNameBuffer, TargetPathBuffer, ucchMax);
|
||||||
|
/* We'll return that length in case of a success */
|
||||||
|
RetLength = Length;
|
||||||
|
|
||||||
|
/* Handle the case where we would fill output buffer completly */
|
||||||
|
if (Length != 0 && Length == ucchMax)
|
||||||
|
{
|
||||||
|
/* This will be our work length (but not the one we return) */
|
||||||
|
--Length;
|
||||||
|
/* Already 0 the last char */
|
||||||
|
lpTargetPath[Length] = ANSI_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we had an output, start the convert loop */
|
||||||
if (Length != 0)
|
if (Length != 0)
|
||||||
{
|
{
|
||||||
TargetPathA.Buffer = lpTargetPath;
|
/*
|
||||||
TargetPathU.Buffer = Buffer;
|
* We'll have to loop because TargetPathBuffer may contain
|
||||||
ucchMax = Length;
|
* several strings (NULL separated)
|
||||||
|
* We'll start at position 0
|
||||||
while (ucchMax)
|
*/
|
||||||
|
CurrentPosition = 0;
|
||||||
|
while (CurrentPosition < Length)
|
||||||
{
|
{
|
||||||
CurrentLength = min(ucchMax, MAXUSHORT / 2);
|
/* Get the maximum length */
|
||||||
TargetPathU.MaximumLength = TargetPathU.Length = (USHORT)CurrentLength * sizeof(WCHAR);
|
CurrentLength = min(Length - CurrentPosition, MAXUSHORT / 2);
|
||||||
|
|
||||||
TargetPathA.Length = 0;
|
/* Initialize our output string */
|
||||||
TargetPathA.MaximumLength = (USHORT)CurrentLength;
|
AnsiString.Length = 0;
|
||||||
|
AnsiString.MaximumLength = CurrentLength + sizeof(ANSI_NULL);
|
||||||
|
AnsiString.Buffer = &lpTargetPath[CurrentPosition];
|
||||||
|
|
||||||
RtlUnicodeStringToAnsiString(&TargetPathA, &TargetPathU, FALSE);
|
/* Initialize input string that will be converted */
|
||||||
ucchMax -= CurrentLength;
|
TargetPathU.Length = CurrentLength * sizeof(WCHAR);
|
||||||
TargetPathA.Buffer += TargetPathA.Length;
|
TargetPathU.MaximumLength = CurrentLength * sizeof(WCHAR) + sizeof(UNICODE_NULL);
|
||||||
TargetPathU.Buffer += TargetPathU.Length / sizeof(WCHAR);
|
TargetPathU.Buffer = &TargetPathBuffer[CurrentPosition];
|
||||||
|
|
||||||
|
/* Convert to ANSI */
|
||||||
|
Status = RtlUnicodeStringToAnsiString(&AnsiString, &TargetPathU, FALSE);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
BaseSetLastNTError(Status);
|
||||||
|
/* In case of a failure, forget about everything */
|
||||||
|
RetLength = 0;
|
||||||
|
|
||||||
|
goto Leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Move to the next string */
|
||||||
|
CurrentPosition += CurrentLength;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
|
Leave:
|
||||||
if (lpDeviceName)
|
/* Free our intermediate buffer and leave */
|
||||||
{
|
RtlFreeHeap(RtlGetProcessHeap(), 0, TargetPathBuffer);
|
||||||
RtlFreeHeap(RtlGetProcessHeap(), 0, DeviceNameU.Buffer);
|
|
||||||
}
|
return RetLength;
|
||||||
return Length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue