summaryrefslogtreecommitdiffstats
path: root/private/net/svcdlls/rpl/server/config.c
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/net/svcdlls/rpl/server/config.c
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/net/svcdlls/rpl/server/config.c')
-rw-r--r--private/net/svcdlls/rpl/server/config.c711
1 files changed, 711 insertions, 0 deletions
diff --git a/private/net/svcdlls/rpl/server/config.c b/private/net/svcdlls/rpl/server/config.c
new file mode 100644
index 000000000..698cb962e
--- /dev/null
+++ b/private/net/svcdlls/rpl/server/config.c
@@ -0,0 +1,711 @@
+/*++
+
+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);
+}