mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3434 lines
103 KiB
3434 lines
103 KiB
/*++
|
|
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
regtool.c
|
|
|
|
Abstract:
|
|
|
|
This file contains functions for supporting the registry tools
|
|
REGINI, REGDMP, REGDIR and REGFIND
|
|
|
|
Author:
|
|
|
|
Steve Wood (stevewo) 15-Nov-1995
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <tchar.h>
|
|
#include "regutil.h"
|
|
|
|
ULONG ValueBufferSize = (4096 * 100);
|
|
PVOID ValueBuffer;
|
|
|
|
|
|
UCHAR BlanksForPadding[] =
|
|
" ";
|
|
|
|
//
|
|
// routines for creating security descriptors (defined in regacl.c)
|
|
//
|
|
|
|
BOOLEAN
|
|
RegInitializeSecurity(
|
|
VOID
|
|
);
|
|
|
|
BOOLEAN
|
|
WINAPI
|
|
RegUnicodeToDWORD(
|
|
IN OUT PWSTR *String,
|
|
IN DWORD Base OPTIONAL,
|
|
OUT PDWORD Value
|
|
);
|
|
|
|
BOOLEAN
|
|
RegCreateSecurity(
|
|
IN PWSTR Description,
|
|
OUT PSECURITY_DESCRIPTOR SecurityDescriptor
|
|
);
|
|
|
|
BOOLEAN
|
|
RegFormatSecurity(
|
|
IN PSECURITY_DESCRIPTOR SecurityDescriptor,
|
|
OUT PWSTR AceList
|
|
);
|
|
|
|
VOID
|
|
RegDestroySecurity(
|
|
IN PSECURITY_DESCRIPTOR SecurityDescriptor
|
|
);
|
|
|
|
LONG
|
|
RegLoadHive(
|
|
IN PREG_CONTEXT RegistryContext,
|
|
IN PWSTR HiveFileName,
|
|
IN PWSTR HiveRootName
|
|
);
|
|
|
|
void
|
|
RegUnloadHive(
|
|
IN PREG_CONTEXT RegistryContext
|
|
);
|
|
|
|
|
|
|
|
struct {
|
|
PWSTR TypeName;
|
|
ULONG ValueType;
|
|
BOOLEAN GetDataFromBinaryFile;
|
|
BOOLEAN GetDataFromMultiSzFile;
|
|
BOOLEAN ParseDateTime;
|
|
} RegTypeNameTable[] = {
|
|
{L"REG_SZ", REG_SZ, FALSE, FALSE, FALSE},
|
|
{L"REG_EXPAND_SZ", REG_EXPAND_SZ, FALSE, FALSE, FALSE},
|
|
{L"REG_MULTI_SZ", REG_MULTI_SZ, FALSE, FALSE, FALSE},
|
|
{L"REG_MULTISZ_FILE", REG_MULTI_SZ, FALSE, TRUE, FALSE},
|
|
{L"REG_DWORD", REG_DWORD, FALSE, FALSE, FALSE},
|
|
{L"REG_NONE", REG_NONE, FALSE, FALSE, FALSE},
|
|
{L"REG_BINARY", REG_BINARY, FALSE, FALSE, FALSE},
|
|
{L"REG_BINARYFILE", REG_BINARY, TRUE, FALSE, FALSE},
|
|
{L"REG_DATE", REG_BINARY, FALSE, FALSE, TRUE},
|
|
{L"REG_RESOURCE_LIST", REG_RESOURCE_LIST, FALSE, FALSE, FALSE},
|
|
{L"REG_RESOURCE_REQUIREMENTS_LIST", REG_RESOURCE_REQUIREMENTS_LIST, FALSE, FALSE, FALSE},
|
|
{L"REG_RESOURCE_REQUIREMENTS", REG_RESOURCE_REQUIREMENTS_LIST, FALSE, FALSE, FALSE},
|
|
{L"REG_FULL_RESOURCE_DESCRIPTOR", REG_FULL_RESOURCE_DESCRIPTOR, FALSE, FALSE, FALSE},
|
|
{NULL, REG_NONE, FALSE, FALSE, FALSE}
|
|
};
|
|
|
|
struct {
|
|
PWSTR ValueName;
|
|
ULONG Value;
|
|
} RegValueNameTable[] = {
|
|
{L"ON", TRUE},
|
|
{L"YES", TRUE},
|
|
{L"TRUE", TRUE},
|
|
{L"OFF", FALSE},
|
|
{L"NO", FALSE},
|
|
{L"FALSE", FALSE},
|
|
{NULL, FALSE}
|
|
};
|
|
|
|
|
|
int
|
|
RegAnsiToUnicode(
|
|
LPCSTR Source,
|
|
PWSTR Destination,
|
|
ULONG NumberOfChars
|
|
)
|
|
{
|
|
int NumberOfXlatedChars;
|
|
|
|
if (NumberOfChars == 0) {
|
|
NumberOfChars = strlen( Source );
|
|
}
|
|
|
|
NumberOfXlatedChars = MultiByteToWideChar( CP_ACP,
|
|
MB_PRECOMPOSED,
|
|
Source,
|
|
NumberOfChars,
|
|
Destination,
|
|
NumberOfChars
|
|
);
|
|
|
|
Destination[ NumberOfXlatedChars ] = UNICODE_NULL;
|
|
|
|
if ( NumberOfXlatedChars == 0 ) {
|
|
SetLastError( ERROR_NO_UNICODE_TRANSLATION );
|
|
}
|
|
|
|
return NumberOfXlatedChars;
|
|
}
|
|
|
|
|
|
int
|
|
RegUnicodeToAnsi(
|
|
PCWSTR Source,
|
|
LPSTR Destination,
|
|
ULONG NumberOfChars
|
|
)
|
|
{
|
|
int NumberOfXlatedChars;
|
|
|
|
if (NumberOfChars == 0) {
|
|
NumberOfChars = wcslen( Source );
|
|
}
|
|
|
|
NumberOfXlatedChars = WideCharToMultiByte( CP_ACP,
|
|
0,
|
|
Source,
|
|
NumberOfChars,
|
|
Destination,
|
|
NumberOfChars * 2,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
Destination[ NumberOfXlatedChars ] = '\0';
|
|
|
|
if ( NumberOfXlatedChars == 0 ) {
|
|
SetLastError( ERROR_NO_UNICODE_TRANSLATION );
|
|
}
|
|
|
|
return NumberOfXlatedChars;
|
|
}
|
|
|
|
typedef
|
|
LONG
|
|
(APIENTRY *LPVMMREGMAPPREDEFKEYTOFILE_PROCEDURE)(
|
|
HKEY hKey,
|
|
LPCSTR lpFileName,
|
|
UINT Flags
|
|
);
|
|
|
|
typedef
|
|
LONG
|
|
(APIENTRY *LPVMMREGLOADKEY_PROCEDURE)(
|
|
HKEY hKey,
|
|
LPCSTR lpSubKey,
|
|
LPCSTR lpFileName
|
|
);
|
|
|
|
typedef
|
|
LONG
|
|
(APIENTRY *LPVMMREGUNLOADKEY_PROCEDURE)(
|
|
HKEY hKey,
|
|
LPCSTR lpSubKey
|
|
);
|
|
|
|
typedef
|
|
LONG
|
|
(APIENTRY *LPVMMREGCREATEKEY_PROCEDURE)(
|
|
HKEY hKey,
|
|
LPCSTR lpSubKey,
|
|
PHKEY lphSubKey
|
|
);
|
|
|
|
typedef
|
|
LONG
|
|
(APIENTRY *LPVMMREGDELETEKEY_PROCEDURE)(
|
|
HKEY hKey,
|
|
LPCSTR lpSubKey
|
|
);
|
|
|
|
typedef
|
|
LONG
|
|
(APIENTRY *LPVMMREGOPENKEY_PROCEDURE)(
|
|
HKEY hKey,
|
|
LPCSTR lpSubKey,
|
|
PHKEY lphSubKey
|
|
);
|
|
|
|
typedef
|
|
LONG
|
|
(APIENTRY *LPVMMREGFLUSHKEY_PROCEDURE)(
|
|
HKEY hKey
|
|
);
|
|
|
|
typedef
|
|
LONG
|
|
(APIENTRY *LPVMMREGCLOSEKEY_PROCEDURE)(
|
|
HKEY hKey
|
|
);
|
|
|
|
typedef
|
|
LONG
|
|
(APIENTRY *LPVMMREGQUERYINFOKEY_PROCEDURE)(
|
|
HKEY hKey,
|
|
LPCSTR lpClass,
|
|
LPDWORD lpcbClass,
|
|
LPDWORD lpReserved,
|
|
LPDWORD lpcSubKeys,
|
|
LPDWORD lpcbMaxSubKeyLen,
|
|
LPDWORD lpcbMaxClassLen,
|
|
LPDWORD lpcValues,
|
|
LPDWORD lpcbMaxValueName,
|
|
LPDWORD lpcbMaxValueData,
|
|
LPVOID lpcbSecurityDescriptor,
|
|
LPVOID lpftLastWriteTime
|
|
);
|
|
|
|
typedef
|
|
LONG
|
|
(APIENTRY *LPVMMREGENUMKEY_PROCEDURE)(
|
|
HKEY hKey,
|
|
DWORD Index,
|
|
LPSTR lpKeyName,
|
|
DWORD cbKeyName
|
|
);
|
|
|
|
typedef
|
|
LONG
|
|
(APIENTRY *LPVMMREGENUMVALUE_PROCEDURE)(
|
|
HKEY hKey,
|
|
DWORD Index,
|
|
LPSTR lpValueName,
|
|
LPDWORD lpcbValueName,
|
|
LPDWORD lpReserved,
|
|
LPDWORD lpType,
|
|
LPBYTE lpData,
|
|
LPDWORD lpcbData
|
|
);
|
|
|
|
typedef
|
|
LONG
|
|
(APIENTRY *LPVMMREGQUERYVALUEEX_PROCEDURE)(
|
|
HKEY hKey,
|
|
LPCSTR lpValueName,
|
|
LPDWORD lpReserved,
|
|
LPDWORD lpType,
|
|
LPBYTE lpData,
|
|
LPDWORD lpcbData
|
|
);
|
|
|
|
typedef
|
|
LONG
|
|
(APIENTRY *LPVMMREGSETVALUEEX_PROCEDURE)(
|
|
HKEY hKey,
|
|
LPCSTR lpValueName,
|
|
DWORD Reserved,
|
|
DWORD Type,
|
|
LPBYTE lpData,
|
|
DWORD cbData
|
|
);
|
|
|
|
typedef
|
|
LONG
|
|
(APIENTRY *LPVMMREGDELETEVALUE_PROCEDURE)(
|
|
HKEY hKey,
|
|
LPCSTR lpValueName
|
|
);
|
|
|
|
HMODULE hVMMREG32;
|
|
LPVMMREGMAPPREDEFKEYTOFILE_PROCEDURE _Win95RegMapPredefKeyToFile;
|
|
LPVMMREGLOADKEY_PROCEDURE _Win95RegLoadKey;
|
|
LPVMMREGUNLOADKEY_PROCEDURE _Win95RegUnLoadKey;
|
|
LPVMMREGCREATEKEY_PROCEDURE _Win95RegCreateKey;
|
|
LPVMMREGDELETEKEY_PROCEDURE _Win95RegDeleteKey;
|
|
LPVMMREGOPENKEY_PROCEDURE _Win95RegOpenKey;
|
|
LPVMMREGFLUSHKEY_PROCEDURE _Win95RegFlushKey;
|
|
LPVMMREGCLOSEKEY_PROCEDURE _Win95RegCloseKey;
|
|
LPVMMREGQUERYINFOKEY_PROCEDURE _Win95RegQueryInfoKey;
|
|
LPVMMREGENUMKEY_PROCEDURE _Win95RegEnumKey;
|
|
LPVMMREGENUMVALUE_PROCEDURE _Win95RegEnumValue;
|
|
LPVMMREGQUERYVALUEEX_PROCEDURE _Win95RegQueryValueEx;
|
|
LPVMMREGSETVALUEEX_PROCEDURE _Win95RegSetValueEx;
|
|
LPVMMREGDELETEVALUE_PROCEDURE _Win95RegDeleteValue;
|
|
|
|
BOOLEAN
|
|
RegInitWin95RegistryAccess(
|
|
PREG_CONTEXT RegistryContext,
|
|
PWSTR Win95Path,
|
|
PWSTR Win95UserPath
|
|
)
|
|
{
|
|
LONG Error;
|
|
char Buffer[ MAX_PATH+1 ];
|
|
|
|
if ((hVMMREG32 = LoadLibrary( L"VMMREG32" )) == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
_Win95RegMapPredefKeyToFile = (LPVMMREGMAPPREDEFKEYTOFILE_PROCEDURE)GetProcAddress( hVMMREG32, "VMMRegMapPredefKeyToFile" );
|
|
_Win95RegLoadKey = (LPVMMREGLOADKEY_PROCEDURE )GetProcAddress( hVMMREG32, "VMMRegLoadKey" );
|
|
_Win95RegUnLoadKey = (LPVMMREGUNLOADKEY_PROCEDURE )GetProcAddress( hVMMREG32, "VMMRegUnLoadKey" );
|
|
_Win95RegCreateKey = (LPVMMREGCREATEKEY_PROCEDURE )GetProcAddress( hVMMREG32, "VMMRegCreateKey" );
|
|
_Win95RegDeleteKey = (LPVMMREGDELETEKEY_PROCEDURE )GetProcAddress( hVMMREG32, "VMMRegDeleteKey" );
|
|
_Win95RegOpenKey = (LPVMMREGOPENKEY_PROCEDURE )GetProcAddress( hVMMREG32, "VMMRegOpenKey" );
|
|
_Win95RegFlushKey = (LPVMMREGFLUSHKEY_PROCEDURE )GetProcAddress( hVMMREG32, "VMMRegFlushKey" );
|
|
_Win95RegCloseKey = (LPVMMREGCLOSEKEY_PROCEDURE )GetProcAddress( hVMMREG32, "VMMRegCloseKey" );
|
|
_Win95RegQueryInfoKey = (LPVMMREGQUERYINFOKEY_PROCEDURE )GetProcAddress( hVMMREG32, "VMMRegQueryInfoKey" );
|
|
_Win95RegEnumKey = (LPVMMREGENUMKEY_PROCEDURE )GetProcAddress( hVMMREG32, "VMMRegEnumKey" );
|
|
_Win95RegEnumValue = (LPVMMREGENUMVALUE_PROCEDURE )GetProcAddress( hVMMREG32, "VMMRegEnumValue" );
|
|
_Win95RegQueryValueEx = (LPVMMREGQUERYVALUEEX_PROCEDURE )GetProcAddress( hVMMREG32, "VMMRegQueryValueEx" );
|
|
_Win95RegSetValueEx = (LPVMMREGSETVALUEEX_PROCEDURE )GetProcAddress( hVMMREG32, "VMMRegSetValueEx" );
|
|
_Win95RegDeleteValue = (LPVMMREGDELETEVALUE_PROCEDURE )GetProcAddress( hVMMREG32, "VMMRegDeleteValue" );
|
|
|
|
if ((_Win95RegMapPredefKeyToFile == NULL) ||
|
|
(_Win95RegLoadKey == NULL) ||
|
|
(_Win95RegUnLoadKey == NULL) ||
|
|
(_Win95RegCreateKey == NULL) ||
|
|
(_Win95RegDeleteKey == NULL) ||
|
|
(_Win95RegOpenKey == NULL) ||
|
|
(_Win95RegFlushKey == NULL) ||
|
|
(_Win95RegCloseKey == NULL) ||
|
|
(_Win95RegQueryInfoKey == NULL) ||
|
|
(_Win95RegEnumKey == NULL) ||
|
|
(_Win95RegEnumValue == NULL) ||
|
|
(_Win95RegQueryValueEx == NULL) ||
|
|
(_Win95RegSetValueEx == NULL) ||
|
|
(_Win95RegDeleteValue == NULL)
|
|
) {
|
|
FreeLibrary( hVMMREG32 );
|
|
SetLastError( ERROR_PROC_NOT_FOUND );
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Map HKEY_LOCAL_MACHINE of Win95 hive
|
|
//
|
|
|
|
RegUnicodeToAnsi( Win95Path, Buffer, 0 );
|
|
strcat( Buffer, "\\system.dat" );
|
|
Error = (_Win95RegMapPredefKeyToFile)( HKEY_LOCAL_MACHINE, Buffer, 0 );
|
|
if (Error == NO_ERROR) {
|
|
RegistryContext->MachineRoot = HKEY_LOCAL_MACHINE;
|
|
RegUnicodeToAnsi( Win95Path, Buffer, 0 );
|
|
strcat( Buffer, "\\user.dat" );
|
|
Error = (_Win95RegMapPredefKeyToFile)( HKEY_USERS, Buffer, 0 );
|
|
if (Error == NO_ERROR) {
|
|
RegistryContext->UsersRoot = HKEY_USERS;
|
|
Error = (_Win95RegOpenKey)( HKEY_USERS, ".Default", &RegistryContext->CurrentUserRoot );
|
|
}
|
|
}
|
|
|
|
if (Error != NO_ERROR) {
|
|
if (RegistryContext->MachineRoot != NULL) {
|
|
(_Win95RegMapPredefKeyToFile)( RegistryContext->MachineRoot, NULL, 0 );
|
|
}
|
|
|
|
if (RegistryContext->UsersRoot) {
|
|
(_Win95RegMapPredefKeyToFile)( RegistryContext->UsersRoot, NULL, 0 );
|
|
}
|
|
|
|
FreeLibrary( hVMMREG32 );
|
|
SetLastError( Error );
|
|
return FALSE;
|
|
}
|
|
|
|
wcscpy( RegistryContext->UsersPath, L"\\Registry\\Users" );
|
|
wcscpy( RegistryContext->CurrentUserPath, RegistryContext->UsersPath );
|
|
wcscat( RegistryContext->CurrentUserPath, L"\\.Default" );
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOLEAN PrivilegeEnabled;
|
|
BOOLEAN RestoreWasEnabled;
|
|
BOOLEAN BackupWasEnabled;
|
|
|
|
BOOLEAN
|
|
RTEnableBackupRestorePrivilege( void )
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Try to enable backup and restore privileges
|
|
//
|
|
Status = RtlAdjustPrivilege( SE_RESTORE_PRIVILEGE,
|
|
TRUE, // Enable
|
|
FALSE, // Not impersonating
|
|
&RestoreWasEnabled // previous state
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
return FALSE;
|
|
}
|
|
|
|
Status = RtlAdjustPrivilege( SE_BACKUP_PRIVILEGE,
|
|
TRUE, // Enable
|
|
FALSE, // Not impersonating
|
|
&BackupWasEnabled // previous state
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
return FALSE;
|
|
}
|
|
|
|
PrivilegeEnabled = TRUE;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
void
|
|
RTDisableBackupRestorePrivilege( void )
|
|
{
|
|
//
|
|
// Restore privileges to what they were
|
|
//
|
|
|
|
RtlAdjustPrivilege( SE_RESTORE_PRIVILEGE,
|
|
RestoreWasEnabled,
|
|
FALSE,
|
|
&RestoreWasEnabled
|
|
);
|
|
|
|
RtlAdjustPrivilege( SE_BACKUP_PRIVILEGE,
|
|
BackupWasEnabled,
|
|
FALSE,
|
|
&BackupWasEnabled
|
|
);
|
|
|
|
PrivilegeEnabled = FALSE;
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
RTInitialize( void )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
DLL initialization function.
|
|
|
|
Arguments:
|
|
|
|
hInstance - Instance handle
|
|
Reason - Reason for the entrypoint being called
|
|
Context - Context record
|
|
|
|
Return Value:
|
|
|
|
TRUE - Initialization succeeded
|
|
FALSE - Initialization failed
|
|
|
|
--*/
|
|
|
|
{
|
|
ValueBuffer = VirtualAlloc( NULL, ValueBufferSize, MEM_COMMIT, PAGE_READWRITE );
|
|
if (ValueBuffer == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (!RegInitializeSecurity()) {
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
LONG
|
|
RTConnectToRegistry(
|
|
IN PWSTR MachineName,
|
|
IN PWSTR HiveFileName,
|
|
IN PWSTR HiveRootName,
|
|
IN PWSTR Win95Path,
|
|
IN PWSTR Win95UserName,
|
|
OUT PWSTR *DefaultRootKeyName,
|
|
OUT PREG_CONTEXT RegistryContext
|
|
)
|
|
{
|
|
LONG Error;
|
|
|
|
if (MachineName != NULL) {
|
|
if (HiveRootName || HiveFileName || Win95Path || Win95UserName) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
Error = RegConnectRegistry( MachineName, HKEY_LOCAL_MACHINE, (PHKEY)&RegistryContext->MachineRoot );
|
|
if (Error == NO_ERROR) {
|
|
Error = RegConnectRegistry( MachineName, HKEY_USERS, (PHKEY)&RegistryContext->UsersRoot );
|
|
if (Error == NO_ERROR) {
|
|
Error = RegOpenKey( RegistryContext->UsersRoot, L".Default", &RegistryContext->CurrentUserRoot );
|
|
}
|
|
}
|
|
|
|
if (Error != NO_ERROR) {
|
|
if (RegistryContext->MachineRoot != NULL) {
|
|
RegCloseKey( RegistryContext->MachineRoot );
|
|
RegistryContext->MachineRoot = NULL;
|
|
}
|
|
|
|
if (RegistryContext->UsersRoot != NULL) {
|
|
RegCloseKey( RegistryContext->UsersRoot );
|
|
RegistryContext->UsersRoot = NULL;
|
|
}
|
|
|
|
return Error;
|
|
}
|
|
|
|
wcscpy( RegistryContext->MachinePath, L"\\Registry\\Machine" );
|
|
wcscpy( RegistryContext->UsersPath, L"\\Registry\\Users" );
|
|
wcscpy( RegistryContext->CurrentUserPath, L"\\Registry\\Users\\.Default" );
|
|
RegistryContext->Target = REG_TARGET_REMOTE_REGISTRY;
|
|
}
|
|
else
|
|
if (HiveRootName != NULL || HiveFileName != NULL) {
|
|
if (HiveRootName == NULL || HiveFileName == NULL ||
|
|
Win95Path != NULL || Win95UserName != NULL
|
|
) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (!PrivilegeEnabled && !RTEnableBackupRestorePrivilege()) {
|
|
return ERROR_PRIVILEGE_NOT_HELD;
|
|
}
|
|
|
|
RegistryContext->MachineRoot = NULL;
|
|
RegistryContext->UsersRoot = NULL;
|
|
RegistryContext->CurrentUserRoot = NULL;
|
|
|
|
Error = RegLoadHive( RegistryContext, HiveFileName, HiveRootName );
|
|
if (Error != NO_ERROR) {
|
|
return Error;
|
|
}
|
|
|
|
if (DefaultRootKeyName != NULL && *DefaultRootKeyName == NULL) {
|
|
*DefaultRootKeyName = HiveRootName;
|
|
}
|
|
RegistryContext->Target = REG_TARGET_HIVE_REGISTRY;
|
|
}
|
|
else
|
|
if (Win95Path != NULL || Win95UserName != NULL) {
|
|
if (!RegInitWin95RegistryAccess( RegistryContext,
|
|
Win95Path,
|
|
Win95UserName
|
|
)
|
|
) {
|
|
return GetLastError();
|
|
}
|
|
|
|
RegistryContext->Target = REG_TARGET_WIN95_REGISTRY;
|
|
}
|
|
else {
|
|
NTSTATUS Status;
|
|
UNICODE_STRING CurrentUserKeyPath;
|
|
|
|
RegistryContext->MachineRoot = HKEY_LOCAL_MACHINE;
|
|
RegistryContext->UsersRoot = HKEY_USERS;
|
|
RegistryContext->CurrentUserRoot = HKEY_CURRENT_USER;
|
|
|
|
wcscpy( RegistryContext->MachinePath, L"\\Registry\\Machine" );
|
|
wcscpy( RegistryContext->UsersPath, L"\\Registry\\Users" );
|
|
Status = RtlFormatCurrentUserKeyPath( &CurrentUserKeyPath );
|
|
if (!NT_SUCCESS( Status )) {
|
|
SetLastError( RtlNtStatusToDosError( Status ) );
|
|
return FALSE;
|
|
}
|
|
|
|
wcscpy( RegistryContext->CurrentUserPath, CurrentUserKeyPath.Buffer );
|
|
RtlFreeUnicodeString( &CurrentUserKeyPath );
|
|
|
|
RegistryContext->Target = REG_TARGET_LOCAL_REGISTRY;
|
|
}
|
|
|
|
if (DefaultRootKeyName != NULL && *DefaultRootKeyName == NULL) {
|
|
*DefaultRootKeyName = L"\\Registry";
|
|
}
|
|
RegistryContext->MachinePathLength = wcslen( RegistryContext->MachinePath );
|
|
RegistryContext->UsersPathLength = wcslen( RegistryContext->UsersPath );
|
|
RegistryContext->CurrentUserPathLength = wcslen( RegistryContext->CurrentUserPath );
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
LONG
|
|
RTDisconnectFromRegistry(
|
|
IN PREG_CONTEXT RegistryContext
|
|
)
|
|
{
|
|
switch( RegistryContext->Target ) {
|
|
case REG_TARGET_DISCONNECTED:
|
|
break;
|
|
|
|
case REG_TARGET_LOCAL_REGISTRY:
|
|
break;
|
|
|
|
case REG_TARGET_REMOTE_REGISTRY:
|
|
break;
|
|
|
|
case REG_TARGET_WIN95_REGISTRY:
|
|
// (_Win95RegMapPredefKeyToFile)( RegistryContext->MachineRoot, NULL, 0 );
|
|
// (_Win95RegMapPredefKeyToFile)( RegistryContext->UsersRoot, NULL, 0 );
|
|
(_Win95RegCloseKey)( RegistryContext->CurrentUserRoot );
|
|
FreeLibrary( hVMMREG32 );
|
|
break;
|
|
|
|
case REG_TARGET_HIVE_REGISTRY:
|
|
RegUnloadHive( RegistryContext );
|
|
break;
|
|
}
|
|
|
|
if (PrivilegeEnabled) {
|
|
RTDisableBackupRestorePrivilege();
|
|
}
|
|
|
|
RegistryContext->Target = REG_TARGET_DISCONNECTED;
|
|
return NO_ERROR;
|
|
}
|
|
|
|
UNICODE_STRING RegHiveRootName;
|
|
|
|
LONG
|
|
RegLoadHive(
|
|
IN PREG_CONTEXT RegistryContext,
|
|
IN PWSTR HiveFileName,
|
|
IN PWSTR HiveRootName
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
UNICODE_STRING NtFileName;
|
|
OBJECT_ATTRIBUTES File;
|
|
SECURITY_DESCRIPTOR SecurityDescriptor;
|
|
|
|
//
|
|
// Create security descriptor with a NULL Dacl. This is necessary
|
|
// because the security descriptor we pass in gets used in system
|
|
// context. So if we just pass in NULL, then the Wrong Thing happens.
|
|
// (but only on NTFS!)
|
|
//
|
|
Status = RtlCreateSecurityDescriptor( &SecurityDescriptor,
|
|
SECURITY_DESCRIPTOR_REVISION
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
return RtlNtStatusToDosError( Status );
|
|
}
|
|
|
|
Status = RtlSetDaclSecurityDescriptor( &SecurityDescriptor,
|
|
TRUE, // Dacl present
|
|
NULL, // but grants all access
|
|
FALSE
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
return RtlNtStatusToDosError( Status );
|
|
}
|
|
|
|
if (!RtlDosPathNameToNtPathName_U( HiveFileName,
|
|
&NtFileName,
|
|
NULL,
|
|
NULL
|
|
)
|
|
) {
|
|
return ERROR_BAD_PATHNAME;
|
|
}
|
|
InitializeObjectAttributes( &File,
|
|
&NtFileName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
&SecurityDescriptor
|
|
);
|
|
|
|
RtlInitUnicodeString( &RegHiveRootName, L"\\Registry");
|
|
InitializeObjectAttributes( &RegistryContext->HiveRootKey,
|
|
&RegHiveRootName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
Status = NtOpenKey( &RegistryContext->HiveRootHandle,
|
|
MAXIMUM_ALLOWED,
|
|
&RegistryContext->HiveRootKey
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
return RtlNtStatusToDosError( Status );
|
|
}
|
|
|
|
RtlInitUnicodeString( &RegHiveRootName, HiveRootName );
|
|
InitializeObjectAttributes( &RegistryContext->HiveRootKey,
|
|
&RegHiveRootName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
RegistryContext->HiveRootHandle,
|
|
NULL
|
|
);
|
|
NtUnloadKey( &RegistryContext->HiveRootKey );
|
|
Status = NtLoadKey( &RegistryContext->HiveRootKey, &File );
|
|
if (!NT_SUCCESS( Status )) {
|
|
return RtlNtStatusToDosError( Status );
|
|
}
|
|
|
|
return NO_ERROR;
|
|
|
|
}
|
|
|
|
void
|
|
RegUnloadHive(
|
|
IN PREG_CONTEXT RegistryContext
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
HANDLE Handle;
|
|
PREG_CONTEXT_OPEN_HIVE_KEY p, p1;
|
|
|
|
Status = NtOpenKey( &Handle,
|
|
MAXIMUM_ALLOWED,
|
|
&RegistryContext->HiveRootKey
|
|
);
|
|
if (NT_SUCCESS( Status )) {
|
|
NtFlushKey( Handle );
|
|
NtClose( Handle );
|
|
}
|
|
|
|
p = RegistryContext->OpenHiveKeys;
|
|
while (p) {
|
|
RegCloseKey( p->KeyHandle );
|
|
p1 = p;
|
|
p = p->Next;
|
|
HeapFree( GetProcessHeap(), 0, p1 );
|
|
};
|
|
|
|
do {
|
|
Status = NtUnloadKey( &RegistryContext->HiveRootKey );
|
|
}
|
|
while (NT_SUCCESS( Status ) );
|
|
|
|
NtClose( RegistryContext->HiveRootHandle );
|
|
return;
|
|
}
|
|
|
|
|
|
void
|
|
RegRememberOpenKey(
|
|
IN PREG_CONTEXT RegistryContext,
|
|
IN HKEY KeyHandle
|
|
)
|
|
{
|
|
PREG_CONTEXT_OPEN_HIVE_KEY p, *pp;
|
|
|
|
pp = &RegistryContext->OpenHiveKeys;
|
|
while ((p = *pp) != NULL) {
|
|
if (p->KeyHandle == KeyHandle) {
|
|
p->ReferenceCount += 1;
|
|
return;
|
|
}
|
|
else {
|
|
pp = &p->Next;
|
|
}
|
|
}
|
|
|
|
p = HeapAlloc( GetProcessHeap(), 0, sizeof( *p ) );
|
|
if (p != NULL) {
|
|
p->KeyHandle = KeyHandle;
|
|
p->ReferenceCount = 1;
|
|
p->Next = NULL;
|
|
*pp = p;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void
|
|
RegForgetOpenKey(
|
|
IN PREG_CONTEXT RegistryContext,
|
|
IN HKEY KeyHandle
|
|
)
|
|
{
|
|
PREG_CONTEXT_OPEN_HIVE_KEY p, *pp;
|
|
|
|
pp = &RegistryContext->OpenHiveKeys;
|
|
while ((p = *pp) != NULL) {
|
|
if (p->KeyHandle == KeyHandle) {
|
|
p->ReferenceCount -= 1;
|
|
if (p->ReferenceCount == 0) {
|
|
*pp = p->Next;
|
|
HeapFree( GetProcessHeap(), 0, p );
|
|
return;
|
|
}
|
|
}
|
|
else {
|
|
pp = &p->Next;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
BOOLEAN
|
|
RegCheckPrefix(
|
|
IN OUT PCWSTR *s,
|
|
IN PCWSTR Prefix,
|
|
IN ULONG PrefixLength
|
|
)
|
|
{
|
|
if (PrefixLength == 0) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (!_wcsnicmp( *s, Prefix, PrefixLength )) {
|
|
*s += PrefixLength;
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
RegValidateKeyPath(
|
|
IN PREG_CONTEXT RegistryContext,
|
|
IN OUT PHKEY RootKeyHandle,
|
|
IN OUT PCWSTR *SubKeyName
|
|
)
|
|
{
|
|
PCWSTR s;
|
|
|
|
s = *SubKeyName;
|
|
if (*RootKeyHandle == NULL) {
|
|
if (RegCheckPrefix( &s, L"USER:", 5 ) ||
|
|
RegCheckPrefix( &s, L"HKEY_CURRENT_USER", 17 )
|
|
) {
|
|
if (RegistryContext->CurrentUserRoot == NULL) {
|
|
SetLastError( ERROR_BAD_PATHNAME );
|
|
return FALSE;
|
|
}
|
|
|
|
if (*s == L'\\') {
|
|
s += 1;
|
|
}
|
|
else
|
|
if (s[-1] != L':' && *s != UNICODE_NULL) {
|
|
SetLastError( ERROR_BAD_PATHNAME );
|
|
return FALSE;
|
|
}
|
|
|
|
*RootKeyHandle = RegistryContext->CurrentUserRoot;
|
|
}
|
|
else
|
|
if (RegCheckPrefix( &s, L"HKEY_LOCAL_MACHINE", 18 )) {
|
|
if (*s == L'\\') {
|
|
s += 1;
|
|
}
|
|
else
|
|
if (*s != UNICODE_NULL) {
|
|
SetLastError( ERROR_BAD_PATHNAME );
|
|
return FALSE;
|
|
}
|
|
|
|
*RootKeyHandle = RegistryContext->MachineRoot;
|
|
}
|
|
else
|
|
if (RegCheckPrefix( &s, L"HKEY_USERS", 10 )) {
|
|
if (*s == L'\\') {
|
|
s += 1;
|
|
}
|
|
else
|
|
if (*s != UNICODE_NULL) {
|
|
SetLastError( ERROR_BAD_PATHNAME );
|
|
return FALSE;
|
|
}
|
|
|
|
*RootKeyHandle = RegistryContext->UsersRoot;
|
|
}
|
|
else
|
|
if (*s != L'\\') {
|
|
SetLastError( ERROR_BAD_PATHNAME );
|
|
return FALSE;
|
|
}
|
|
else
|
|
if (RegCheckPrefix( &s, RegistryContext->MachinePath, RegistryContext->MachinePathLength )) {
|
|
*RootKeyHandle = RegistryContext->MachineRoot;
|
|
if (*s == L'\\') {
|
|
s += 1;
|
|
}
|
|
}
|
|
else
|
|
if (RegCheckPrefix( &s, RegistryContext->UsersPath, RegistryContext->UsersPathLength )) {
|
|
*RootKeyHandle = RegistryContext->UsersRoot;
|
|
if (*s == L'\\') {
|
|
s += 1;
|
|
}
|
|
}
|
|
else
|
|
if (RegCheckPrefix( &s, RegistryContext->CurrentUserPath, RegistryContext->CurrentUserPathLength )) {
|
|
*RootKeyHandle = RegistryContext->CurrentUserRoot;
|
|
if (*s == L'\\') {
|
|
s += 1;
|
|
}
|
|
}
|
|
else
|
|
if (!_wcsicmp( *SubKeyName, L"\\Registry" )) {
|
|
*RootKeyHandle = NULL;
|
|
}
|
|
else {
|
|
SetLastError( ERROR_BAD_PATHNAME );
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
if (*s == L'\\') {
|
|
SetLastError( ERROR_BAD_PATHNAME );
|
|
return FALSE;
|
|
}
|
|
|
|
*SubKeyName = s;
|
|
return TRUE;
|
|
}
|
|
|
|
LONG
|
|
RTCreateKey(
|
|
IN PREG_CONTEXT RegistryContext,
|
|
IN HKEY RootKeyHandle,
|
|
IN PCWSTR SubKeyName,
|
|
IN ACCESS_MASK DesiredAccess,
|
|
IN ULONG CreateOptions,
|
|
IN PVOID SecurityDescriptor,
|
|
OUT PHKEY ReturnedKeyHandle,
|
|
OUT PULONG Disposition
|
|
)
|
|
{
|
|
LONG Error;
|
|
|
|
if (!RegValidateKeyPath( RegistryContext, &RootKeyHandle, &SubKeyName )) {
|
|
return GetLastError();
|
|
}
|
|
|
|
if (RootKeyHandle == NULL) {
|
|
*Disposition = REG_OPENED_EXISTING_KEY;
|
|
*ReturnedKeyHandle = HKEY_REGISTRY_ROOT;
|
|
return NO_ERROR;
|
|
}
|
|
else
|
|
if (RootKeyHandle == HKEY_REGISTRY_ROOT) {
|
|
*ReturnedKeyHandle = NULL;
|
|
if (!_wcsicmp( SubKeyName, L"Machine" )) {
|
|
*ReturnedKeyHandle = RegistryContext->MachineRoot;
|
|
}
|
|
else
|
|
if (!_wcsicmp( SubKeyName, L"Users" )) {
|
|
*ReturnedKeyHandle = RegistryContext->UsersRoot;
|
|
}
|
|
|
|
|
|
if (*ReturnedKeyHandle != NULL) {
|
|
return NO_ERROR;
|
|
}
|
|
else {
|
|
return ERROR_PATH_NOT_FOUND;
|
|
}
|
|
}
|
|
|
|
if (RegistryContext->Target == REG_TARGET_WIN95_REGISTRY) {
|
|
UCHAR AnsiSubKeyName[ MAX_PATH ], *p;
|
|
|
|
if (SubKeyName != NULL) {
|
|
if (!RegUnicodeToAnsi( SubKeyName, AnsiSubKeyName, 0 )) {
|
|
return GetLastError();
|
|
}
|
|
|
|
p = AnsiSubKeyName;
|
|
}
|
|
else {
|
|
p = NULL;
|
|
}
|
|
|
|
Error = (_Win95RegOpenKey)( RootKeyHandle, p, ReturnedKeyHandle );
|
|
if (Error == NO_ERROR) {
|
|
*Disposition = REG_OPENED_EXISTING_KEY;
|
|
}
|
|
else {
|
|
Error = (_Win95RegCreateKey)( RootKeyHandle, p, ReturnedKeyHandle );
|
|
if (Error == NO_ERROR) {
|
|
*Disposition = REG_CREATED_NEW_KEY;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
SECURITY_ATTRIBUTES SecurityAttributes;
|
|
|
|
SecurityAttributes.nLength = sizeof( SecurityAttributes );
|
|
SecurityAttributes.lpSecurityDescriptor = SecurityDescriptor;
|
|
SecurityAttributes.bInheritHandle = FALSE;
|
|
Error = RegCreateKeyEx( RootKeyHandle,
|
|
SubKeyName,
|
|
0,
|
|
NULL,
|
|
CreateOptions,
|
|
(REGSAM)DesiredAccess,
|
|
&SecurityAttributes,
|
|
ReturnedKeyHandle,
|
|
Disposition
|
|
);
|
|
if (Error == NO_ERROR &&
|
|
RegistryContext->Target == REG_TARGET_HIVE_REGISTRY
|
|
) {
|
|
RegRememberOpenKey( RegistryContext, *ReturnedKeyHandle );
|
|
}
|
|
|
|
if (Error == NO_ERROR &&
|
|
*Disposition == REG_OPENED_EXISTING_KEY &&
|
|
SecurityDescriptor != NULL
|
|
) {
|
|
RegSetKeySecurity( *ReturnedKeyHandle,
|
|
DACL_SECURITY_INFORMATION,
|
|
SecurityDescriptor
|
|
);
|
|
}
|
|
}
|
|
|
|
return Error;
|
|
}
|
|
|
|
LONG
|
|
RTOpenKey(
|
|
IN PREG_CONTEXT RegistryContext,
|
|
IN HKEY RootKeyHandle,
|
|
IN PCWSTR SubKeyName,
|
|
IN ACCESS_MASK DesiredAccess,
|
|
IN ULONG OpenOptions,
|
|
OUT PHKEY ReturnedKeyHandle
|
|
)
|
|
{
|
|
LONG Error;
|
|
|
|
if (!RegValidateKeyPath( RegistryContext, &RootKeyHandle, &SubKeyName )) {
|
|
return GetLastError();
|
|
}
|
|
|
|
if (RootKeyHandle == NULL) {
|
|
*ReturnedKeyHandle = HKEY_REGISTRY_ROOT;
|
|
return NO_ERROR;
|
|
}
|
|
else
|
|
if (RootKeyHandle == HKEY_REGISTRY_ROOT) {
|
|
*ReturnedKeyHandle = NULL;
|
|
if (!_wcsicmp( SubKeyName, L"Machine" )) {
|
|
*ReturnedKeyHandle = RegistryContext->MachineRoot;
|
|
}
|
|
else
|
|
if (!_wcsicmp( SubKeyName, L"Users" )) {
|
|
*ReturnedKeyHandle = RegistryContext->UsersRoot;
|
|
}
|
|
|
|
if (*ReturnedKeyHandle != NULL) {
|
|
return NO_ERROR;
|
|
}
|
|
else {
|
|
return ERROR_PATH_NOT_FOUND;
|
|
}
|
|
}
|
|
|
|
if (RegistryContext->Target == REG_TARGET_WIN95_REGISTRY) {
|
|
UCHAR AnsiSubKeyName[ MAX_PATH ], *p;
|
|
|
|
if (SubKeyName != NULL) {
|
|
if (!RegUnicodeToAnsi( SubKeyName, AnsiSubKeyName, 0 )) {
|
|
return GetLastError();
|
|
}
|
|
|
|
p = AnsiSubKeyName;
|
|
}
|
|
else {
|
|
p = NULL;
|
|
}
|
|
|
|
return (_Win95RegOpenKey)( RootKeyHandle, p, ReturnedKeyHandle );
|
|
}
|
|
else {
|
|
Error = RegOpenKeyEx( RootKeyHandle,
|
|
SubKeyName,
|
|
OpenOptions,
|
|
DesiredAccess,
|
|
ReturnedKeyHandle
|
|
);
|
|
if (Error == NO_ERROR &&
|
|
RegistryContext->Target == REG_TARGET_HIVE_REGISTRY
|
|
) {
|
|
RegRememberOpenKey( RegistryContext, *ReturnedKeyHandle );
|
|
}
|
|
|
|
return Error;
|
|
}
|
|
}
|
|
|
|
LONG
|
|
RTCloseKey(
|
|
IN PREG_CONTEXT RegistryContext,
|
|
IN HKEY KeyHandle
|
|
)
|
|
{
|
|
LONG Error;
|
|
|
|
if (KeyHandle == HKEY_REGISTRY_ROOT) {
|
|
return NO_ERROR;
|
|
}
|
|
else
|
|
if (RegistryContext->Target == REG_TARGET_WIN95_REGISTRY) {
|
|
return (_Win95RegCloseKey)( KeyHandle );
|
|
}
|
|
else {
|
|
Error = RegCloseKey( KeyHandle );
|
|
if (Error == NO_ERROR &&
|
|
RegistryContext->Target == REG_TARGET_HIVE_REGISTRY
|
|
) {
|
|
RegForgetOpenKey( RegistryContext, KeyHandle );
|
|
}
|
|
|
|
return Error;
|
|
}
|
|
}
|
|
|
|
LONG
|
|
RTFlushKey(
|
|
IN PREG_CONTEXT RegistryContext,
|
|
IN HKEY KeyHandle
|
|
)
|
|
{
|
|
if (KeyHandle == HKEY_REGISTRY_ROOT) {
|
|
return NO_ERROR;
|
|
}
|
|
else
|
|
if (RegistryContext->Target == REG_TARGET_WIN95_REGISTRY) {
|
|
return (_Win95RegFlushKey)( KeyHandle );
|
|
}
|
|
else {
|
|
return RegFlushKey( KeyHandle );
|
|
}
|
|
}
|
|
|
|
LONG
|
|
RTEnumerateKey(
|
|
IN PREG_CONTEXT RegistryContext,
|
|
IN HKEY KeyHandle,
|
|
IN ULONG Index,
|
|
OUT PFILETIME LastWriteTime,
|
|
IN OUT PULONG KeyNameLength,
|
|
OUT PWSTR KeyName
|
|
)
|
|
{
|
|
ULONG Error;
|
|
|
|
if (KeyHandle == HKEY_REGISTRY_ROOT) {
|
|
if (Index == 0) {
|
|
if (*KeyNameLength <= 7) {
|
|
return ERROR_MORE_DATA;
|
|
}
|
|
else {
|
|
wcscpy( KeyName, L"Machine" );
|
|
return NO_ERROR;
|
|
}
|
|
}
|
|
else
|
|
if (Index == 1) {
|
|
if (*KeyNameLength <= 5) {
|
|
return ERROR_MORE_DATA;
|
|
}
|
|
else {
|
|
wcscpy( KeyName, L"Users" );
|
|
return NO_ERROR;
|
|
}
|
|
}
|
|
else {
|
|
return ERROR_NO_MORE_ITEMS;
|
|
}
|
|
}
|
|
else
|
|
if (RegistryContext->Target == REG_TARGET_WIN95_REGISTRY) {
|
|
UCHAR AnsiKeyName[ MAX_PATH ];
|
|
ULONG AnsiKeyNameLength;
|
|
|
|
AnsiKeyNameLength = sizeof( AnsiKeyName );
|
|
Error = _Win95RegEnumKey( KeyHandle,
|
|
Index,
|
|
AnsiKeyName,
|
|
AnsiKeyNameLength
|
|
);
|
|
if (Error == NO_ERROR) {
|
|
if (strlen( AnsiKeyName ) >= *KeyNameLength) {
|
|
return ERROR_MORE_DATA;
|
|
}
|
|
|
|
*KeyNameLength = RegAnsiToUnicode( AnsiKeyName, KeyName, AnsiKeyNameLength );
|
|
|
|
if (*KeyNameLength == 0) {
|
|
return GetLastError();
|
|
}
|
|
|
|
RtlZeroMemory( LastWriteTime, sizeof( *LastWriteTime ) );
|
|
}
|
|
}
|
|
else {
|
|
Error = RegEnumKeyEx( KeyHandle,
|
|
Index,
|
|
KeyName,
|
|
KeyNameLength,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
LastWriteTime
|
|
);
|
|
}
|
|
|
|
return Error;
|
|
}
|
|
|
|
LONG
|
|
RTEnumerateValueKey(
|
|
IN PREG_CONTEXT RegistryContext,
|
|
IN HKEY KeyHandle,
|
|
IN ULONG Index,
|
|
OUT PULONG ValueType,
|
|
IN OUT PULONG ValueNameLength,
|
|
OUT PWSTR ValueName,
|
|
IN OUT PULONG ValueDataLength,
|
|
OUT PVOID ValueData
|
|
)
|
|
{
|
|
ULONG Error;
|
|
|
|
if (KeyHandle == HKEY_REGISTRY_ROOT) {
|
|
return ERROR_NO_MORE_ITEMS;
|
|
}
|
|
else
|
|
if (RegistryContext->Target == REG_TARGET_WIN95_REGISTRY) {
|
|
UCHAR AnsiValueName[ MAX_PATH ];
|
|
ULONG AnsiValueNameLength;
|
|
LPSTR AnsiValueData;
|
|
ULONG OriginalValueDataLength;
|
|
|
|
AnsiValueNameLength = sizeof( AnsiValueName );
|
|
OriginalValueDataLength = *ValueDataLength;
|
|
Error = (_Win95RegEnumValue)( KeyHandle,
|
|
Index,
|
|
AnsiValueName,
|
|
&AnsiValueNameLength,
|
|
0,
|
|
ValueType,
|
|
ValueData,
|
|
ValueDataLength
|
|
);
|
|
|
|
if (Error != NO_ERROR) {
|
|
return Error;
|
|
}
|
|
|
|
if (AnsiValueNameLength >= *ValueNameLength) {
|
|
return ERROR_MORE_DATA;
|
|
}
|
|
|
|
if (RegAnsiToUnicode( AnsiValueName, ValueName, AnsiValueNameLength ) == 0) {
|
|
return GetLastError();
|
|
}
|
|
|
|
if (*ValueType == REG_SZ) {
|
|
AnsiValueData = HeapAlloc( GetProcessHeap(), 0, *ValueDataLength );
|
|
if (AnsiValueData == NULL) {
|
|
return ERROR_OUTOFMEMORY;
|
|
}
|
|
|
|
RtlMoveMemory( AnsiValueData, ValueData, *ValueDataLength );
|
|
if (RegAnsiToUnicode( AnsiValueData, (PWSTR)ValueData, *ValueDataLength ) == 0) {
|
|
Error = GetLastError();
|
|
}
|
|
else {
|
|
*ValueDataLength *= sizeof( WCHAR );
|
|
}
|
|
|
|
HeapFree( GetProcessHeap(), 0, AnsiValueData );
|
|
}
|
|
|
|
return Error;
|
|
}
|
|
else {
|
|
Error = RegEnumValue( KeyHandle,
|
|
Index,
|
|
ValueName,
|
|
ValueNameLength,
|
|
NULL,
|
|
ValueType,
|
|
ValueData,
|
|
ValueDataLength
|
|
);
|
|
if (Error == NO_ERROR) {
|
|
RtlZeroMemory( (PCHAR)ValueData + *ValueDataLength, 4 - (*ValueDataLength & 3) );
|
|
}
|
|
|
|
return Error;
|
|
}
|
|
}
|
|
|
|
|
|
LONG
|
|
RTQueryKey(
|
|
IN PREG_CONTEXT RegistryContext,
|
|
IN HKEY KeyHandle,
|
|
OUT PFILETIME LastWriteTime,
|
|
OUT PULONG NumberOfSubkeys,
|
|
OUT PULONG NumberOfValues
|
|
)
|
|
{
|
|
LONG Error;
|
|
|
|
if (KeyHandle == HKEY_REGISTRY_ROOT) {
|
|
if (NumberOfSubkeys != NULL) {
|
|
*NumberOfSubkeys = 2;
|
|
}
|
|
|
|
if (NumberOfValues != NULL) {
|
|
*NumberOfValues = 0;
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
else
|
|
if (RegistryContext->Target == REG_TARGET_WIN95_REGISTRY) {
|
|
Error = (_Win95RegQueryInfoKey)( KeyHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NumberOfSubkeys,
|
|
NULL,
|
|
NULL,
|
|
NumberOfValues,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
(PVOID)LastWriteTime
|
|
);
|
|
}
|
|
else {
|
|
Error = RegQueryInfoKey( KeyHandle, // hKey,
|
|
NULL, // lpClass,
|
|
NULL, // lpcbClass,
|
|
NULL, // lpReserved,
|
|
NumberOfSubkeys, // lpcSubKeys,
|
|
NULL, // lpcbMaxSubKeyLen,
|
|
NULL, // lpcbMaxClassLen,
|
|
NumberOfValues, // lpcValues,
|
|
NULL, // lpcbMaxValueNameLen,
|
|
NULL, // lpcbMaxValueLen,
|
|
NULL, // lpcbSecurityDescriptor,
|
|
LastWriteTime // lpftLastWriteTime
|
|
);
|
|
}
|
|
|
|
return Error;
|
|
}
|
|
|
|
LONG
|
|
RTQueryValueKey(
|
|
IN PREG_CONTEXT RegistryContext,
|
|
IN HKEY KeyHandle,
|
|
IN PWSTR ValueName,
|
|
OUT PULONG ValueType,
|
|
IN OUT PULONG ValueDataLength,
|
|
OUT PVOID ValueData
|
|
)
|
|
{
|
|
LONG Error;
|
|
|
|
if (RegistryContext->Target == REG_TARGET_WIN95_REGISTRY) {
|
|
UCHAR AnsiValueName[ MAX_PATH ], *p;
|
|
ULONG OriginalValueDataLength;
|
|
|
|
if (ValueName != NULL) {
|
|
if (!RegUnicodeToAnsi( ValueName, AnsiValueName, 0 )) {
|
|
return GetLastError();
|
|
}
|
|
|
|
p = AnsiValueName;
|
|
}
|
|
else {
|
|
p = NULL;
|
|
}
|
|
|
|
OriginalValueDataLength = *ValueDataLength;
|
|
Error = (_Win95RegQueryValueEx)( KeyHandle,
|
|
p,
|
|
NULL,
|
|
ValueType,
|
|
ValueData,
|
|
ValueDataLength
|
|
);
|
|
if (Error == NO_ERROR && *ValueType == REG_SZ) {
|
|
if ((*ValueDataLength * sizeof( WCHAR )) > OriginalValueDataLength) {
|
|
return ERROR_MORE_DATA;
|
|
}
|
|
|
|
p = HeapAlloc( GetProcessHeap(), 0, *ValueDataLength );
|
|
if (p == NULL) {
|
|
return ERROR_OUTOFMEMORY;
|
|
}
|
|
|
|
RtlMoveMemory( p, ValueData, *ValueDataLength );
|
|
if (RegAnsiToUnicode( (LPCSTR)p, (PWSTR)ValueData, *ValueDataLength ) == 0) {
|
|
Error = GetLastError();
|
|
}
|
|
else {
|
|
*ValueDataLength *= sizeof( WCHAR );
|
|
*ValueDataLength += sizeof( UNICODE_NULL );
|
|
}
|
|
|
|
HeapFree( GetProcessHeap(), 0, p );
|
|
}
|
|
}
|
|
else {
|
|
Error = RegQueryValueEx( KeyHandle,
|
|
ValueName,
|
|
NULL,
|
|
ValueType,
|
|
ValueData,
|
|
ValueDataLength
|
|
);
|
|
|
|
if (Error == NO_ERROR) {
|
|
RtlZeroMemory( (PCHAR)ValueData + *ValueDataLength, 4 - (*ValueDataLength & 3) );
|
|
}
|
|
}
|
|
|
|
return Error;
|
|
}
|
|
|
|
LONG
|
|
RTSetValueKey(
|
|
IN PREG_CONTEXT RegistryContext,
|
|
IN HKEY KeyHandle,
|
|
IN PWSTR ValueName,
|
|
IN ULONG ValueType,
|
|
IN ULONG ValueDataLength,
|
|
IN PVOID ValueData
|
|
)
|
|
{
|
|
LONG Error;
|
|
|
|
if (RegistryContext->Target == REG_TARGET_WIN95_REGISTRY) {
|
|
UCHAR AnsiValueName[ MAX_PATH ], *p;
|
|
ULONG OriginalValueDataLength;
|
|
LPSTR AnsiValueData;
|
|
|
|
if (ValueName != NULL) {
|
|
if (!RegUnicodeToAnsi( ValueName, AnsiValueName, 0 )) {
|
|
return GetLastError();
|
|
}
|
|
|
|
p = AnsiValueName;
|
|
}
|
|
else {
|
|
p = NULL;
|
|
}
|
|
|
|
if (ValueType == REG_SZ) {
|
|
AnsiValueData = HeapAlloc( GetProcessHeap(), 0, ValueDataLength * 2 );
|
|
if (AnsiValueData == NULL) {
|
|
return ERROR_OUTOFMEMORY;
|
|
}
|
|
|
|
ValueDataLength = RegUnicodeToAnsi( ValueData, AnsiValueData, ValueDataLength );
|
|
if (ValueDataLength == 0) {
|
|
return GetLastError();
|
|
}
|
|
|
|
ValueData = AnsiValueData;
|
|
}
|
|
else {
|
|
AnsiValueData = NULL;
|
|
}
|
|
|
|
Error = (_Win95RegSetValueEx)( KeyHandle,
|
|
p,
|
|
0,
|
|
ValueType,
|
|
ValueData,
|
|
ValueDataLength
|
|
);
|
|
|
|
if (AnsiValueData != NULL) {
|
|
HeapFree( GetProcessHeap(), 0, AnsiValueData );
|
|
}
|
|
|
|
if (p != NULL) {
|
|
HeapFree( GetProcessHeap(), 0, p );
|
|
}
|
|
}
|
|
else {
|
|
Error = RegSetValueEx( KeyHandle,
|
|
ValueName,
|
|
0,
|
|
ValueType,
|
|
ValueData,
|
|
ValueDataLength
|
|
);
|
|
}
|
|
|
|
return Error;
|
|
}
|
|
|
|
LONG
|
|
RTDeleteKey(
|
|
IN PREG_CONTEXT RegistryContext,
|
|
IN HKEY KeyHandle,
|
|
IN PCWSTR SubKeyName
|
|
)
|
|
{
|
|
if (!RegValidateKeyPath( RegistryContext, &KeyHandle, &SubKeyName )) {
|
|
return GetLastError();
|
|
}
|
|
|
|
if (RegistryContext->Target == REG_TARGET_WIN95_REGISTRY) {
|
|
UCHAR AnsiSubKeyName[ MAX_PATH ], *p;
|
|
|
|
if (SubKeyName != NULL) {
|
|
if (!RegUnicodeToAnsi( SubKeyName, AnsiSubKeyName, 0 )) {
|
|
return GetLastError();
|
|
}
|
|
|
|
p = AnsiSubKeyName;
|
|
}
|
|
else {
|
|
p = NULL;
|
|
}
|
|
|
|
return (_Win95RegDeleteKey)( KeyHandle, p );
|
|
}
|
|
else {
|
|
return RegDeleteKey( KeyHandle, SubKeyName );
|
|
}
|
|
}
|
|
|
|
|
|
LONG
|
|
RTDeleteValueKey(
|
|
IN PREG_CONTEXT RegistryContext,
|
|
IN HKEY KeyHandle,
|
|
IN PWSTR ValueName
|
|
)
|
|
{
|
|
if (RegistryContext->Target == REG_TARGET_WIN95_REGISTRY) {
|
|
UCHAR AnsiValueName[ MAX_PATH ], *p;
|
|
ULONG OriginalValueDataLength;
|
|
LPSTR AnsiValueData;
|
|
|
|
if (ValueName != NULL) {
|
|
if (!RegUnicodeToAnsi( ValueName, AnsiValueName, 0 )) {
|
|
return GetLastError();
|
|
}
|
|
|
|
p = AnsiValueName;
|
|
}
|
|
else {
|
|
p = NULL;
|
|
}
|
|
|
|
return (_Win95RegDeleteValue)( KeyHandle,
|
|
p
|
|
);
|
|
}
|
|
else {
|
|
return RegDeleteValue( KeyHandle, ValueName );
|
|
}
|
|
}
|
|
|
|
|
|
LONG
|
|
RTLoadAsciiFileAsUnicode(
|
|
IN PWSTR FileName,
|
|
OUT PREG_UNICODE_FILE UnicodeFile
|
|
)
|
|
{
|
|
LONG Error = NO_ERROR;
|
|
HANDLE File;
|
|
DWORD FileSize;
|
|
DWORD CharsInFile;
|
|
DWORD BytesRead;
|
|
DWORD BufferSize, i, i1, LineCount, DeferredLineCount;
|
|
PVOID BufferBase;
|
|
PWSTR Src, Src1, Dst;
|
|
|
|
File = CreateFile( FileName,
|
|
FILE_GENERIC_READ,
|
|
FILE_SHARE_DELETE |
|
|
FILE_SHARE_READ |
|
|
FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
0,
|
|
NULL
|
|
);
|
|
if (File == INVALID_HANDLE_VALUE) {
|
|
return GetLastError();
|
|
}
|
|
|
|
FileSize = GetFileSize( File, NULL );
|
|
if (FileSize == INVALID_FILE_SIZE) {
|
|
CloseHandle( File );
|
|
return GetLastError();
|
|
}
|
|
|
|
BufferSize = FileSize * sizeof( WCHAR );
|
|
BufferSize += sizeof( UNICODE_NULL );
|
|
BufferBase = NULL;
|
|
BufferBase = VirtualAlloc( NULL, BufferSize, MEM_COMMIT, PAGE_READWRITE );
|
|
if (BufferBase != NULL) {
|
|
if (ReadFile( File, BufferBase, FileSize, &BytesRead, NULL )) {
|
|
if (BytesRead != FileSize) {
|
|
Error = ERROR_HANDLE_EOF;
|
|
}
|
|
else
|
|
if (!GetFileTime( File, NULL, NULL, &UnicodeFile->LastWriteTime )) {
|
|
Error = GetLastError();
|
|
}
|
|
else {
|
|
Error = NO_ERROR;
|
|
}
|
|
}
|
|
|
|
if (Error != NO_ERROR) {
|
|
VirtualFree( BufferBase, 0, MEM_RELEASE );
|
|
}
|
|
} else {
|
|
Error = GetLastError();
|
|
}
|
|
|
|
CloseHandle( File );
|
|
if (Error != NO_ERROR) {
|
|
return Error;
|
|
}
|
|
|
|
Src = (PWSTR)BufferBase;
|
|
|
|
if (!IsTextUnicode( BufferBase, FileSize, NULL )) {
|
|
RtlMoveMemory( (PCHAR)BufferBase + FileSize, BufferBase, FileSize );
|
|
CharsInFile = RegAnsiToUnicode( (PCHAR)BufferBase + FileSize, BufferBase, FileSize );
|
|
if (CharsInFile == 0) {
|
|
return GetLastError();
|
|
}
|
|
}
|
|
else {
|
|
CharsInFile = FileSize / sizeof( WCHAR );
|
|
|
|
//
|
|
// Skip ByteOrderMark
|
|
//
|
|
if (Src[0] == 0xfeff || Src[0] == 0xfffe) {
|
|
Src++;
|
|
CharsInFile--;
|
|
}
|
|
}
|
|
|
|
DeferredLineCount = 0;
|
|
Dst = (PWSTR)BufferBase;
|
|
|
|
i = 0;
|
|
|
|
//
|
|
// Now loop over the in memory copy of the file, collapsing all carriage
|
|
// return line feed pairs into just new lines, and removing all line
|
|
// continuation characters and the spaces that surround them. This lets
|
|
// RTParseNextLine see a single line for each Key Name or Value input,
|
|
// terminated by a new line character.
|
|
//
|
|
while (i < CharsInFile) {
|
|
//
|
|
// See if we just went over a line continuation character
|
|
//
|
|
if (i > 0 && Src[-1] == L'\\' && (*Src == L'\r' || *Src == L'\n')) {
|
|
//
|
|
// Move back over the line continuation we just copied the previous iteration
|
|
//
|
|
if (Dst[-1] == L'\\') {
|
|
--Dst;
|
|
}
|
|
|
|
//
|
|
// Move back over all but one of any space characters that preceed
|
|
// the line continuation character. The may be none, in which case
|
|
// we leave it be, as the user must want no space
|
|
//
|
|
while (Dst > (PWSTR)BufferBase) {
|
|
if (Dst[-1] > L' ') {
|
|
break;
|
|
}
|
|
Dst -= 1;
|
|
}
|
|
|
|
//
|
|
// Leave one space, if there is one
|
|
//
|
|
if (Dst[0] == L' ') {
|
|
Dst += 1;
|
|
}
|
|
|
|
//
|
|
// Now, skip over the new line after the line continuation. We
|
|
// actually will skip over any number of them, keeping count so
|
|
// we can update the source file line number correctly.
|
|
//
|
|
LineCount = 0;
|
|
while (i < CharsInFile) {
|
|
if (*Src == L'\n') {
|
|
i++;
|
|
Src++;
|
|
LineCount++;
|
|
}
|
|
else
|
|
if (*Src == L'\r' &&
|
|
(i+1) < CharsInFile &&
|
|
Src[ 1 ] == L'\n'
|
|
) {
|
|
i += 2;
|
|
Src += 2;
|
|
LineCount++;
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we saw more than just new line after the line continuation
|
|
// character, then put them back into the destination as just
|
|
// new lines, without any carriage returns.
|
|
//
|
|
if (LineCount > 1) {
|
|
DeferredLineCount += LineCount;
|
|
while (DeferredLineCount) {
|
|
DeferredLineCount -= 1;
|
|
*Dst++ = L'\n';
|
|
}
|
|
}
|
|
else {
|
|
DeferredLineCount += 1;
|
|
|
|
//
|
|
// Skip leading spaces of next line of continuation
|
|
|
|
while (i < CharsInFile && (*Src == L' ' || *Src == L'\t')) {
|
|
i++;
|
|
Src++;
|
|
}
|
|
}
|
|
|
|
//
|
|
// All done if we hit the end of the file
|
|
//
|
|
if (i >= CharsInFile) {
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
if ((*Src == '\r' && Src[1] == '\n') || *Src == '\n') {
|
|
while (TRUE) {
|
|
while (i < CharsInFile && (*Src == '\r' || *Src == '\n')) {
|
|
i++;
|
|
Src++;
|
|
}
|
|
Src1 = Src;
|
|
i1 = i;
|
|
while (i1 < CharsInFile && (*Src1 == ' ' || *Src1 == '\t')) {
|
|
i1++;
|
|
Src1++;
|
|
}
|
|
if (i1 < CharsInFile &&
|
|
(*Src1 == '\r' && Src1[1] == '\n') || *Src1 == '\n'
|
|
) {
|
|
Src = Src1;
|
|
i = i1;
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
while (DeferredLineCount) {
|
|
DeferredLineCount -= 1;
|
|
*Dst++ = L'\n';
|
|
}
|
|
*Dst++ = L'\n';
|
|
}
|
|
else {
|
|
i++;
|
|
*Dst++ = *Src++;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Make sure line ends with a CRLF sequence.
|
|
//
|
|
while (DeferredLineCount) {
|
|
DeferredLineCount -= 1;
|
|
*Dst++ = L'\n';
|
|
}
|
|
*Dst++ = L'\n';
|
|
*Dst = UNICODE_NULL;
|
|
UnicodeFile->FileName = FileName;
|
|
UnicodeFile->FileContents = BufferBase;
|
|
UnicodeFile->EndOfFile = Dst;
|
|
UnicodeFile->NextLine = BufferBase;
|
|
UnicodeFile->NextLineNumber = 1;
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
void
|
|
RTUnloadUnicodeFile(
|
|
IN OUT PREG_UNICODE_FILE UnicodeFile
|
|
)
|
|
{
|
|
VirtualFree( UnicodeFile->FileContents, 0, MEM_RELEASE );
|
|
return;
|
|
}
|
|
|
|
#define ACL_LIST_START L'['
|
|
#define ACL_LIST_END L']'
|
|
|
|
BOOLEAN
|
|
RegGetMultiString(
|
|
IN BOOLEAN BackwardsCompatibleInput,
|
|
IN OUT PWSTR *ValueString,
|
|
IN OUT PWSTR *ValueData,
|
|
IN ULONG MaximumValueLength,
|
|
IN OUT PULONG ValueLength
|
|
);
|
|
|
|
|
|
BOOLEAN
|
|
RegReadMultiSzFile(
|
|
IN OUT PREG_UNICODE_PARSE ParsedLine,
|
|
IN BOOLEAN BackwardsCompatibleInput,
|
|
IN PWSTR FileName,
|
|
IN OUT PVOID ValueData,
|
|
IN OUT PULONG ValueLength
|
|
);
|
|
|
|
BOOLEAN
|
|
RegReadBinaryFile(
|
|
IN OUT PREG_UNICODE_PARSE ParsedLine,
|
|
IN PWSTR FileName,
|
|
IN OUT PVOID ValueData,
|
|
IN OUT PULONG ValueLength
|
|
);
|
|
|
|
BOOLEAN
|
|
RTParseNextLine(
|
|
IN OUT PREG_UNICODE_FILE UnicodeFile,
|
|
OUT PREG_UNICODE_PARSE ParsedLine
|
|
)
|
|
{
|
|
PWSTR BeginLine, EqualSign, AclBracket, AclStart, s, s1;
|
|
WCHAR QuoteChar;
|
|
|
|
if (ParsedLine->IsKeyName && ParsedLine->SecurityDescriptor) {
|
|
RegDestroySecurity( ParsedLine->SecurityDescriptor );
|
|
}
|
|
|
|
RtlZeroMemory( ParsedLine, sizeof( *ParsedLine ) );
|
|
while (TRUE) {
|
|
if (!(s = UnicodeFile->NextLine)) {
|
|
ParsedLine->AtEndOfFile = TRUE;
|
|
return FALSE;
|
|
}
|
|
UnicodeFile->NextLine = NULL;
|
|
if (*s == UNICODE_NULL) {
|
|
ParsedLine->AtEndOfFile = TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
while (*s <= L' ') {
|
|
if (*s == L' ') {
|
|
ParsedLine->IndentAmount += 1;
|
|
}
|
|
else
|
|
if (*s == L'\t') {
|
|
ParsedLine->IndentAmount = ((ParsedLine->IndentAmount + 8) -
|
|
(ParsedLine->IndentAmount % 8)
|
|
);
|
|
}
|
|
|
|
if (++s >= UnicodeFile->EndOfFile) {
|
|
ParsedLine->AtEndOfFile = TRUE;
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
BeginLine = s;
|
|
EqualSign = NULL;
|
|
AclBracket = NULL;
|
|
if (!UnicodeFile->BackwardsCompatibleInput && *s == L';') {
|
|
while (s < UnicodeFile->EndOfFile) {
|
|
if (*s == L'\n') {
|
|
do {
|
|
UnicodeFile->NextLineNumber += 1;
|
|
*s++ = UNICODE_NULL;
|
|
}
|
|
while (*s == L'\n');
|
|
break;
|
|
}
|
|
else {
|
|
s += 1;
|
|
}
|
|
}
|
|
|
|
BeginLine = s;
|
|
UnicodeFile->NextLine = s;
|
|
}
|
|
else
|
|
if (*s != '\n') {
|
|
|
|
//
|
|
// If not being backward compatible, see if the first thing on
|
|
// the line is the beginning of a quoted string.
|
|
//
|
|
|
|
if (!UnicodeFile->BackwardsCompatibleInput && (*s == L'"' || *s == L'\'')) {
|
|
//
|
|
// Yes, it is either a quoted key name or value name. Find the
|
|
// the trailing quote. Specifically do NOT support quotes inside
|
|
// a quoted string, other than a different kind. Which means unless
|
|
// you want both types of quoted characters within the same name
|
|
// you wont care.
|
|
//
|
|
QuoteChar = *s++;
|
|
BeginLine += 1;
|
|
while (s < UnicodeFile->EndOfFile && *s != QuoteChar) {
|
|
s += 1;
|
|
}
|
|
|
|
//
|
|
// If trailing quote not found, then return an error
|
|
//
|
|
if (*s != QuoteChar) {
|
|
ParsedLine->ParseFailureReason = ParseFailInvalidQuoteCharacter;
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Mark the end of the name and move past the trailing quote
|
|
//
|
|
*s++ = UNICODE_NULL;
|
|
}
|
|
|
|
//
|
|
// Now scan forward looking for one of the following:
|
|
//
|
|
// equal sign - this would mean the stuff to the left
|
|
// of the equal sign is a value name and the stuff
|
|
// to the right is the value type and data.
|
|
//
|
|
// left square bracket - this would mean the stuff to the
|
|
// left of the square bracket is a key name and the
|
|
// stuff to the right is the security descriptor information
|
|
//
|
|
// end of line - this would mean the stuff to the left
|
|
// is a key name, with no security descriptor.
|
|
//
|
|
|
|
while (s < UnicodeFile->EndOfFile) {
|
|
if (*s == L'=') {
|
|
//
|
|
// We found an equal sign, so value name is to the left
|
|
// and value type and data follows.
|
|
//
|
|
EqualSign = s;
|
|
|
|
//
|
|
// Ignore any left square bracket we might have seen
|
|
// in before this. It must have been part of the value
|
|
// name.
|
|
AclBracket = NULL;
|
|
|
|
//
|
|
// All done scanning
|
|
//
|
|
break;
|
|
}
|
|
else
|
|
if (*s == ACL_LIST_START) {
|
|
//
|
|
// We found a left square bracket. Keep scanning
|
|
// in case there is an equal sign later.
|
|
//
|
|
AclBracket = s;
|
|
s += 1;
|
|
}
|
|
else
|
|
if (*s == L'\n') {
|
|
//
|
|
// We found end of line, so key name is to the left.
|
|
// Update where to start next time we are called.
|
|
//
|
|
UnicodeFile->NextLine = s + 1;
|
|
break;
|
|
}
|
|
else
|
|
if (*s == L'\t') {
|
|
//
|
|
// Convert imbedded hard tabs to single spaces
|
|
//
|
|
*s++ = L' ';
|
|
}
|
|
else {
|
|
//
|
|
// Nothing interesting, keep looking.
|
|
//
|
|
s += 1;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Trim any trailing spaces off the end of what is to the
|
|
// left of where we are. The make sure we stop looking
|
|
// if we see the null character put down over the trailing
|
|
// quote character above, if any.
|
|
//
|
|
*s = UNICODE_NULL;
|
|
while (s > BeginLine && *--s <= L' ' && *s) {
|
|
*s = UNICODE_NULL;
|
|
}
|
|
|
|
//
|
|
// BeginLine now points to either the null terminated value
|
|
// name or key name. EqualSign, if non-null, points to the
|
|
// equal sign, so scan forward and find the terminating new line,
|
|
// and store a null there to terminate the input. Otherwise,
|
|
// we already stored a null over the terminating new line above.
|
|
//
|
|
if (EqualSign != NULL) {
|
|
s = EqualSign + 1;
|
|
while (s < UnicodeFile->EndOfFile) {
|
|
if (*s == '\n') {
|
|
*s = UNICODE_NULL;
|
|
break;
|
|
}
|
|
|
|
s += 1;
|
|
}
|
|
|
|
//
|
|
// Update where we should start next time we are called.
|
|
//
|
|
UnicodeFile->NextLine = s + 1;
|
|
}
|
|
else
|
|
if (AclBracket != NULL) {
|
|
//
|
|
// Since we did not stop on the AclBracket, go back an
|
|
// clobber it and any spaces before it.
|
|
//
|
|
s = AclBracket;
|
|
*s = UNICODE_NULL;
|
|
while (s > BeginLine && *--s <= L' ' && *s) {
|
|
*s = UNICODE_NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Tell them which line number and where the line begins
|
|
//
|
|
ParsedLine->LineNumber = UnicodeFile->NextLineNumber;
|
|
UnicodeFile->NextLineNumber += 1;
|
|
ParsedLine->BeginLine = BeginLine;
|
|
|
|
//
|
|
// Now handle value or key semantics
|
|
//
|
|
if (EqualSign != NULL) {
|
|
//
|
|
// We have ValueName = ValueType ValueData
|
|
//
|
|
|
|
//
|
|
// Value name is the beginning of the line, unless
|
|
// it was the special symbol or null
|
|
//
|
|
if (*BeginLine != L'@' && BeginLine != EqualSign) {
|
|
ParsedLine->ValueName = BeginLine;
|
|
}
|
|
|
|
//
|
|
// Skip any blanks after the equal sign.
|
|
//
|
|
while (*++EqualSign && *EqualSign <= L' ') {
|
|
}
|
|
|
|
//
|
|
// If all that is left is the DELETE keyword, then
|
|
// tell the caller
|
|
//
|
|
if (!_wcsicmp( L"DELETE", EqualSign )) {
|
|
ParsedLine->DeleteValue = TRUE;
|
|
return TRUE;
|
|
}
|
|
else {
|
|
//
|
|
// Otherwise parse the data after the equal sign.
|
|
//
|
|
ParsedLine->ValueString = EqualSign;
|
|
return RTParseValueData( UnicodeFile,
|
|
ParsedLine,
|
|
ValueBuffer,
|
|
ValueBufferSize,
|
|
&ParsedLine->ValueType,
|
|
&ParsedLine->ValueData,
|
|
&ParsedLine->ValueLength
|
|
);
|
|
}
|
|
}
|
|
else {
|
|
//
|
|
// We have a key name. Tell the caller and handle any
|
|
// security descriptor info if present.
|
|
//
|
|
ParsedLine->IsKeyName = TRUE;
|
|
ParsedLine->KeyName = BeginLine;
|
|
if (AclBracket != NULL) {
|
|
//
|
|
// We have found an ACL name
|
|
//
|
|
AclStart = ++AclBracket;
|
|
ParsedLine->AclString = AclStart;
|
|
while (*AclBracket != UNICODE_NULL && *AclBracket != ACL_LIST_END) {
|
|
AclBracket += 1;
|
|
}
|
|
if (*AclBracket != ACL_LIST_END) {
|
|
return FALSE;
|
|
}
|
|
|
|
*AclBracket = UNICODE_NULL;
|
|
if (!_wcsicmp( L"DELETE", AclStart )) {
|
|
ParsedLine->DeleteKey = TRUE;
|
|
}
|
|
else {
|
|
ParsedLine->SecurityDescriptor = &ParsedLine->SecurityDescriptorBuffer;
|
|
if (!RegCreateSecurity( AclStart, ParsedLine->SecurityDescriptor )) {
|
|
ParsedLine->SecurityDescriptor = NULL;
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
else {
|
|
UnicodeFile->NextLineNumber += 1;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOLEAN
|
|
RTParseValueData(
|
|
IN OUT PREG_UNICODE_FILE UnicodeFile,
|
|
IN OUT PREG_UNICODE_PARSE ParsedLine,
|
|
IN PVOID ValueBuffer,
|
|
IN ULONG ValueBufferSize,
|
|
OUT PULONG ValueType,
|
|
OUT PVOID *ValueData,
|
|
OUT PULONG ValueLength
|
|
)
|
|
{
|
|
PWSTR ValueString;
|
|
ULONG PrefixLength, MaximumValueLength;
|
|
PULONG p;
|
|
PWSTR s, Src, Dst;
|
|
ULONG i, n, cchValue;
|
|
BOOLEAN BackwardsCompatibleInput = FALSE;
|
|
BOOLEAN GetDataFromBinaryFile = FALSE;
|
|
BOOLEAN GetDataFromMultiSzFile = FALSE;
|
|
BOOLEAN ParseDateTime = FALSE;
|
|
|
|
if (UnicodeFile != NULL) {
|
|
BackwardsCompatibleInput = UnicodeFile->BackwardsCompatibleInput;
|
|
}
|
|
ValueString = ParsedLine->ValueString;
|
|
*ValueData = NULL;
|
|
*ValueLength = 0;
|
|
*ValueType = REG_SZ;
|
|
for (i=0; RegTypeNameTable[i].TypeName != NULL; i++) {
|
|
PrefixLength = wcslen( RegTypeNameTable[i].TypeName );
|
|
if (ValueString[ PrefixLength ] <= L' ' &&
|
|
!_wcsnicmp( RegTypeNameTable[i].TypeName,
|
|
ValueString,
|
|
PrefixLength
|
|
)
|
|
) {
|
|
*ValueType = RegTypeNameTable[i].ValueType;
|
|
GetDataFromBinaryFile = RegTypeNameTable[i].GetDataFromBinaryFile;
|
|
GetDataFromMultiSzFile = RegTypeNameTable[i].GetDataFromMultiSzFile;
|
|
ParseDateTime = RegTypeNameTable[i].ParseDateTime;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (RegTypeNameTable[i].TypeName != NULL) {
|
|
ValueString += PrefixLength;
|
|
while (*ValueString != UNICODE_NULL && *ValueString <= L' ') {
|
|
ValueString += 1;
|
|
}
|
|
}
|
|
|
|
if (GetDataFromMultiSzFile) {
|
|
*ValueData = ValueBuffer;
|
|
*ValueLength = ValueBufferSize;
|
|
return RegReadMultiSzFile( ParsedLine,
|
|
BackwardsCompatibleInput,
|
|
ValueString,
|
|
ValueBuffer,
|
|
ValueLength
|
|
);
|
|
}
|
|
|
|
if (GetDataFromBinaryFile) {
|
|
*ValueData = ValueBuffer;
|
|
*ValueLength = ValueBufferSize;
|
|
return RegReadBinaryFile( ParsedLine,
|
|
ValueString,
|
|
ValueBuffer,
|
|
ValueLength
|
|
);
|
|
}
|
|
|
|
cchValue = wcslen( ValueString );
|
|
Src = ValueString;
|
|
switch( *ValueType ) {
|
|
case REG_SZ:
|
|
case REG_EXPAND_SZ:
|
|
//
|
|
// Strip off any surrounding quote characters
|
|
//
|
|
if (cchValue > 1 && Src[ 0 ] == Src[ cchValue - 1 ] &&
|
|
(Src[ 0 ] == L'"' || Src[ 0 ] == L'\'')
|
|
) {
|
|
Src += 1;
|
|
cchValue -= 2;
|
|
}
|
|
|
|
//
|
|
// Fall through after stripping any quotes.
|
|
//
|
|
|
|
case REG_LINK:
|
|
*ValueLength = (cchValue + 1) * sizeof( WCHAR );
|
|
if (*ValueLength > ValueBufferSize) {
|
|
SetLastError( ERROR_BUFFER_OVERFLOW );
|
|
ParsedLine->ParseFailureReason = ParseFailValueTooLarge;
|
|
return FALSE;
|
|
}
|
|
*ValueData = ValueBuffer;
|
|
RtlMoveMemory( *ValueData, Src, *ValueLength );
|
|
*((PWSTR)*ValueData + cchValue) = UNICODE_NULL;
|
|
return TRUE;
|
|
|
|
case REG_DWORD:
|
|
*ValueData = ValueBuffer;
|
|
*ValueLength = sizeof( ULONG );
|
|
for (i=0; RegValueNameTable[i].ValueName != NULL; i++) {
|
|
PrefixLength = wcslen( RegValueNameTable[i].ValueName );
|
|
if (!_wcsnicmp( RegValueNameTable[i].ValueName,
|
|
ValueString,
|
|
PrefixLength
|
|
)
|
|
) {
|
|
*(PULONG)*ValueData = RegValueNameTable[i].Value;
|
|
return TRUE;
|
|
}
|
|
}
|
|
return RegUnicodeToDWORD( &Src, 0, (PULONG)*ValueData );
|
|
|
|
case REG_BINARY:
|
|
if (ParseDateTime) {
|
|
#define NUMBER_DATE_TIME_FIELDS 6
|
|
ULONG FieldIndexes[ NUMBER_DATE_TIME_FIELDS ] = {1, 2, 0, 3, 4, 7};
|
|
//
|
|
// Month/Day/Year HH:MM DayOfWeek
|
|
//
|
|
|
|
ULONG CurrentField = 0;
|
|
PCSHORT Fields;
|
|
TIME_FIELDS DateTimeFields;
|
|
PWSTR Field;
|
|
ULONG FieldValue;
|
|
|
|
RtlZeroMemory( &DateTimeFields, sizeof( DateTimeFields ) );
|
|
Fields = &DateTimeFields.Year;
|
|
while (cchValue) {
|
|
if (CurrentField >= 7) {
|
|
return( FALSE );
|
|
}
|
|
|
|
while (cchValue && *Src == L' ') {
|
|
cchValue--;
|
|
Src += 1;
|
|
}
|
|
|
|
Field = Src;
|
|
while (cchValue) {
|
|
if (CurrentField == (NUMBER_DATE_TIME_FIELDS-1)) {
|
|
}
|
|
else
|
|
if (*Src < L'0' || *Src > L'9') {
|
|
break;
|
|
}
|
|
|
|
cchValue--;
|
|
Src += 1;
|
|
}
|
|
|
|
if (cchValue) {
|
|
cchValue--;
|
|
Src += 1;
|
|
}
|
|
|
|
if (CurrentField == (NUMBER_DATE_TIME_FIELDS-1)) {
|
|
if (cchValue < 3) {
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
ParsedLine->ParseFailureReason = ParseFailDateTimeFormatInvalid;
|
|
return FALSE;
|
|
}
|
|
|
|
if (DateTimeFields.Year != 0) {
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
ParsedLine->ParseFailureReason = ParseFailDateTimeFormatInvalid;
|
|
return FALSE;
|
|
}
|
|
|
|
if (!_wcsnicmp( Field, L"SUN", 3 )) {
|
|
FieldValue = 0;
|
|
}
|
|
else
|
|
if (!_wcsnicmp( Field, L"MON", 3 )) {
|
|
FieldValue = 1;
|
|
}
|
|
else
|
|
if (!_wcsnicmp( Field, L"TUE", 3 )) {
|
|
FieldValue = 2;
|
|
}
|
|
else
|
|
if (!_wcsnicmp( Field, L"WED", 3 )) {
|
|
FieldValue = 3;
|
|
}
|
|
else
|
|
if (!_wcsnicmp( Field, L"THU", 3 )) {
|
|
FieldValue = 4;
|
|
}
|
|
else
|
|
if (!_wcsnicmp( Field, L"FRI", 3 )) {
|
|
FieldValue = 5;
|
|
}
|
|
else
|
|
if (!_wcsnicmp( Field, L"SAT", 3 )) {
|
|
FieldValue = 6;
|
|
}
|
|
else {
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
if (!RegUnicodeToDWORD( &Field, 0, &FieldValue )) {
|
|
ParsedLine->ParseFailureReason = ParseFailDateTimeFormatInvalid;
|
|
return FALSE;
|
|
}
|
|
|
|
Fields[ FieldIndexes[ CurrentField++ ] ] = (CSHORT)FieldValue;
|
|
}
|
|
|
|
if (DateTimeFields.Year == 0) {
|
|
if (DateTimeFields.Day > 5) {
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
ParsedLine->ParseFailureReason = ParseFailDateTimeFormatInvalid;
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
if (DateTimeFields.Year < 100) {
|
|
DateTimeFields.Year += 1900;
|
|
}
|
|
|
|
*ValueLength = sizeof( DateTimeFields );
|
|
if (*ValueLength > ValueBufferSize) {
|
|
SetLastError( ERROR_BUFFER_OVERFLOW );
|
|
ParsedLine->ParseFailureReason = ParseFailValueTooLarge;
|
|
return FALSE;
|
|
}
|
|
*ValueData = ValueBuffer;
|
|
RtlMoveMemory( *ValueData, &DateTimeFields, sizeof( DateTimeFields ) );
|
|
return TRUE;
|
|
}
|
|
|
|
case REG_RESOURCE_LIST:
|
|
case REG_RESOURCE_REQUIREMENTS_LIST:
|
|
case REG_FULL_RESOURCE_DESCRIPTOR:
|
|
case REG_NONE:
|
|
if (!RegUnicodeToDWORD( &Src, 0, ValueLength )) {
|
|
ParsedLine->ParseFailureReason = ParseFailBinaryDataLengthMissing;
|
|
return FALSE;
|
|
}
|
|
|
|
if (*ValueLength >= ValueBufferSize) {
|
|
SetLastError( ERROR_BUFFER_OVERFLOW );
|
|
ParsedLine->ParseFailureReason = ParseFailValueTooLarge;
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Calculate number of DWORD's of data based on specified byte count
|
|
//
|
|
n = (*ValueLength + sizeof( ULONG ) - 1) / sizeof( ULONG );
|
|
|
|
//
|
|
// Store converted binary data in ValueBuffer
|
|
//
|
|
*ValueData = ValueBuffer;
|
|
p = ValueBuffer;
|
|
|
|
//
|
|
// Src points to remaining text to convert.
|
|
//
|
|
while (n--) {
|
|
if (!RegUnicodeToDWORD( &Src, 0, p )) {
|
|
if (BackwardsCompatibleInput) {
|
|
Src = UnicodeFile->NextLine;
|
|
s = Src;
|
|
while (TRUE) {
|
|
if (*s == '\n') {
|
|
*s = UNICODE_NULL;
|
|
UnicodeFile->NextLineNumber += 1;
|
|
break;
|
|
}
|
|
else
|
|
if (s >= UnicodeFile->EndOfFile || *s == UNICODE_NULL) {
|
|
UnicodeFile->NextLine = NULL;
|
|
ParsedLine->ParseFailureReason = ParseFailBinaryDataNotEnough;
|
|
SetLastError( ERROR_MORE_DATA );
|
|
return FALSE;
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
UnicodeFile->NextLine = s + 1;
|
|
n += 1;
|
|
}
|
|
else {
|
|
if (p == ValueBuffer) {
|
|
ParsedLine->ParseFailureReason = ParseFailBinaryDataOmitted;
|
|
SetLastError( ERROR_NO_DATA );
|
|
}
|
|
else {
|
|
ParsedLine->ParseFailureReason = ParseFailBinaryDataNotEnough;
|
|
SetLastError( ERROR_MORE_DATA );
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
}
|
|
else {
|
|
p += 1;
|
|
}
|
|
}
|
|
return TRUE;
|
|
|
|
case REG_MULTI_SZ:
|
|
*ValueLength = 0;
|
|
*ValueData = ValueBuffer;
|
|
MaximumValueLength = ValueBufferSize;
|
|
Dst = *ValueData;
|
|
while (RegGetMultiString( BackwardsCompatibleInput,
|
|
&Src,
|
|
&Dst,
|
|
MaximumValueLength,
|
|
ValueLength
|
|
)
|
|
) {
|
|
}
|
|
|
|
if (GetLastError() == NO_ERROR) {
|
|
return TRUE;
|
|
}
|
|
else {
|
|
ParsedLine->ParseFailureReason = ParseFailValueTooLarge;
|
|
return FALSE;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
ParsedLine->ParseFailureReason = ParseFailInvalidRegistryType;
|
|
return FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
BOOLEAN
|
|
RegGetMultiString(
|
|
IN BOOLEAN BackwardsCompatibleInput,
|
|
IN OUT PWSTR *ValueString,
|
|
IN OUT PWSTR *ValueData,
|
|
IN ULONG MaximumValueLength,
|
|
IN OUT PULONG ValueLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine parses multi-strings of the form
|
|
|
|
"foo" "bar" "bletch"
|
|
|
|
Each time it is called, it strips the first string in quotes from
|
|
the input string, and returns it as the multi-string.
|
|
|
|
INPUT ValueString: "foo" "bar" "bletch"
|
|
|
|
OUTPUT ValueString: "bar" "bletch"
|
|
ValueData: foo
|
|
|
|
Arguments:
|
|
|
|
BackwardsCompatibleInput - TRUE if supporting old format input
|
|
|
|
ValueString - Supplies the string from which the multi-string will be
|
|
parsed
|
|
- Returns the remaining string after the multi-string is
|
|
removed
|
|
|
|
ValueData - Supplies the location where the removed multi-string is
|
|
to be stored.
|
|
- Returns the location to the first byte after the returned
|
|
multi-string
|
|
|
|
MaximumValueLength - Supplies the maximum length of data that can be
|
|
stored in ValueData.
|
|
|
|
ValueLength - Supplies a pointer to the current length of data stored
|
|
in ValueData.
|
|
- Returns the size of the
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful and FALSE if not.
|
|
|
|
--*/
|
|
|
|
{
|
|
PWSTR Src, Dst;
|
|
ULONG n;
|
|
BOOLEAN Result;
|
|
|
|
//
|
|
// Find the first quote mark.
|
|
//
|
|
Src = *ValueString;
|
|
while (*Src != UNICODE_NULL && *Src != L'"') {
|
|
Src += 1;
|
|
}
|
|
|
|
Dst = *ValueData;
|
|
if (*Src == UNICODE_NULL) {
|
|
SetLastError( NO_ERROR );
|
|
Result = FALSE;
|
|
}
|
|
else {
|
|
//
|
|
// We have found the start of the multi-string. Now find the end,
|
|
// building up our return ValueData as we go.
|
|
//
|
|
|
|
Src += 1;
|
|
while (*Src != UNICODE_NULL) {
|
|
if (*Src == L'"') {
|
|
if (!BackwardsCompatibleInput &&
|
|
Src[1] == L'"'
|
|
) {
|
|
Src += 1;
|
|
}
|
|
else {
|
|
*Src++ = UNICODE_NULL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
*ValueLength += sizeof( WCHAR );
|
|
if (*ValueLength >= MaximumValueLength) {
|
|
SetLastError( ERROR_BUFFER_OVERFLOW );
|
|
return FALSE;
|
|
}
|
|
|
|
*Dst++ = *Src++;
|
|
}
|
|
|
|
Result = TRUE;
|
|
}
|
|
|
|
*ValueLength += sizeof( WCHAR );
|
|
if (*ValueLength >= MaximumValueLength) {
|
|
SetLastError( ERROR_BUFFER_OVERFLOW );
|
|
return FALSE;
|
|
}
|
|
|
|
*Dst++ = UNICODE_NULL;
|
|
*ValueData = Dst;
|
|
*ValueString = Src;
|
|
return Result;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
RegReadMultiSzFile(
|
|
IN OUT PREG_UNICODE_PARSE ParsedLine,
|
|
IN BOOLEAN BackwardsCompatibleInput,
|
|
IN PWSTR FileName,
|
|
IN OUT PVOID ValueData,
|
|
IN OUT PULONG ValueLength
|
|
)
|
|
{
|
|
PWSTR Src, Dst;
|
|
REG_UNICODE_FILE MultiSzFile;
|
|
ULONG MaximumValueLength;
|
|
BOOLEAN Result;
|
|
|
|
if (!RTLoadAsciiFileAsUnicode( FileName, &MultiSzFile )) {
|
|
ParsedLine->ParseFailureReason = ParseFailUnableToAccessFile;
|
|
return FALSE;
|
|
}
|
|
|
|
MaximumValueLength = *ValueLength;
|
|
*ValueLength = 0;
|
|
Src = MultiSzFile.NextLine;
|
|
Dst = ValueData;
|
|
while (RegGetMultiString( BackwardsCompatibleInput,
|
|
&Src,
|
|
&Dst,
|
|
MaximumValueLength,
|
|
ValueLength
|
|
)
|
|
) {
|
|
}
|
|
|
|
if (GetLastError() == NO_ERROR) {
|
|
Result = TRUE;
|
|
}
|
|
else {
|
|
ParsedLine->ParseFailureReason = ParseFailValueTooLarge;
|
|
Result = FALSE;
|
|
}
|
|
|
|
RTUnloadUnicodeFile( &MultiSzFile );
|
|
|
|
return Result;
|
|
}
|
|
|
|
BOOLEAN
|
|
RegReadBinaryFile(
|
|
IN OUT PREG_UNICODE_PARSE ParsedLine,
|
|
IN PWSTR FileName,
|
|
IN OUT PVOID ValueData,
|
|
IN OUT PULONG ValueLength
|
|
)
|
|
{
|
|
BOOLEAN Result;
|
|
HANDLE File;
|
|
DWORD FileSize, FileSizeHigh;
|
|
DWORD BytesRead;
|
|
|
|
File = CreateFile( FileName,
|
|
FILE_GENERIC_READ,
|
|
FILE_SHARE_DELETE |
|
|
FILE_SHARE_READ |
|
|
FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
0,
|
|
NULL
|
|
);
|
|
if (File == INVALID_HANDLE_VALUE) {
|
|
ParsedLine->ParseFailureReason = ParseFailUnableToAccessFile;
|
|
return FALSE;
|
|
}
|
|
|
|
ParsedLine->ParseFailureReason = ParseFailValueTooLarge;
|
|
FileSize = GetFileSize( File, &FileSizeHigh );
|
|
if (FileSizeHigh != 0 ||
|
|
FileSize == INVALID_FILE_SIZE ||
|
|
FileSize >= *ValueLength
|
|
) {
|
|
CloseHandle( File );
|
|
SetLastError( ERROR_BUFFER_OVERFLOW );
|
|
return FALSE;
|
|
}
|
|
|
|
Result = FALSE;
|
|
if (ReadFile( File, ValueData, FileSize, &BytesRead, NULL )) {
|
|
if (BytesRead != FileSize) {
|
|
SetLastError( ERROR_HANDLE_EOF );
|
|
}
|
|
else {
|
|
ParsedLine->ParseFailureReason = ParseFailNoFailure;
|
|
*ValueLength = FileSize;
|
|
Result = TRUE;
|
|
}
|
|
}
|
|
|
|
CloseHandle( File );
|
|
return Result;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
NeedQuotedString(
|
|
PWSTR Name,
|
|
PWSTR Value,
|
|
PWCHAR QuoteChar
|
|
)
|
|
{
|
|
ULONG i;
|
|
|
|
if (Name != NULL) {
|
|
if (*Name != UNICODE_NULL &&
|
|
(*Name == L' ' || Name[ wcslen( Name ) - 1 ] == L' ')
|
|
) {
|
|
*QuoteChar = '"';
|
|
return TRUE;
|
|
}
|
|
else {
|
|
return FALSE;
|
|
}
|
|
}
|
|
else {
|
|
i = wcslen( Value ) - 1;
|
|
if (*Value != UNICODE_NULL) {
|
|
if ((*Value == L' ' || Value[ i ] == L' ' || Value[ i ] == L'\\')) {
|
|
*QuoteChar = '"';
|
|
return TRUE;
|
|
}
|
|
else
|
|
if (*Value == L'"' && Value[ i ] == L'"') {
|
|
*QuoteChar = '\'';
|
|
return TRUE;
|
|
}
|
|
else
|
|
if (*Value == L'\'' && Value[ i ] == L'\'') {
|
|
*QuoteChar = '"';
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
void
|
|
RTFormatKeyName(
|
|
PREG_OUTPUT_ROUTINE OutputRoutine,
|
|
PVOID OutputRoutineParameter,
|
|
ULONG IndentLevel,
|
|
PWSTR KeyName
|
|
)
|
|
{
|
|
PWSTR pw;
|
|
WCHAR QuoteChar;
|
|
|
|
if (NeedQuotedString( KeyName, NULL, &QuoteChar )) {
|
|
(OutputRoutine)( OutputRoutineParameter,
|
|
"%.*s%c%ws%c",
|
|
IndentLevel,
|
|
BlanksForPadding,
|
|
QuoteChar,
|
|
KeyName,
|
|
QuoteChar
|
|
);
|
|
}
|
|
else {
|
|
(OutputRoutine)( OutputRoutineParameter,
|
|
"%.*s%ws",
|
|
IndentLevel,
|
|
BlanksForPadding,
|
|
KeyName
|
|
);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void
|
|
RTFormatKeySecurity(
|
|
PREG_OUTPUT_ROUTINE OutputRoutine,
|
|
PVOID OutputRoutineParameter,
|
|
HKEY KeyHandle,
|
|
PSECURITY_DESCRIPTOR SecurityDescriptor
|
|
)
|
|
{
|
|
ULONG SecurityBufferLength;
|
|
BOOLEAN FormattedAces;
|
|
WCHAR AceList[ 256 ];
|
|
|
|
FormattedAces = FALSE;
|
|
if (KeyHandle != NULL)
|
|
{
|
|
SecurityBufferLength = 0;
|
|
if (RegGetKeySecurity( KeyHandle,
|
|
DACL_SECURITY_INFORMATION,
|
|
SecurityDescriptor,
|
|
&SecurityBufferLength
|
|
) == ERROR_INSUFFICIENT_BUFFER )
|
|
{
|
|
SecurityDescriptor = (PSECURITY_DESCRIPTOR)HeapAlloc( GetProcessHeap(),
|
|
0,
|
|
SecurityBufferLength
|
|
);
|
|
|
|
if (SecurityDescriptor)
|
|
{
|
|
if (RegGetKeySecurity( KeyHandle,
|
|
DACL_SECURITY_INFORMATION,
|
|
SecurityDescriptor,
|
|
&SecurityBufferLength
|
|
) != NO_ERROR ) {
|
|
HeapFree( GetProcessHeap(), 0, SecurityDescriptor );
|
|
} else {
|
|
FormattedAces = RegFormatSecurity( SecurityDescriptor, AceList );
|
|
HeapFree( GetProcessHeap(), 0, SecurityDescriptor );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
if (SecurityDescriptor != NULL) {
|
|
FormattedAces = RegFormatSecurity( SecurityDescriptor, AceList );
|
|
}
|
|
|
|
if (FormattedAces) {
|
|
(OutputRoutine)( OutputRoutineParameter,
|
|
" %wc%ws%wc",
|
|
ACL_LIST_START,
|
|
AceList,
|
|
ACL_LIST_END
|
|
);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void
|
|
RegDisplayResourceListAsComment(
|
|
ULONG OutputWidth,
|
|
PREG_OUTPUT_ROUTINE OutputRoutine,
|
|
PVOID OutputRoutineParameter,
|
|
ULONG IndentLevel,
|
|
ULONG ValueLength,
|
|
ULONG ValueType,
|
|
PWSTR ValueData
|
|
);
|
|
|
|
void
|
|
RTFormatKeyValue(
|
|
ULONG OutputWidth,
|
|
PREG_OUTPUT_ROUTINE OutputRoutine,
|
|
PVOID OutputRoutineParameter,
|
|
BOOLEAN SummaryOutput,
|
|
ULONG IndentLevel,
|
|
PWSTR ValueName,
|
|
ULONG ValueLength,
|
|
ULONG ValueType,
|
|
PWSTR ValueData
|
|
)
|
|
{
|
|
PULONG p;
|
|
PWSTR pw, pw1, pwBreak;
|
|
WCHAR QuoteChar, BreakChar;
|
|
ULONG i, j, k, m, cbPrefix, cb;
|
|
PUCHAR pbyte;
|
|
char eol[11];
|
|
|
|
cbPrefix = (OutputRoutine)( OutputRoutineParameter,
|
|
"%.*s",
|
|
IndentLevel,
|
|
BlanksForPadding
|
|
);
|
|
|
|
if (ValueName != NULL && *ValueName != UNICODE_NULL) {
|
|
if (NeedQuotedString( ValueName, NULL, &QuoteChar )) {
|
|
cbPrefix += (OutputRoutine)( OutputRoutineParameter,
|
|
"%c%ws%c ",
|
|
QuoteChar,
|
|
ValueName,
|
|
QuoteChar
|
|
);
|
|
}
|
|
else {
|
|
cbPrefix += (OutputRoutine)( OutputRoutineParameter, "%ws ", ValueName );
|
|
}
|
|
}
|
|
cbPrefix += (OutputRoutine)( OutputRoutineParameter, "= " );
|
|
|
|
switch( ValueType ) {
|
|
case REG_SZ:
|
|
case REG_EXPAND_SZ:
|
|
|
|
if (ValueType == REG_EXPAND_SZ) {
|
|
cbPrefix += (OutputRoutine)( OutputRoutineParameter, "REG_EXPAND_SZ " );
|
|
}
|
|
pw = (PWSTR)ValueData;
|
|
if (ValueLength & (sizeof(WCHAR)-1)) {
|
|
(OutputRoutine)( OutputRoutineParameter, "(*** Length not multiple of WCHAR ***)" );
|
|
ValueLength = (ValueLength+sizeof(WCHAR)-1) & ~(sizeof(WCHAR)-1);
|
|
}
|
|
|
|
if (ValueLength == 0 ||
|
|
*(PWSTR)((PCHAR)pw + ValueLength - sizeof( WCHAR )) != UNICODE_NULL
|
|
) {
|
|
(OutputRoutine)( OutputRoutineParameter, "(*** MISSING TRAILING NULL CHARACTER ***)" );
|
|
*(PWSTR)((PCHAR)pw + ValueLength) = UNICODE_NULL;
|
|
}
|
|
|
|
if (NeedQuotedString( NULL, pw, &QuoteChar )) {
|
|
(OutputRoutine)( OutputRoutineParameter, "%c%ws%c", QuoteChar, pw, QuoteChar );
|
|
}
|
|
else
|
|
if ((cbPrefix + wcslen(pw)) <= OutputWidth) {
|
|
(OutputRoutine)( OutputRoutineParameter, "%ws", pw );
|
|
}
|
|
else {
|
|
while (*pw) {
|
|
pw1 = pw;
|
|
pwBreak = NULL;
|
|
while (*pw1 && *pw1 >= L' ') {
|
|
if ((cbPrefix + (ULONG)(pw1 - pw)) > (OutputWidth-4)) {
|
|
break;
|
|
}
|
|
|
|
if (wcschr( L" ,;", *pw1 )) {
|
|
pwBreak = pw1;
|
|
}
|
|
|
|
pw1++;
|
|
}
|
|
|
|
if (pwBreak != NULL) {
|
|
while (*pwBreak == pwBreak[1]) {
|
|
pwBreak += 1;
|
|
}
|
|
pw1 = pwBreak + 1;
|
|
}
|
|
else {
|
|
while (*pw1) {
|
|
pw1 += 1;
|
|
}
|
|
}
|
|
|
|
(OutputRoutine)( OutputRoutineParameter, "%.*ws", pw1 - pw, pw );
|
|
if (*pw1 == UNICODE_NULL) {
|
|
break;
|
|
}
|
|
if (SummaryOutput) {
|
|
(OutputRoutine)( OutputRoutineParameter, "\\..." );
|
|
break;
|
|
}
|
|
|
|
(OutputRoutine)( OutputRoutineParameter,
|
|
"\\\n%.*s",
|
|
IndentLevel == 0 ? 4 : cbPrefix,
|
|
BlanksForPadding
|
|
);
|
|
pw = pw1;
|
|
}
|
|
}
|
|
|
|
(OutputRoutine)( OutputRoutineParameter, "\n" );
|
|
break;
|
|
|
|
case REG_RESOURCE_LIST:
|
|
case REG_FULL_RESOURCE_DESCRIPTOR:
|
|
case REG_RESOURCE_REQUIREMENTS_LIST:
|
|
case REG_BINARY:
|
|
case REG_NONE:
|
|
switch( ValueType ) {
|
|
case REG_NONE:
|
|
pw = L"REG_NONE";
|
|
break;
|
|
case REG_BINARY:
|
|
pw = L"REG_BINARY";
|
|
break;
|
|
case REG_RESOURCE_REQUIREMENTS_LIST:
|
|
pw = L"REG_RESOURCE_REQUIREMENTS_LIST";
|
|
break;
|
|
case REG_RESOURCE_LIST:
|
|
pw = L"REG_RESOURCE_LIST";
|
|
break;
|
|
case REG_FULL_RESOURCE_DESCRIPTOR:
|
|
pw = L"REG_FULL_RESOURCE_DESCRIPTOR";
|
|
break;
|
|
}
|
|
cb = (OutputRoutine)( OutputRoutineParameter, "%ws 0x%08lx", pw, ValueLength );
|
|
|
|
if (ValueLength != 0) {
|
|
p = (PULONG)ValueData;
|
|
i = (ValueLength + 3) / sizeof( ULONG );
|
|
if (!SummaryOutput || i <= 2) {
|
|
for (j=0; j<i; j++) {
|
|
if ((cbPrefix + cb + 11) > (OutputWidth - 2)) {
|
|
(OutputRoutine)( OutputRoutineParameter,
|
|
" \\\n%.*s",
|
|
IndentLevel == 0 ? 4 : cbPrefix,
|
|
BlanksForPadding
|
|
);
|
|
cb = 0;
|
|
}
|
|
else {
|
|
cb += (OutputRoutine)( OutputRoutineParameter, " " );
|
|
}
|
|
|
|
cb += (OutputRoutine)( OutputRoutineParameter, "0x%08lx", *p++ );
|
|
}
|
|
}
|
|
else {
|
|
(OutputRoutine)( OutputRoutineParameter, " \\..." );
|
|
}
|
|
}
|
|
|
|
(OutputRoutine)( OutputRoutineParameter, "\n" );
|
|
|
|
if (!SummaryOutput) {
|
|
RegDisplayResourceListAsComment( OutputWidth,
|
|
OutputRoutine,
|
|
OutputRoutineParameter,
|
|
IndentLevel,
|
|
ValueLength,
|
|
ValueType,
|
|
ValueData
|
|
);
|
|
}
|
|
|
|
break;
|
|
|
|
// case REG_DWORD_LITTLE_ENDIAN:
|
|
case REG_DWORD:
|
|
(OutputRoutine)( OutputRoutineParameter, "REG_DWORD 0x%08lx\n",
|
|
*(PULONG)ValueData
|
|
);
|
|
break;
|
|
|
|
case REG_DWORD_BIG_ENDIAN:
|
|
(OutputRoutine)( OutputRoutineParameter, "REG_DWORD_BIG_ENDIAN 0x%08lx\n",
|
|
*(PULONG)ValueData
|
|
);
|
|
break;
|
|
|
|
case REG_LINK:
|
|
(OutputRoutine)( OutputRoutineParameter, "REG_LINK %ws\n",
|
|
(PWSTR)ValueData
|
|
);
|
|
break;
|
|
|
|
case REG_MULTI_SZ:
|
|
(!FullPathOutput) ? strcpy (eol, " \\\n%.*s") : strcpy (eol, " \\ ->%.*s");
|
|
cbPrefix += (OutputRoutine)( OutputRoutineParameter, "REG_MULTI_SZ " );
|
|
pw = (PWSTR)ValueData;
|
|
i = 0;
|
|
if (*pw)
|
|
while (i < (ValueLength - 1) / sizeof( WCHAR )) {
|
|
if (i > 0) {
|
|
(OutputRoutine)( OutputRoutineParameter,
|
|
eol,
|
|
IndentLevel == 0 ? 4 : cbPrefix,
|
|
BlanksForPadding
|
|
);
|
|
}
|
|
(OutputRoutine)( OutputRoutineParameter, "\"");
|
|
do {
|
|
if (pw[i] == '"') {
|
|
(OutputRoutine)( OutputRoutineParameter, "%wc",pw[i]);
|
|
}
|
|
(OutputRoutine)( OutputRoutineParameter, "%wc",pw[i]);
|
|
++i;
|
|
}
|
|
while ( pw[i] != UNICODE_NULL );
|
|
(OutputRoutine)( OutputRoutineParameter, "\" ");
|
|
|
|
if (SummaryOutput) {
|
|
(OutputRoutine)( OutputRoutineParameter, " \\..." );
|
|
break;
|
|
}
|
|
|
|
++i;
|
|
}
|
|
|
|
(OutputRoutine)( OutputRoutineParameter, "\n" );
|
|
break;
|
|
|
|
default:
|
|
(OutputRoutine)( OutputRoutineParameter, "*** Unknown Registry Data Type (%08lx) Length: 0x%lx\n",
|
|
ValueType,
|
|
ValueLength
|
|
);
|
|
break;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void
|
|
RegDisplayResourceListAsComment(
|
|
ULONG OutputWidth,
|
|
PREG_OUTPUT_ROUTINE OutputRoutine,
|
|
PVOID OutputRoutineParameter,
|
|
ULONG IndentLevel,
|
|
ULONG ValueLength,
|
|
ULONG ValueType,
|
|
PWSTR ValueData
|
|
)
|
|
{
|
|
PCM_RESOURCE_LIST ResourceList = (PCM_RESOURCE_LIST)ValueData;
|
|
PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor;
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialResourceDescriptor;
|
|
ULONG i, j, k, l, count, cb;
|
|
PWSTR TypeName;
|
|
PWSTR FlagName;
|
|
ULONG Size = ValueLength;
|
|
PULONG p;
|
|
|
|
if (ValueType == REG_RESOURCE_LIST) {
|
|
if (ValueLength < sizeof( *ResourceList )) {
|
|
return;
|
|
}
|
|
|
|
count = ResourceList->Count;
|
|
FullDescriptor = &ResourceList->List[0];
|
|
(OutputRoutine)( OutputRoutineParameter,
|
|
";%.*sNumber of Full resource Descriptors = %d",
|
|
IndentLevel - 1,
|
|
BlanksForPadding,
|
|
count
|
|
);
|
|
}
|
|
else
|
|
if (ValueType == REG_FULL_RESOURCE_DESCRIPTOR) {
|
|
if (ValueLength < sizeof( *FullDescriptor )) {
|
|
return;
|
|
}
|
|
|
|
count = 1;
|
|
FullDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)ValueData;
|
|
}
|
|
else {
|
|
return;
|
|
}
|
|
|
|
for (i=0; i< count; i++) {
|
|
(OutputRoutine)( OutputRoutineParameter, "\n;%.*sPartial List number %d\n",
|
|
IndentLevel+4-1,
|
|
BlanksForPadding,
|
|
i
|
|
);
|
|
|
|
switch(FullDescriptor->InterfaceType) {
|
|
case InterfaceTypeUndefined: TypeName = L"Undefined";break;
|
|
case Internal: TypeName = L"Internal"; break;
|
|
case Isa: TypeName = L"Isa"; break;
|
|
case Eisa: TypeName = L"Eisa"; break;
|
|
case MicroChannel: TypeName = L"MicroChannel"; break;
|
|
case TurboChannel: TypeName = L"TurboChannel"; break;
|
|
case PCIBus: TypeName = L"PCI"; break;
|
|
case VMEBus: TypeName = L"VME"; break;
|
|
case NuBus: TypeName = L"NuBus"; break;
|
|
case PCMCIABus: TypeName = L"PCMCIA"; break;
|
|
case CBus: TypeName = L"CBUS"; break;
|
|
case MPIBus: TypeName = L"MPI"; break;
|
|
case MPSABus: TypeName = L"MPSA"; break;
|
|
case ProcessorInternal: TypeName = L"ProcessorInternal";break;
|
|
case InternalPowerBus: TypeName = L"InternalPower"; break;
|
|
case PNPISABus: TypeName = L"PNP Isa"; break;
|
|
|
|
default:
|
|
TypeName = L"***invalid bus type***";
|
|
break;
|
|
}
|
|
|
|
(OutputRoutine)( OutputRoutineParameter, ";%.*sINTERFACE_TYPE %ws\n",
|
|
IndentLevel+8-1,
|
|
BlanksForPadding,
|
|
TypeName
|
|
);
|
|
|
|
(OutputRoutine)( OutputRoutineParameter, ";%.*sBUS_NUMBER %d\n",
|
|
IndentLevel+8-1,
|
|
BlanksForPadding,
|
|
FullDescriptor->BusNumber
|
|
);
|
|
|
|
//
|
|
// This is a basic test to see if the data format is right.
|
|
// We know at least some video resource list are bogus ...
|
|
//
|
|
|
|
if (Size < FullDescriptor->PartialResourceList.Count *
|
|
sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) ) {
|
|
|
|
(OutputRoutine)( OutputRoutineParameter, "\n;%.*s *** !!! Invalid ResourceList !!! *** \n",
|
|
IndentLevel+8-1,
|
|
BlanksForPadding,
|
|
i
|
|
);
|
|
|
|
break;
|
|
}
|
|
|
|
Size -= FullDescriptor->PartialResourceList.Count *
|
|
sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
|
|
|
|
|
|
|
|
for (j=0; j<FullDescriptor->PartialResourceList.Count; j++) {
|
|
|
|
(OutputRoutine)( OutputRoutineParameter, ";%.*sDescriptor number %d\n",
|
|
IndentLevel+12-1,
|
|
BlanksForPadding,
|
|
j
|
|
);
|
|
|
|
PartialResourceDescriptor = &(FullDescriptor->PartialResourceList.PartialDescriptors[j]);
|
|
switch(PartialResourceDescriptor->ShareDisposition) {
|
|
case CmResourceShareUndetermined:
|
|
TypeName = L"CmResourceShareUndetermined";
|
|
break;
|
|
case CmResourceShareDeviceExclusive:
|
|
TypeName = L"CmResourceDeviceExclusive";
|
|
break;
|
|
case CmResourceShareDriverExclusive:
|
|
TypeName = L"CmResourceDriverExclusive";
|
|
break;
|
|
case CmResourceShareShared:
|
|
TypeName = L"CmResourceShared";
|
|
break;
|
|
default:
|
|
TypeName = L"***invalid share disposition***";
|
|
break;
|
|
}
|
|
|
|
(OutputRoutine)( OutputRoutineParameter, ";%.*sShare Disposition %ws\n",
|
|
IndentLevel+12-1,
|
|
BlanksForPadding,
|
|
TypeName
|
|
);
|
|
|
|
FlagName = L"***invalid Flags";
|
|
|
|
switch(PartialResourceDescriptor->Type) {
|
|
case CmResourceTypeNull:
|
|
TypeName = L"NULL";
|
|
FlagName = L"***Unused";
|
|
break;
|
|
case CmResourceTypePort:
|
|
TypeName = L"PORT";
|
|
if (PartialResourceDescriptor->Flags == CM_RESOURCE_PORT_MEMORY) {
|
|
FlagName = L"CM_RESOURCE_PORT_MEMORY";
|
|
}
|
|
if (PartialResourceDescriptor->Flags == CM_RESOURCE_PORT_IO) {
|
|
FlagName = L"CM_RESOURCE_PORT_IO";
|
|
}
|
|
break;
|
|
case CmResourceTypeInterrupt:
|
|
TypeName = L"INTERRUPT";
|
|
if (PartialResourceDescriptor->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE) {
|
|
FlagName = L"CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE";
|
|
}
|
|
if (PartialResourceDescriptor->Flags == CM_RESOURCE_INTERRUPT_LATCHED) {
|
|
FlagName = L"CM_RESOURCE_INTERRUPT_LATCHED";
|
|
}
|
|
break;
|
|
case CmResourceTypeMemory:
|
|
TypeName = L"MEMORY";
|
|
if (PartialResourceDescriptor->Flags == CM_RESOURCE_MEMORY_READ_WRITE) {
|
|
FlagName = L"CM_RESOURCE_MEMORY_READ_WRITE";
|
|
}
|
|
if (PartialResourceDescriptor->Flags == CM_RESOURCE_MEMORY_READ_ONLY) {
|
|
FlagName = L"CM_RESOURCE_MEMORY_READ_ONLY";
|
|
}
|
|
if (PartialResourceDescriptor->Flags == CM_RESOURCE_MEMORY_WRITE_ONLY) {
|
|
FlagName = L"CM_RESOURCE_MEMORY_WRITE_ONLY";
|
|
}
|
|
break;
|
|
case CmResourceTypeDma:
|
|
TypeName = L"DMA";
|
|
FlagName = L"***Unused";
|
|
break;
|
|
case CmResourceTypeDeviceSpecific:
|
|
TypeName = L"DEVICE SPECIFIC";
|
|
FlagName = L"***Unused";
|
|
break;
|
|
default:
|
|
TypeName = L"***invalid type***";
|
|
break;
|
|
}
|
|
|
|
(OutputRoutine)( OutputRoutineParameter, ";%.*sTYPE %ws\n",
|
|
IndentLevel+12-1,
|
|
BlanksForPadding,
|
|
TypeName
|
|
);
|
|
|
|
(OutputRoutine)( OutputRoutineParameter, ";%.*sFlags %ws\n",
|
|
IndentLevel+12-1,
|
|
BlanksForPadding,
|
|
FlagName
|
|
);
|
|
|
|
switch(PartialResourceDescriptor->Type) {
|
|
case CmResourceTypePort:
|
|
(OutputRoutine)( OutputRoutineParameter, ";%.*sSTART 0x%08lx LENGTH 0x%08lx\n",
|
|
IndentLevel+12-1,
|
|
BlanksForPadding,
|
|
PartialResourceDescriptor->u.Port.Start.LowPart,
|
|
PartialResourceDescriptor->u.Port.Length
|
|
);
|
|
break;
|
|
|
|
case CmResourceTypeInterrupt:
|
|
(OutputRoutine)( OutputRoutineParameter, ";%.*sLEVEL %d VECTOR %d AFFINITY %d\n",
|
|
IndentLevel+12-1,
|
|
BlanksForPadding,
|
|
PartialResourceDescriptor->u.Interrupt.Level,
|
|
PartialResourceDescriptor->u.Interrupt.Vector,
|
|
PartialResourceDescriptor->u.Interrupt.Affinity
|
|
);
|
|
break;
|
|
|
|
case CmResourceTypeMemory:
|
|
(OutputRoutine)( OutputRoutineParameter, ";%.*sSTART 0x%08lx%08lx LENGTH 0x%08lx\n",
|
|
IndentLevel+12-1,
|
|
BlanksForPadding,
|
|
PartialResourceDescriptor->u.Memory.Start.HighPart,
|
|
PartialResourceDescriptor->u.Memory.Start.LowPart,
|
|
PartialResourceDescriptor->u.Memory.Length
|
|
);
|
|
break;
|
|
|
|
case CmResourceTypeDma:
|
|
(OutputRoutine)( OutputRoutineParameter, ";%.*sCHANNEL %d PORT %d\n",
|
|
IndentLevel+12-1,
|
|
BlanksForPadding,
|
|
PartialResourceDescriptor->u.Dma.Channel,
|
|
PartialResourceDescriptor->u.Dma.Port
|
|
);
|
|
break;
|
|
|
|
case CmResourceTypeDeviceSpecific:
|
|
cb = (OutputRoutine)( OutputRoutineParameter, ";%.*sDataSize 0x%08lx Data:",
|
|
IndentLevel+12-1,
|
|
BlanksForPadding,
|
|
PartialResourceDescriptor->u.DeviceSpecificData.DataSize
|
|
);
|
|
|
|
p = (PULONG)(PartialResourceDescriptor + 1);
|
|
k = (PartialResourceDescriptor->u.DeviceSpecificData.DataSize + 3) / sizeof( ULONG );
|
|
for (l=0; l<k; l++) {
|
|
if ((cb + 11) >= OutputWidth) {
|
|
cb = (OutputRoutine)( OutputRoutineParameter, "\n;%.*s",
|
|
IndentLevel+12-1,
|
|
BlanksForPadding
|
|
) - 1;
|
|
}
|
|
|
|
cb += (OutputRoutine)( OutputRoutineParameter, " 0x%08lx", *p++ );
|
|
}
|
|
|
|
(OutputRoutine)( OutputRoutineParameter, "\n" );
|
|
break;
|
|
|
|
default:
|
|
(OutputRoutine)( OutputRoutineParameter, ";%.*s*** Unknown resource list type: 0x%x ****\n",
|
|
IndentLevel+12-1,
|
|
BlanksForPadding,
|
|
PartialResourceDescriptor->Type
|
|
);
|
|
break;
|
|
}
|
|
|
|
(OutputRoutine)( OutputRoutineParameter, ";\n" );
|
|
}
|
|
|
|
FullDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR) (PartialResourceDescriptor+1);
|
|
}
|
|
|
|
return;
|
|
}
|