mirror of https://github.com/lianthony/NT4.0
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.
711 lines
23 KiB
711 lines
23 KiB
/*++
|
|
|
|
Copyright (c) 1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
config.c
|
|
|
|
Abstract:
|
|
|
|
This module contains RPL config apis: ConfigEnum.
|
|
|
|
Author:
|
|
|
|
Vladimir Z. Vulovic (vladimv) 05 - November - 1993
|
|
|
|
Revision History:
|
|
|
|
05-Nov-1993 vladimv
|
|
Created
|
|
|
|
--*/
|
|
|
|
#include "local.h"
|
|
#include "rpldb.h"
|
|
#include "db.h"
|
|
#include "dblib.h"
|
|
#include "boot.h"
|
|
#include "profile.h"
|
|
#define RPLCONFIG_ALLOCATE
|
|
#include "config.h"
|
|
#undef RPLCONFIG_ALLOCATE
|
|
#include "setup.h" // IsConfigEnabled()
|
|
|
|
|
|
|
|
DWORD ConfigSetInfo(
|
|
IN PRPL_SESSION pSession,
|
|
IN DWORD Level,
|
|
IN LPVOID Buffer,
|
|
OUT LPDWORD pErrorParameter
|
|
)
|
|
{
|
|
LPRPL_CONFIG_INFO_2 Info = Buffer;
|
|
switch( Level) {
|
|
case 2:
|
|
if ( Info->FitPersonal != NULL) {
|
|
*pErrorParameter = CONFIG_FitPersonal;
|
|
CallM( JetSetColumn( pSession->SesId, pSession->ConfigTableId,
|
|
ConfigTable[ CONFIG_FitPersonal].ColumnId,
|
|
Info->FitPersonal,
|
|
( wcslen( Info->FitPersonal) + 1) * sizeof(WCHAR),
|
|
0, NULL));
|
|
}
|
|
if ( Info->FitShared != NULL) {
|
|
*pErrorParameter = CONFIG_FitShared;
|
|
CallM( JetSetColumn( pSession->SesId, pSession->ConfigTableId,
|
|
ConfigTable[ CONFIG_FitShared].ColumnId,
|
|
Info->FitShared,
|
|
( wcslen( Info->FitShared) + 1) * sizeof(WCHAR),
|
|
0, NULL));
|
|
}
|
|
if ( Info->DirName4 != NULL) {
|
|
*pErrorParameter = CONFIG_DirName4;
|
|
CallM( JetSetColumn( pSession->SesId, pSession->ConfigTableId,
|
|
ConfigTable[ CONFIG_DirName4].ColumnId,
|
|
Info->DirName4,
|
|
( wcslen( Info->DirName4) + 1) * sizeof(WCHAR),
|
|
0, NULL));
|
|
}
|
|
if ( Info->DirName3 != NULL) {
|
|
*pErrorParameter = CONFIG_DirName3;
|
|
CallM( JetSetColumn( pSession->SesId, pSession->ConfigTableId,
|
|
ConfigTable[ CONFIG_DirName3].ColumnId,
|
|
Info->DirName3,
|
|
( wcslen( Info->DirName3) + 1) * sizeof(WCHAR),
|
|
0, NULL));
|
|
}
|
|
if ( Info->DirName2 != NULL) {
|
|
*pErrorParameter = CONFIG_DirName2;
|
|
CallM( JetSetColumn( pSession->SesId, pSession->ConfigTableId,
|
|
ConfigTable[ CONFIG_DirName2].ColumnId,
|
|
Info->DirName2,
|
|
( wcslen( Info->DirName2) + 1) * sizeof(WCHAR),
|
|
0, NULL));
|
|
}
|
|
if ( Info->DirName != NULL) {
|
|
*pErrorParameter = CONFIG_DirName;
|
|
CallM( JetSetColumn( pSession->SesId, pSession->ConfigTableId,
|
|
ConfigTable[ CONFIG_DirName].ColumnId,
|
|
Info->DirName,
|
|
( wcslen( Info->DirName) + 1) * sizeof(WCHAR),
|
|
0, NULL));
|
|
}
|
|
if ( Info->BootName != NULL) {
|
|
*pErrorParameter = CONFIG_BootName;
|
|
CallM( JetSetColumn( pSession->SesId, pSession->ConfigTableId,
|
|
ConfigTable[ CONFIG_BootName].ColumnId,
|
|
Info->BootName,
|
|
( wcslen( Info->BootName) + 1) * sizeof(WCHAR),
|
|
0, NULL));
|
|
}
|
|
NOTHING; // fall through
|
|
case 1:
|
|
if ( Info->Flags != 0) {
|
|
*pErrorParameter = CONFIG_Flags;
|
|
CallM( JetSetColumn( pSession->SesId, pSession->ConfigTableId,
|
|
ConfigTable[ CONFIG_Flags].ColumnId,
|
|
&Info->Flags, sizeof( Info->Flags), 0, NULL));
|
|
}
|
|
NOTHING; // fall through
|
|
case 0:
|
|
if ( Info->ConfigComment != NULL) {
|
|
*pErrorParameter = CONFIG_ConfigComment;
|
|
CallM( JetSetColumn( pSession->SesId, pSession->ConfigTableId,
|
|
ConfigTable[ CONFIG_ConfigComment].ColumnId,
|
|
Info->ConfigComment,
|
|
( wcslen( Info->ConfigComment) + 1) * sizeof(WCHAR),
|
|
0, NULL));
|
|
}
|
|
if ( Info->ConfigName != NULL) {
|
|
*pErrorParameter = CONFIG_ConfigName;
|
|
CallM( JetSetColumn( pSession->SesId, pSession->ConfigTableId,
|
|
ConfigTable[ CONFIG_ConfigName].ColumnId,
|
|
Info->ConfigName,
|
|
( wcslen( Info->ConfigName) + 1) * sizeof(WCHAR),
|
|
0, NULL));
|
|
}
|
|
break;
|
|
}
|
|
return( NO_ERROR);
|
|
}
|
|
|
|
|
|
DWORD ConfigGetField(
|
|
IN PRPL_SESSION pSession,
|
|
IN DWORD FieldIndex,
|
|
OUT LPVOID * pData,
|
|
IN OUT LPINT pSpaceLeft
|
|
)
|
|
{
|
|
BYTE LocalBuffer[ 300];
|
|
PBYTE Buffer;
|
|
DWORD DataSize;
|
|
DWORD BufferSize;
|
|
JET_ERR JetError;
|
|
|
|
switch( FieldIndex) {
|
|
case CONFIG_Flags:
|
|
Buffer = (PBYTE)pData;
|
|
BufferSize = sizeof( DWORD);
|
|
break;
|
|
default:
|
|
Buffer = LocalBuffer;
|
|
BufferSize = sizeof( LocalBuffer);
|
|
break;
|
|
}
|
|
JetError = JetRetrieveColumn( pSession->SesId, pSession->ConfigTableId,
|
|
ConfigTable[ FieldIndex].ColumnId, Buffer,
|
|
BufferSize, &DataSize, 0, NULL);
|
|
if ( JetError < 0) {
|
|
RplDump( ++RG_Assert, ("JetError=%d", JetError));
|
|
return( NERR_RplConfigInfoCorrupted);
|
|
}
|
|
if ( Buffer != LocalBuffer) {
|
|
if ( BufferSize == DataSize) {
|
|
return( NO_ERROR);
|
|
} else {
|
|
RplDump( ++RG_Assert, ("Bad DataSize=0x%x", DataSize));
|
|
return( NERR_RplConfigInfoCorrupted);
|
|
}
|
|
}
|
|
//
|
|
// We have done with fixed data. From here on we deal with unicode
|
|
// strings only.
|
|
//
|
|
if ( DataSize > sizeof( LocalBuffer)) {
|
|
RplDump( ++RG_Assert, ( "Too big DataSize=0x%x", DataSize));
|
|
return( NERR_RplConfigInfoCorrupted);
|
|
}
|
|
if ( DataSize == 0) {
|
|
if ( JetError != JET_wrnColumnNull) {
|
|
RplDump( ++RG_Assert, ( "JetError=%d", JetError));
|
|
return( NERR_RplConfigInfoCorrupted);
|
|
} else {
|
|
*pData = NULL; // so RPC rpcrt4!_tree_size_ndr() does not bomb here
|
|
return( NO_ERROR);
|
|
}
|
|
}
|
|
if ( DataSize & 1 != 0 || wcslen((PWCHAR)LocalBuffer) + 1 != DataSize/2) {
|
|
RplDump( ++RG_Assert, ("LocalBuffer=0x%x, DataSize=0x%x", LocalBuffer, DataSize));
|
|
return( NERR_RplConfigInfoCorrupted);
|
|
}
|
|
*pData = MIDL_user_allocate( DataSize);
|
|
if ( *pData == NULL) {
|
|
RplDump( ++RG_Assert, ( "Error=%d", GetLastError()));
|
|
RPL_RETURN( ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
memcpy( *pData, LocalBuffer, DataSize);
|
|
*pSpaceLeft -= DataSize; // BUGBUG might become negative?
|
|
return( NO_ERROR);
|
|
}
|
|
|
|
|
|
DWORD ConfigGetInfo(
|
|
IN PRPL_SESSION pSession,
|
|
IN LPWSTR ConfigName,
|
|
IN DWORD Level,
|
|
OUT LPVOID Buffer,
|
|
IN OUT LPINT pSpaceLeft
|
|
)
|
|
{
|
|
DWORD Error;
|
|
LPRPL_CONFIG_INFO_2 Info = Buffer;
|
|
|
|
switch( Level) {
|
|
case 2:
|
|
Error = ConfigGetField( pSession, CONFIG_FitPersonal, &Info->FitPersonal, pSpaceLeft);
|
|
if ( Error != NO_ERROR) {
|
|
return( Error);
|
|
}
|
|
Error = ConfigGetField( pSession, CONFIG_FitShared, &Info->FitShared, pSpaceLeft);
|
|
if ( Error != NO_ERROR) {
|
|
return( Error);
|
|
}
|
|
Error = ConfigGetField( pSession, CONFIG_DirName4, &Info->DirName4, pSpaceLeft);
|
|
if ( Error != NO_ERROR) {
|
|
return( Error);
|
|
}
|
|
Error = ConfigGetField( pSession, CONFIG_DirName3, &Info->DirName3, pSpaceLeft);
|
|
if ( Error != NO_ERROR) {
|
|
return( Error);
|
|
}
|
|
Error = ConfigGetField( pSession, CONFIG_DirName2, &Info->DirName2, pSpaceLeft);
|
|
if ( Error != NO_ERROR) {
|
|
return( Error);
|
|
}
|
|
Error = ConfigGetField( pSession, CONFIG_DirName, &Info->DirName, pSpaceLeft);
|
|
if ( Error != NO_ERROR) {
|
|
return( Error);
|
|
}
|
|
Error = ConfigGetField( pSession, CONFIG_BootName, &Info->BootName, pSpaceLeft);
|
|
if ( Error != NO_ERROR) {
|
|
return( Error);
|
|
}
|
|
NOTHING; // fall through
|
|
case 1:
|
|
Error = ConfigGetField( pSession, CONFIG_Flags, (LPVOID *)&Info->Flags, pSpaceLeft);
|
|
if ( Error != NO_ERROR) {
|
|
return( Error);
|
|
}
|
|
case 0:
|
|
Error = ConfigGetField( pSession, CONFIG_ConfigComment, &Info->ConfigComment, pSpaceLeft);
|
|
if ( Error != NO_ERROR) {
|
|
return( Error);
|
|
}
|
|
if ( ConfigName == NULL) {
|
|
Error = ConfigGetField( pSession, CONFIG_ConfigName, &Info->ConfigName, pSpaceLeft);
|
|
if ( Error != NO_ERROR) {
|
|
return( Error);
|
|
}
|
|
} else {
|
|
DWORD DataSize = (wcslen( ConfigName) + 1) * sizeof(WCHAR);
|
|
Info->ConfigName = MIDL_user_allocate( DataSize);
|
|
if ( Info->ConfigName == NULL) {
|
|
return( ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
RplDump( RG_DebugLevel & RPL_DEBUG_CONFIG, ( "ConfigName=0x%x", Info->ConfigName));
|
|
memcpy( Info->ConfigName, ConfigName, DataSize);
|
|
*pSpaceLeft -= DataSize;
|
|
}
|
|
break;
|
|
default:
|
|
return( ERROR_INVALID_LEVEL);
|
|
break;
|
|
}
|
|
return( NO_ERROR);
|
|
}
|
|
|
|
|
|
|
|
VOID ConfigGetInfoCleanup(
|
|
IN DWORD Level,
|
|
IN OUT LPVOID Buffer
|
|
)
|
|
{
|
|
LPRPL_CONFIG_INFO_2 Info = Buffer;
|
|
|
|
switch( Level) {
|
|
case 2:
|
|
if ( Info->FitPersonal != NULL) {
|
|
MIDL_user_free( Info->FitPersonal);
|
|
}
|
|
if ( Info->FitShared != NULL) {
|
|
MIDL_user_free( Info->FitShared);
|
|
}
|
|
if ( Info->DirName4 != NULL) {
|
|
MIDL_user_free( Info->DirName4);
|
|
}
|
|
if ( Info->DirName3 != NULL) {
|
|
MIDL_user_free( Info->DirName3);
|
|
}
|
|
if ( Info->DirName2 != NULL) {
|
|
MIDL_user_free( Info->DirName2);
|
|
}
|
|
if ( Info->DirName != NULL) {
|
|
MIDL_user_free( Info->DirName);
|
|
}
|
|
if ( Info->BootName != NULL) {
|
|
MIDL_user_free( Info->BootName);
|
|
}
|
|
NOTHING; // fall through
|
|
case 1:
|
|
NOTHING; // fall through
|
|
case 0:
|
|
if ( Info->ConfigComment != NULL) {
|
|
MIDL_user_free( Info->ConfigComment);
|
|
}
|
|
if ( Info->ConfigName != NULL) {
|
|
MIDL_user_free( Info->ConfigName);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
NET_API_STATUS NET_API_FUNCTION
|
|
NetrRplConfigAdd(
|
|
IN RPL_HANDLE ServerHandle,
|
|
IN DWORD Level,
|
|
OUT LPRPL_CONFIG_INFO_STRUCT ConfigInfoStruct,
|
|
OUT LPDWORD pErrorParameter OPTIONAL
|
|
)
|
|
{
|
|
LPRPL_CONFIG_INFO_2 Info;
|
|
LPVOID Buffer;
|
|
DWORD Error;
|
|
DWORD ErrorParameter;
|
|
PRPL_SESSION pSession = &RG_ApiSession;
|
|
|
|
ErrorParameter = INVALID_ERROR_PARAMETER;
|
|
Buffer = Info = ConfigInfoStruct->ConfigInfo2;
|
|
|
|
switch( Level) {
|
|
case 2:
|
|
if ( !ValidName( Info->FitPersonal, RPL_MAX_STRING_LENGTH, TRUE)) {
|
|
ErrorParameter = CONFIG_FitPersonal;
|
|
break;
|
|
}
|
|
if ( !ValidName( Info->FitShared, RPL_MAX_STRING_LENGTH, TRUE)) {
|
|
ErrorParameter = CONFIG_FitShared;
|
|
break;
|
|
}
|
|
if ( !ValidName( Info->DirName4, RPL_MAX_STRING_LENGTH, FALSE)) {
|
|
ErrorParameter = CONFIG_DirName4;
|
|
break;
|
|
}
|
|
if ( !ValidName( Info->DirName3, RPL_MAX_STRING_LENGTH, FALSE)) {
|
|
ErrorParameter = CONFIG_DirName3;
|
|
break;
|
|
}
|
|
if ( !ValidName( Info->DirName2, RPL_MAX_STRING_LENGTH, TRUE)) {
|
|
ErrorParameter = CONFIG_DirName2;
|
|
break;
|
|
}
|
|
if ( !ValidName( Info->DirName, RPL_MAX_STRING_LENGTH, TRUE)) {
|
|
ErrorParameter = CONFIG_DirName;
|
|
break;
|
|
}
|
|
if ( !ValidName( Info->BootName, RPL_MAX_BOOT_NAME_LENGTH, TRUE)) {
|
|
ErrorParameter = CONFIG_BootName;
|
|
break;
|
|
}
|
|
_wcsupr( Info->BootName);
|
|
if ( Info->Flags & ~CONFIG_FLAGS_MASK_ENABLED) {
|
|
ErrorParameter = CONFIG_Flags;
|
|
break;
|
|
}
|
|
switch ( Info->Flags) {
|
|
case 0:
|
|
Info->Flags = RplConfigEnabled( Info->DirName2) == TRUE ?
|
|
CONFIG_FLAGS_ENABLED_TRUE : CONFIG_FLAGS_ENABLED_FALSE;
|
|
break;
|
|
case CONFIG_FLAGS_ENABLED_TRUE:
|
|
case CONFIG_FLAGS_ENABLED_FALSE:
|
|
break;
|
|
default:
|
|
ErrorParameter = CONFIG_Flags;
|
|
break;
|
|
}
|
|
if ( RPL_STRING_TOO_LONG( Info->ConfigComment)) {
|
|
ErrorParameter = CONFIG_ConfigComment;
|
|
break;
|
|
}
|
|
if ( !ValidName( Info->ConfigName, RPL_MAX_CONFIG_NAME_LENGTH, TRUE)) {
|
|
ErrorParameter = CONFIG_ConfigName;
|
|
break;
|
|
}
|
|
_wcsupr( Info->ConfigName);
|
|
break;
|
|
default:
|
|
return( ERROR_INVALID_LEVEL);
|
|
break;
|
|
}
|
|
|
|
if ( ErrorParameter != INVALID_ERROR_PARAMETER) {
|
|
if ( ARGUMENT_PRESENT( pErrorParameter)) {
|
|
*pErrorParameter = ErrorParameter;
|
|
}
|
|
return( ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
EnterCriticalSection( &RG_ProtectDatabase);
|
|
Call( JetBeginTransaction( pSession->SesId));
|
|
|
|
//
|
|
// Verify that ConfigName is available in the database.
|
|
//
|
|
if ( RplFind( pSession, CONFIG_TABLE_TAG, Info->ConfigName)) {
|
|
Error = NERR_RplConfigNameUnavailable;
|
|
goto cleanup;
|
|
}
|
|
|
|
CallJ( JetPrepareUpdate( pSession->SesId, pSession->ConfigTableId, JET_prepInsert));
|
|
|
|
Error = ConfigSetInfo( pSession, Level, Buffer, &ErrorParameter);
|
|
if ( Error == ERROR_SUCCESS) {
|
|
ErrorParameter = 0;
|
|
CallJ( JetUpdate( pSession->SesId, pSession->ConfigTableId, NULL, 0, NULL));
|
|
}
|
|
|
|
cleanup:
|
|
if ( Error == NO_ERROR) {
|
|
Call( JetCommitTransaction( pSession->SesId, JET_bitCommitFlush));
|
|
} else {
|
|
Call( JetRollback( pSession->SesId, JET_bitRollbackAll));
|
|
}
|
|
LeaveCriticalSection( &RG_ProtectDatabase);
|
|
|
|
if ( Error != ERROR_SUCCESS) {
|
|
if ( ARGUMENT_PRESENT( pErrorParameter)) {
|
|
*pErrorParameter = ErrorParameter;
|
|
}
|
|
}
|
|
return( Error);
|
|
}
|
|
|
|
|
|
NET_API_STATUS NET_API_FUNCTION
|
|
NetrRplConfigDel(
|
|
IN RPL_HANDLE ServerHandle,
|
|
IN LPWSTR ConfigName
|
|
)
|
|
/*++
|
|
--*/
|
|
{
|
|
DWORD Error;
|
|
PRPL_SESSION pSession = &RG_ApiSession;
|
|
|
|
_wcsupr( ConfigName);
|
|
|
|
EnterCriticalSection( &RG_ProtectDatabase);
|
|
Call( JetBeginTransaction( pSession->SesId));
|
|
|
|
if ( RplFindByField( pSession, PROFILE_TABLE_TAG,
|
|
PROFILE_INDEX_ConfigNameProfileName, ConfigName)) {
|
|
//
|
|
// We found a PROFILE record which uses this CONFIG.
|
|
//
|
|
Error = NERR_RplConfigNotEmpty;
|
|
goto cleanup;
|
|
}
|
|
if ( !RplFind( pSession, CONFIG_TABLE_TAG, ConfigName)) {
|
|
Error = NERR_RplConfigNotFound;
|
|
goto cleanup;
|
|
}
|
|
CallJ( JetDelete( pSession->SesId, pSession->ConfigTableId));
|
|
Error = NO_ERROR;
|
|
|
|
cleanup:
|
|
if ( Error == NO_ERROR) {
|
|
Call( JetCommitTransaction( pSession->SesId, JET_bitCommitFlush));
|
|
} else {
|
|
Call( JetRollback( pSession->SesId, JET_bitRollbackAll));
|
|
}
|
|
LeaveCriticalSection( &RG_ProtectDatabase);
|
|
return( Error);
|
|
}
|
|
|
|
|
|
NET_API_STATUS NET_API_FUNCTION
|
|
NetrRplConfigEnum(
|
|
IN RPL_RPC_HANDLE ServerHandle,
|
|
IN PWCHAR AdapterName,
|
|
IN OUT LPRPL_CONFIG_ENUM ConfigEnum,
|
|
IN DWORD PrefMaxLength,
|
|
OUT LPDWORD TotalEntries,
|
|
IN OUT LPDWORD pResumeHandle OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
If AdapterName is null, enumerate all configurations.
|
|
If AdapterName is not null, enumerate all configurations that can support
|
|
this adapter id.
|
|
|
|
Arguments:
|
|
|
|
pServerHandle - ptr to RPL_HANDLE
|
|
|
|
InfoStruct - Pointer to a structure that contains the information that
|
|
RPC needs about the returned data. This structure contains the
|
|
following information:
|
|
Level - The desired information level - indicates how to
|
|
interpret the structure of the returned buffer.
|
|
EntriesRead - Indicates how many elements are returned in the
|
|
array of structures that are returned.
|
|
BufferPointer - Location for the pointer to the array of
|
|
structures that are being returned.
|
|
|
|
PrefMaxLen - Indicates a maximum size limit that the caller will allow
|
|
for (the return buffer.
|
|
|
|
TotalEntries - Pointer to a value that upon return indicates the total
|
|
number of entries in the "active" database.
|
|
|
|
pResumeHandle - Inidcates where to restart the enumeration. This is an
|
|
optional parameter and can be NULL.
|
|
|
|
Return Value:
|
|
NO_ERROR if success.
|
|
|
|
--*/
|
|
{
|
|
LPBYTE Buffer;
|
|
DWORD TypicalSize;
|
|
DWORD CoreSize;
|
|
DWORD Error;
|
|
INT SpaceLeft;
|
|
DWORD ArrayLength;
|
|
DWORD EntriesRead;
|
|
BOOL InfoError;
|
|
BOOL TableEnd;
|
|
RPL_FILTER Filter;
|
|
PRPL_FILTER pFilter;
|
|
PRPL_SESSION pSession = &RG_ApiSession;
|
|
|
|
switch( ConfigEnum->Level) {
|
|
case 2:
|
|
TypicalSize = CoreSize = sizeof( RPL_CONFIG_INFO_2);
|
|
TypicalSize += 20 * sizeof( WCHAR); // typical size of FitPersonal
|
|
TypicalSize += 20 * sizeof( WCHAR); // typical size of FitShared
|
|
TypicalSize += 12 * sizeof( WCHAR); // typical size of DirName4
|
|
TypicalSize += 12 * sizeof( WCHAR); // typical size of DirName3
|
|
TypicalSize += 12 * sizeof( WCHAR); // typical size of DirName2
|
|
TypicalSize += 12 * sizeof( WCHAR); // typical size of DirName
|
|
TypicalSize += 8 * sizeof( WCHAR); // typical size of BootName
|
|
NOTHING; // fall through
|
|
case 1:
|
|
if ( ConfigEnum->Level == 1) {
|
|
TypicalSize = CoreSize = sizeof( RPL_CONFIG_INFO_1);
|
|
}
|
|
NOTHING; // fall through
|
|
case 0:
|
|
if ( ConfigEnum->Level == 0) {
|
|
TypicalSize = CoreSize = sizeof( RPL_CONFIG_INFO_0);
|
|
}
|
|
TypicalSize += 20 * sizeof( WCHAR); // typical size of ConfigComment
|
|
TypicalSize += 8 * sizeof( WCHAR); // typical size of ConfigName
|
|
break;
|
|
default:
|
|
return( ERROR_INVALID_LEVEL);
|
|
break;
|
|
}
|
|
|
|
if ( AdapterName != NULL) {
|
|
pFilter = &Filter;
|
|
if ( !ValidHexName( AdapterName, RPL_ADAPTER_NAME_LENGTH, TRUE)) {
|
|
return( ERROR_INVALID_PARAMETER);
|
|
}
|
|
pFilter->VendorId = AdapterNameToVendorId( AdapterName);
|
|
pFilter->FindFirst = TRUE;
|
|
} else {
|
|
pFilter = NULL;
|
|
}
|
|
|
|
if ( PrefMaxLength == -1) {
|
|
//
|
|
// If the caller has not specified a size, calculate a size
|
|
// that will hold the entire enumeration.
|
|
//
|
|
SpaceLeft = DEFAULT_BUFFER_SIZE;
|
|
} else {
|
|
SpaceLeft = PrefMaxLength;
|
|
}
|
|
|
|
//
|
|
// Buffer space is shared by the array and by strings pointed at
|
|
// by the elements in this array. We need to decide up front how much
|
|
// space is allocated for array and how much for the strings.
|
|
//
|
|
ArrayLength = SpaceLeft / TypicalSize;
|
|
if ( ArrayLength == 0) {
|
|
ArrayLength = 1; // try to return at least one element
|
|
}
|
|
|
|
//
|
|
// Note that MIDL_user_allocate() returns memory which is NOT initialized
|
|
// to zero. Since we do NOT use allocate all nodes, this means that all
|
|
// fields, especially pointers, in array elements must be properly set.
|
|
//
|
|
Buffer = MIDL_user_allocate( ArrayLength * CoreSize);
|
|
if ( Buffer == NULL) {
|
|
return( ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
RplDump( RG_DebugLevel & RPL_DEBUG_CONFIG, (
|
|
"ConfigEnum: Buffer=0x%x, ArrayLength=0x%x", Buffer, ArrayLength));
|
|
ConfigEnum->ConfigInfo.Level0->Buffer = (LPRPL_CONFIG_INFO_0)Buffer;
|
|
|
|
EntriesRead = 0;
|
|
InfoError = FALSE;
|
|
Error = NO_ERROR;
|
|
|
|
EnterCriticalSection( &RG_ProtectDatabase);
|
|
Call( JetBeginTransaction( pSession->SesId));
|
|
|
|
if ( !RplFilterFirst( pSession, CONFIG_TABLE_TAG, pFilter, pResumeHandle, &TableEnd)) {
|
|
Error = NERR_RplCannotEnum;
|
|
goto cleanup;
|
|
}
|
|
if ( TableEnd == TRUE) {
|
|
goto cleanup;
|
|
}
|
|
for ( ; ; ) {
|
|
memset( Buffer, 0, CoreSize); // for cleanup to work properly
|
|
Error = ConfigGetInfo( pSession, NULL, ConfigEnum->Level, Buffer, &SpaceLeft);
|
|
if ( Error != NO_ERROR) {
|
|
InfoError = TRUE; // clean things up without holding crit sec
|
|
break;
|
|
}
|
|
EntriesRead++;
|
|
Buffer += CoreSize;
|
|
SpaceLeft -= CoreSize;
|
|
if ( !RplFilterNext( pSession, pSession->ConfigTableId, pFilter, &TableEnd)) {
|
|
Error = NERR_RplCannotEnum;
|
|
goto cleanup;
|
|
}
|
|
if ( TableEnd == TRUE) {
|
|
goto cleanup;
|
|
}
|
|
if ( SpaceLeft <= 0) {
|
|
Error = ERROR_MORE_DATA;
|
|
break;
|
|
}
|
|
if ( EntriesRead >= ArrayLength) {
|
|
//
|
|
// We have space available but allocated array is not big enough.
|
|
// This should NOT happen often as our intent (see above) is to
|
|
// overestimate array length. When it happens we can still try
|
|
// to reallocate array to a larger size here. This is not done
|
|
// for now (too cumbersome) & we just stop the enumeration.
|
|
//
|
|
Error = ERROR_MORE_DATA;
|
|
break;
|
|
}
|
|
}
|
|
cleanup:
|
|
Call( JetCommitTransaction( pSession->SesId, 0));
|
|
LeaveCriticalSection( &RG_ProtectDatabase);
|
|
if ( InfoError == TRUE) {
|
|
ConfigGetInfoCleanup( ConfigEnum->Level, Buffer);
|
|
}
|
|
if ( Error == NO_ERROR) {
|
|
*TotalEntries = EntriesRead;
|
|
} else if ( Error == ERROR_MORE_DATA) {
|
|
*TotalEntries = EntriesRead * 2; // we cheat here
|
|
} else {
|
|
//
|
|
// Cleanup in case of "bad" errors.
|
|
//
|
|
while ( EntriesRead > 0) {
|
|
EntriesRead--;
|
|
Buffer -= CoreSize;
|
|
ConfigGetInfoCleanup( ConfigEnum->Level, Buffer);
|
|
}
|
|
MIDL_user_free( Buffer);
|
|
}
|
|
|
|
RplDump( RG_DebugLevel & RPL_DEBUG_CONFIG, ("ConfigEnum: EntriesRead = 0x%x", EntriesRead));
|
|
|
|
ConfigEnum->ConfigInfo.Level0->EntriesRead = EntriesRead;
|
|
if ( EntriesRead == 0) {
|
|
ConfigEnum->ConfigInfo.Level0->Buffer = NULL;
|
|
}
|
|
|
|
if ( ARGUMENT_PRESENT( pResumeHandle)) {
|
|
if ( Error == ERROR_MORE_DATA && EntriesRead > 0) {
|
|
EnterCriticalSection( &RG_ProtectDatabase);
|
|
Call( JetBeginTransaction( pSession->SesId));
|
|
RplFilterSave( pSession, (DWORD)ServerHandle, pFilter,
|
|
((LPRPL_CONFIG_INFO_0)(Buffer-CoreSize))->ConfigName,
|
|
pResumeHandle);
|
|
Call( JetCommitTransaction( pSession->SesId, JET_bitCommitFlush));
|
|
LeaveCriticalSection( &RG_ProtectDatabase);
|
|
} else {
|
|
*pResumeHandle = 0; // resume from beginning
|
|
}
|
|
}
|
|
return( Error);
|
|
}
|