|
|
/*++
Copyright (c) 2001 Microsoft Corporation
Module Name:
rtlutils.cpp
Abstract: Contains functions from ntdll on XP that are not available on W2K.
History:
09/10/2001 rparsons Created
--*/
#include "rtlutils.h"
namespace ShimLib {
#define IS_PATH_SEPARATOR_U(ch) (((ch) == L'\\') || ((ch) == L'/'))
extern const UNICODE_STRING RtlpDosDevicesPrefix = RTL_CONSTANT_STRING( L"\\??\\" ); extern const UNICODE_STRING RtlpDosDevicesUncPrefix = RTL_CONSTANT_STRING( L"\\??\\UNC\\" );
const UNICODE_STRING RtlpEmptyString = RTL_CONSTANT_STRING(L"");
//
// Taken from %SDXROOT%\public\sdk\inc\ntrtl.h
//
#if DBG
#undef ASSERT
#define ASSERT( exp ) \
((!(exp)) ? \ (RtlAssert( #exp, __FILE__, __LINE__, NULL ),FALSE) : \ TRUE) #else
#undef ASSERT
#define ASSERT( exp ) ((void) 0)
#endif
#define DPFLTR_LEVEL_STATUS(x) ((NT_SUCCESS(x) \
|| (x) == STATUS_OBJECT_NAME_NOT_FOUND \ ) \ ? DPFLTR_TRACE_LEVEL : DPFLTR_ERROR_LEVEL)
//
// These functions were taken from:
// %SDXROOT%\base\ntdll\ldrinit.c
//
PVOID ShimAllocateStringRoutine( SIZE_T NumberOfBytes ) { return RtlAllocateHeap(RtlProcessHeap(), 0, NumberOfBytes); }
VOID ShimFreeStringRoutine( PVOID Buffer ) { RtlFreeHeap(RtlProcessHeap(), 0, Buffer); }
//
// These functions were pulled from:
// %SDXROOT%\base\ntdll\curdir.c
//
RTL_PATH_TYPE NTAPI ShimDetermineDosPathNameType_Ustr( IN PCUNICODE_STRING String )
/*++
Routine Description:
This function examines the Dos format file name and determines the type of file name (i.e. UNC, DriveAbsolute, Current Directory rooted, or Relative.)
Arguments:
DosFileName - Supplies the Dos format file name whose type is to be determined.
Return Value:
RtlPathTypeUnknown - The path type can not be determined
RtlPathTypeUncAbsolute - The path specifies a Unc absolute path in the format \\server-name\sharename\rest-of-path
RtlPathTypeLocalDevice - The path specifies a local device in the format \\.\rest-of-path or \\?\rest-of-path. This can be used for any device where the nt and Win32 names are the same. For example mailslots.
RtlPathTypeRootLocalDevice - The path specifies the root of the local devices in the format \\. or \\?
RtlPathTypeDriveAbsolute - The path specifies a drive letter absolute path in the form drive:\rest-of-path
RtlPathTypeDriveRelative - The path specifies a drive letter relative path in the form drive:rest-of-path
RtlPathTypeRooted - The path is rooted relative to the current disk designator (either Unc disk, or drive). The form is \rest-of-path.
RtlPathTypeRelative - The path is relative (i.e. not absolute or rooted).
--*/
{ RTL_PATH_TYPE ReturnValue; const PCWSTR DosFileName = String->Buffer;
#define ENOUGH_CHARS(_cch) (String->Length >= ((_cch) * sizeof(WCHAR)))
if ( ENOUGH_CHARS(1) && IS_PATH_SEPARATOR_U(*DosFileName) ) { if ( ENOUGH_CHARS(2) && IS_PATH_SEPARATOR_U(*(DosFileName+1)) ) { if ( ENOUGH_CHARS(3) && (DosFileName[2] == '.' || DosFileName[2] == '?') ) {
if ( ENOUGH_CHARS(4) && IS_PATH_SEPARATOR_U(*(DosFileName+3)) ){ // "\\.\" or "\\?\"
ReturnValue = RtlPathTypeLocalDevice; } //
// Bogosity ahead, the code is confusing length and nuls,
// because it was copy/pasted from the PCWSTR version.
//
else if ( ENOUGH_CHARS(4) && (*(DosFileName+3)) == UNICODE_NULL ){ // "\\.\0" or \\?\0"
ReturnValue = RtlPathTypeRootLocalDevice; } else { // "\\.x" or "\\." or "\\?x" or "\\?"
ReturnValue = RtlPathTypeUncAbsolute; } } else { // "\\x"
ReturnValue = RtlPathTypeUncAbsolute; } } else { // "\x"
ReturnValue = RtlPathTypeRooted; } } //
// the "*DosFileName" is left over from the PCWSTR version
// Win32 and DOS don't allow embedded nuls and much code limits
// drive letters to strictly 7bit a-zA-Z so it's ok.
//
else if (ENOUGH_CHARS(2) && *DosFileName && *(DosFileName+1)==L':') { if (ENOUGH_CHARS(3) && IS_PATH_SEPARATOR_U(*(DosFileName+2))) { // "x:\"
ReturnValue = RtlPathTypeDriveAbsolute; } else { // "c:x"
ReturnValue = RtlPathTypeDriveRelative; } } else { // "x", first char is not a slash / second char is not colon
ReturnValue = RtlPathTypeRelative; } return ReturnValue;
#undef ENOUGH_CHARS
}
NTSTATUS NTAPI ShimNtPathNameToDosPathName( IN ULONG Flags, IN OUT PRTL_UNICODE_STRING_BUFFER Path, OUT ULONG* Disposition OPTIONAL, IN OUT PWSTR* FilePart OPTIONAL ) { NTSTATUS Status = STATUS_SUCCESS; SIZE_T NtFilePartOffset = 0; SIZE_T DosFilePartOffset = 0; BOOLEAN Unc = FALSE; const static UNICODE_STRING DosUncPrefix = RTL_CONSTANT_STRING(L"\\\\"); PCUNICODE_STRING NtPrefix = NULL; PCUNICODE_STRING DosPrefix = NULL; RTL_STRING_LENGTH_TYPE Cch = 0;
if (ARGUMENT_PRESENT(Disposition)) { *Disposition = 0; }
if ( !RTL_SOFT_VERIFY(Path != NULL) || !RTL_SOFT_VERIFY(Flags == 0) ) { Status = STATUS_INVALID_PARAMETER; goto Exit; }
if (ARGUMENT_PRESENT(FilePart) && *FilePart != NULL) { NtFilePartOffset = *FilePart - Path->String.Buffer; if (!RTL_SOFT_VERIFY(NtFilePartOffset < RTL_STRING_GET_LENGTH_CHARS(&Path->String)) ) { Status = STATUS_INVALID_PARAMETER; goto Exit; } }
if (RtlPrefixUnicodeString(RTL_CONST_CAST(PUNICODE_STRING)(&RtlpDosDevicesUncPrefix), &Path->String, TRUE) ) { NtPrefix = &RtlpDosDevicesUncPrefix; DosPrefix = &DosUncPrefix; if (ARGUMENT_PRESENT(Disposition)) { *Disposition = RTL_NT_PATH_NAME_TO_DOS_PATH_NAME_UNC; } } else if (RtlPrefixUnicodeString(RTL_CONST_CAST(PUNICODE_STRING)(&RtlpDosDevicesPrefix), &Path->String, TRUE) ) { NtPrefix = &RtlpDosDevicesPrefix; DosPrefix = &RtlpEmptyString; if (ARGUMENT_PRESENT(Disposition)) { *Disposition = RTL_NT_PATH_NAME_TO_DOS_PATH_NAME_DRIVE; } } else { //
// It is not recognizably an Nt path produced by RtlDosPathNameToNtPathName_U.
//
if (ARGUMENT_PRESENT(Disposition)) { RTL_PATH_TYPE PathType = ShimDetermineDosPathNameType_Ustr(&Path->String); switch (PathType) { case RtlPathTypeUnknown: case RtlPathTypeRooted: // NT paths are identified as this
*Disposition = RTL_NT_PATH_NAME_TO_DOS_PATH_NAME_AMBIGUOUS; break;
//
// "already" dospaths, but not gotten from this function, let's
// give a less good disposition
//
case RtlPathTypeDriveRelative: case RtlPathTypeRelative: *Disposition = RTL_NT_PATH_NAME_TO_DOS_PATH_NAME_AMBIGUOUS; break;
// these are pretty clearly dospaths already
case RtlPathTypeUncAbsolute: case RtlPathTypeDriveAbsolute: case RtlPathTypeLocalDevice: // "\\?\" or "\\.\" or "\\?\blah" or "\\.\blah"
case RtlPathTypeRootLocalDevice: // "\\?" or "\\."
*Disposition = RTL_NT_PATH_NAME_TO_DOS_PATH_NAME_ALREADY_DOS; break; } } goto Exit; }
Cch = RTL_STRING_GET_LENGTH_CHARS(&Path->String) + RTL_STRING_GET_LENGTH_CHARS(DosPrefix) - RTL_STRING_GET_LENGTH_CHARS(NtPrefix);
Status = ShimEnsureUnicodeStringBufferSizeChars(Path, Cch); if (!NT_SUCCESS(Status)) { goto Exit; }
//
// overlapping buffer shuffle...careful.
//
RtlMoveMemory( Path->String.Buffer + RTL_STRING_GET_LENGTH_CHARS(DosPrefix), Path->String.Buffer + RTL_STRING_GET_LENGTH_CHARS(NtPrefix), Path->String.Length - NtPrefix->Length ); RtlMoveMemory( Path->String.Buffer, DosPrefix->Buffer, DosPrefix->Length ); Path->String.Length = Cch * sizeof(Path->String.Buffer[0]); RTL_NUL_TERMINATE_STRING(&Path->String);
if (NtFilePartOffset != 0) { // review/test..
*FilePart = Path->String.Buffer + (NtFilePartOffset - RTL_STRING_GET_LENGTH_CHARS(NtPrefix) + RTL_STRING_GET_LENGTH_CHARS(DosPrefix)); } Status = STATUS_SUCCESS; Exit: /* KdPrintEx((
DPFLTR_SXS_ID, DPFLTR_LEVEL_STATUS(Status), "%s(%d):%s(%wZ): 0x%08lx\n", __FILE__, __LINE__, __FUNCTION__, Path, Status)); */ return Status; }
NTSTATUS ShimValidateUnicodeString( ULONG Flags, const UNICODE_STRING *String ) { NTSTATUS Status = STATUS_SUCCESS;
ASSERT(Flags == 0);
if (Flags != 0) { Status = STATUS_INVALID_PARAMETER; goto Exit; }
if (String != NULL) { if (((String->Length % 2) != 0) || ((String->MaximumLength % 2) != 0) || (String->Length > String->MaximumLength)) { Status = STATUS_INVALID_PARAMETER; goto Exit; }
if (((String->Length != 0) || (String->MaximumLength != 0)) && (String->Buffer == NULL)) { Status = STATUS_INVALID_PARAMETER; goto Exit; } }
Status = STATUS_SUCCESS; Exit: return Status; }
//
// This function was taken from:
// %SDXROOT%\base\ntos\rtl\nls.c
//
NTSTATUS ShimDuplicateUnicodeString( ULONG Flags, PCUNICODE_STRING StringIn, PUNICODE_STRING StringOut ) { NTSTATUS Status = STATUS_SUCCESS; USHORT Length = 0; USHORT NewMaximumLength = 0; PWSTR Buffer = NULL;
if (((Flags & ~( RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE | RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING)) != 0) || (StringOut == NULL)) { Status = STATUS_INVALID_PARAMETER; goto Exit; }
// It doesn't make sense to force allocation of a null string unless you
// want null termination.
if ((Flags & RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING) && !(Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE)) { Status = STATUS_INVALID_PARAMETER; goto Exit; }
Status = ShimValidateUnicodeString(0, StringIn); if (!NT_SUCCESS(Status)) goto Exit;
if (StringIn != NULL) Length = StringIn->Length;
if ((Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE) && (Length == UNICODE_STRING_MAX_BYTES)) { Status = STATUS_NAME_TOO_LONG; goto Exit; }
if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE) NewMaximumLength = (USHORT) (Length + sizeof(WCHAR)); else NewMaximumLength = Length;
// If it's a zero length string in, force the allocation length to zero
// unless the caller said that they want zero length strings allocated.
if (((Flags & RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING) == 0) && (Length == 0)) { NewMaximumLength = 0; }
if (NewMaximumLength != 0) { Buffer = (PWSTR)(RtlAllocateStringRoutine)(NewMaximumLength); if (Buffer == NULL) { Status = STATUS_NO_MEMORY; goto Exit; }
// If there's anything to copy, copy it. We explicitly test Length because
// StringIn could be a NULL pointer, so dereferencing it to get the Buffer
// pointer would access violate.
if (Length != 0) { RtlCopyMemory( Buffer, StringIn->Buffer, Length); }
if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE) { Buffer[Length / sizeof(WCHAR)] = L'\0'; } }
StringOut->Buffer = Buffer; StringOut->MaximumLength = NewMaximumLength; StringOut->Length = Length;
Status = STATUS_SUCCESS; Exit: return Status; }
//
// This function was pulled from:
// %SDXROOT%\base\ntdll\buffer.c
//
NTSTATUS NTAPI ShimpEnsureBufferSize( IN ULONG Flags, IN OUT PRTL_BUFFER Buffer, IN SIZE_T Size ) /*++
Routine Description:
This function ensures Buffer can hold Size bytes, or returns an error. It either bumps Buffer->Size closer to Buffer->StaticSize, or heap allocates.
Arguments:
Buffer - a Buffer object, see also RtlInitBuffer.
Size - the number of bytes the caller wishes to store in Buffer->Buffer.
Return Value:
STATUS_SUCCESS STATUS_NO_MEMORY
--*/ { NTSTATUS Status = STATUS_SUCCESS; PUCHAR Temp = NULL;
if ((Flags & ~(RTL_ENSURE_BUFFER_SIZE_NO_COPY)) != 0) { Status = STATUS_INVALID_PARAMETER; goto Exit; } if (Buffer == NULL) { Status = STATUS_INVALID_PARAMETER; goto Exit; }
if (Size <= Buffer->Size) { Status = STATUS_SUCCESS; goto Exit; } // Size <= Buffer->StaticSize does not imply static allocation, it
// could be heap allocation that the client poked smaller.
if (Buffer->Buffer == Buffer->StaticBuffer && Size <= Buffer->StaticSize) { Buffer->Size = Size; Status = STATUS_SUCCESS; goto Exit; } //
// The realloc case was messed up in Whistler, and got removed.
// Put it back in Blackcomb.
//
Temp = (PUCHAR)RtlAllocateStringRoutine(Size); if (Temp == NULL) { Status = STATUS_NO_MEMORY; goto Exit; }
if ((Flags & RTL_ENSURE_BUFFER_SIZE_NO_COPY) == 0) { RtlCopyMemory(Temp, Buffer->Buffer, Buffer->Size); }
if (RTLP_BUFFER_IS_HEAP_ALLOCATED(Buffer)) { RtlFreeStringRoutine(Buffer->Buffer); Buffer->Buffer = NULL; } ASSERT(Temp != NULL); Buffer->Buffer = Temp; Buffer->Size = Size; Status = STATUS_SUCCESS; Exit: return Status; }
} // end of namespace ShimLib
|