/*++ Copyright (c) 1987-1993 Microsoft Corporation Module Name: config.c Abstract: Creates config table. Parses old style RPLMGR.INI config records and creates corresponding entries in jet database table. Author: Vladimir Z. Vulovic (vladimv) 19 - November - 1993 Revision History: --*/ #include "local.h" #define RPLCONFIG_ALLOCATE #include "config.h" #undef RPLCONFIG_ALLOCATE PWCHAR RplmgrIniFile = L"rplmgr.ini"; #define MAX_RPLMGR_INI_FILE_SIZE 0xFFFF // BUGBUG some arbitrary value #define NO_SCRIPT_FIELDS 13 #define SECTION_STARTMARK L'[' #define CONFIG_BEGIN L"[configuration]" #define CARRIAGE_RETURN_CHAR L'\r' // 0xD or \015 // #define RPL_DEBUG_ALL BOOL GetConfigFieldValue( IN PWCHAR Cursor, IN DWORD Index ) /*++ Fields with multiple field values, such as AdapterName, are not properly parsed here. Howerever, we do not care about the values of these fields. --*/ { PWCHAR End; DWORD Length; // // By default the field is empty. // ConfigParseTable[ Index].Value = NULL; ConfigParseTable[ Index].Size = 0; // // Read to EQUALS_CHAR // while ( *Cursor != EQUALS_CHAR && *Cursor != COMMENT_CHAR && *Cursor != CARRIAGE_RETURN_CHAR) { Cursor++; } if ( *Cursor == COMMENT_CHAR || *Cursor == CARRIAGE_RETURN_CHAR) { return( TRUE); } Cursor++; // Skip EQUALS_CHAR // // Read to the beginning of field value. // while( *Cursor != CARRIAGE_RETURN_CHAR && iswspace(*Cursor) && *Cursor != COMMENT_CHAR) { Cursor++; } if ( *Cursor == COMMENT_CHAR || *Cursor == CARRIAGE_RETURN_CHAR) { return( TRUE); } // // Make sure that boot block reference is enabled. // if ( Index == CONFIG_BootName) { if ( *Cursor != L'R') { RplAssert( TRUE, ("Bad boot block id: %.40ws", Cursor)); return( FALSE); } Cursor++; // skip leading 'R' in boot block name } // // Find the end point of this field. Since comments may contain spaces, // space is not used as a separator for CONFIG_ConfigComment field. // End = wcspbrk( Cursor, Index == CONFIG_ConfigComment ? L"\f\n\r\t\v" : L" \f\n\r\t\v"); if ( End != NULL) { Length = End - Cursor; } else { Length = wcslen( Cursor); } ConfigParseTable[ Index].Value = GlobalAlloc( GMEM_FIXED, (Length+1)*sizeof(WCHAR)); if ( ConfigParseTable[ Index].Value == NULL) { DWORD Error = GetLastError(); RplAssert( TRUE, ("GlobalAlloc: Error = %d", Error)); return( FALSE); } ConfigParseTable[ Index].Size = (Length+1)*sizeof(WCHAR); memcpy( ConfigParseTable[ Index].Value, Cursor, Length * sizeof(WCHAR)); ((PWCHAR)ConfigParseTable[ Index].Value)[ Length] = 0; return( TRUE); } BOOL StringISpaceEqual( IN PWCHAR str1, IN PWCHAR str2 ) /*++ Routine Description: Case insensitive version of StringsSpaceEqual. Arguments: str1 - first string str2 - second string Return Value: TRUE if strings are equal, FALSE otherwise. --*/ { WCHAR ch1; #ifdef NOT_YET if ( str1 == NULL || str2 == NULL) { str1 = (str1 != NULL) ? str1 : str2; if ( str2 == NULL) { return( TRUE); // both strings are NULL } while ( iswspace( *str1++)) { NOTHING; // check if not NULL string contains spaces only } return( *str1 == 0); } #endif // NOT_YET // // Compare strings until the first space or NULL character // (in the first string) or until we find the first different character. // while ( (ch1 = toupper(*str1)) && !iswspace(ch1) && ch1 == toupper(*str2)) { str1++, str2++; } // // For strings to be equal, both characters must be NULL or space. // if ( (!ch1 || iswspace(ch1)) && (!(ch1 = *str2) || iswspace(ch1))) { return( TRUE); } return( FALSE); } #ifdef RPL_DEBUG_ALL VOID ProcessConfigDisplay( VOID) { DWORD Index; printf( "\tCONFIGURATION\n"); for ( Index = 0; Index < CONFIG_TABLE_LENGTH; Index++) { if ( ConfigParseTable[ Index].Name == NULL) { continue; } printf( "%ws %ws 0x%x\n", ConfigParseTable[ Index].Name, ConfigParseTable[ Index].Value, ConfigParseTable[ Index].Size); } } #endif PWCHAR ProcessConfig( IN PWCHAR Cursor) /*++ Routine Description: We read all the fields in the Config[] array, then use jet apis to store this config in the database. Arguments: Cursor - at entry this points to the beginning of the config section Return Value: Cursor value after we finished processing the current config section. --*/ { #define INVALID_ERROR_PARAMETER ((DWORD)(-1)) DWORD Index; JET_ERR JetError; DWORD Flags; DWORD Offset; DWORD ErrorParameter; for ( Index = 0; Index < CONFIG_TABLE_LENGTH; Index++) { if ( ConfigParseTable[ Index].Value != NULL) { GlobalFree( ConfigParseTable[ Index].Value); } ConfigParseTable[ Index].Value = NULL; } if ( OffsetAfterComment( Cursor) == 0) { Flags = CONFIG_FLAGS_ENABLED_TRUE; } else { Flags = CONFIG_FLAGS_ENABLED_FALSE; } for ( Cursor=GetNextLine(Cursor), ErrorParameter = INVALID_ERROR_PARAMETER; *Cursor!=0; Cursor=GetNextLine(Cursor)) { Offset = OffsetAfterComment( Cursor); if ( *(Cursor+Offset) == SECTION_STARTMARK) { break; // start of a new section, write the current section } Cursor += Offset; // // Find value for this name. // for ( Index = 0; Index < CONFIG_TABLE_LENGTH; Index++) { if ( ConfigParseTable[ Index].Name == NULL) { continue; // skip this one, not a RPLMGR.INI keyword } if ( !StringISpaceEqual( Cursor, ConfigParseTable[ Index].Name)) { continue; // no match with this keyword } if ( !GetConfigFieldValue( Cursor, Index)) { if ( ErrorParameter == INVALID_ERROR_PARAMETER) { ErrorParameter = Index; } } else if ( Index == CONFIG_FitShared || Index == CONFIG_FitPersonal) { PWCHAR Value; Value = AddFileExtension( ConfigParseTable[ Index].Value, L".FIT", TRUE); if ( Value == NULL) { if ( ErrorParameter == INVALID_ERROR_PARAMETER) { ErrorParameter = Index; } } else if ( Value != ConfigParseTable[ Index].Value) { GlobalFree( ConfigParseTable[ Index].Value); ConfigParseTable[ Index].Value = Value; ConfigParseTable[ Index].Size = (wcslen(Value)+1)*sizeof(WCHAR); } } break; } } #ifdef RPL_DEBUG_ALL ProcessConfigDisplay(); #endif if ( ConfigParseTable[ CONFIG_ConfigName].Value == NULL) { RplAssert( TRUE, ("Bad config")); return( Cursor); } // // Perform same checks as in NetrRplConfigAdd. // if ( ErrorParameter != INVALID_ERROR_PARAMETER) { NOTHING; // do not overwrite the first error } else if ( !ValidName( ConfigParseTable[ CONFIG_FitPersonal].Value, RPL_MAX_STRING_LENGTH, TRUE)) { ErrorParameter = CONFIG_FitPersonal; } else if ( !ValidName( ConfigParseTable[ CONFIG_FitShared].Value, RPL_MAX_STRING_LENGTH, TRUE)) { ErrorParameter = CONFIG_FitShared; } else if ( !ValidName( ConfigParseTable[ CONFIG_DirName4].Value, RPL_MAX_STRING_LENGTH, FALSE)) { ErrorParameter = CONFIG_DirName4; } else if ( !ValidName( ConfigParseTable[ CONFIG_DirName3].Value, RPL_MAX_STRING_LENGTH, FALSE)) { ErrorParameter = CONFIG_DirName3; } else if ( !ValidName( ConfigParseTable[ CONFIG_DirName2].Value, RPL_MAX_STRING_LENGTH, TRUE)) { ErrorParameter = CONFIG_DirName2; } else if ( !ValidName( ConfigParseTable[ CONFIG_DirName].Value, RPL_MAX_STRING_LENGTH, TRUE)) { ErrorParameter = CONFIG_DirName; } else if ( !ValidName( ConfigParseTable[ CONFIG_BootName].Value, RPL_MAX_BOOT_NAME_LENGTH, TRUE)) { ErrorParameter = CONFIG_BootName; } else if ( !ValidName( ConfigParseTable[ CONFIG_ConfigName].Value, RPL_MAX_CONFIG_NAME_LENGTH, TRUE)) { ErrorParameter = CONFIG_ConfigName; } if ( ErrorParameter < CONFIG_TABLE_LENGTH) { RplPrintf2( RPLI_CVT_ConfigInvalid, ConfigParseTable[ CONFIG_ConfigName].Value, ConfigParseTable[ ErrorParameter].Name); return( Cursor); } if ( ConfigParseTable[ CONFIG_FitPersonal].Value == NULL) { // // Ignore default boot configurations. // RplPrintf1( RPLI_CVT_ConfigNoPersonalFIT, ConfigParseTable[ CONFIG_ConfigName].Value); return( Cursor); } if ( !_wcsicmp( L"OS2", ConfigParseTable[ CONFIG_DirName].Value )) { // // Ignore OS/2 configurations. // RplPrintf1( RPLI_CVT_ConfigNoOS2, ConfigParseTable[ CONFIG_ConfigName].Value); return( Cursor); } if ( RPL_STRING_TOO_LONG( ConfigParseTable[ CONFIG_ConfigComment].Value)) { // // Silently truncate comments that are too long. // ((PWCHAR)ConfigParseTable[ CONFIG_ConfigComment].Value)[ RPL_MAX_STRING_LENGTH] = 0; ConfigParseTable[ CONFIG_ConfigComment].Size = (RPL_MAX_STRING_LENGTH+1)*sizeof(WCHAR); } _wcsupr( (PWCHAR)ConfigParseTable[ CONFIG_BootName].Value); _wcsupr( (PWCHAR)ConfigParseTable[ CONFIG_ConfigName].Value); Call( JetPrepareUpdate( SesId, ConfigTableId, JET_prepInsert)); for ( Index = 0; Index < CONFIG_TABLE_LENGTH; Index++ ) { if ( ConfigParseTable[ Index].Name == NULL) { continue; } JetError = JetSetColumn( SesId, ConfigTableId, ConfigTable[ Index].ColumnId, ConfigParseTable[ Index].Value, ConfigParseTable[ Index].Size, 0, NULL); if ( JetError != JET_errSuccess) { RplAssert( TRUE, ("Index=%d(dec) JetError=%d", Index, JetError)); } } Call( JetSetColumn( SesId, ConfigTableId, ConfigTable[ CONFIG_Flags].ColumnId, &Flags, sizeof(Flags), 0, NULL)); Call( JetUpdate( SesId, ConfigTableId, NULL, 0, NULL)); return( Cursor); } DWORD ProcessRplmgrIni( IN LPWSTR FilePath) { PWCHAR Cursor; PWCHAR String; JET_COLUMNDEF ColumnDef; JET_ERR JetError; DWORD Index; DWORD Offset; CHAR IndexKey[ 255]; JetError = JetCreateTable( SesId, DbId, "config", CONFIG_TABLE_PAGE_COUNT, CONFIG_TABLE_DENSITY, &ConfigTableId); ColumnDef.cbStruct = sizeof( ColumnDef); ColumnDef.columnid = 0; ColumnDef.coltyp = JET_coltypLong; ColumnDef.cbMax = 0; ColumnDef.grbit = 0; // // Create columns. First initialize fields that do not change between // addition of columns. // ColumnDef.cbStruct = sizeof(ColumnDef); ColumnDef.columnid = 0; ColumnDef.wCountry = 1; ColumnDef.langid = 0x0409; // USA english ColumnDef.cp = 1200; // UNICODE codepage ColumnDef.wCollate = 0; ColumnDef.cbMax = 0; ColumnDef.grbit = 0; // variable length binary and text data. for ( Index = 0; Index < CONFIG_TABLE_LENGTH; Index++ ) { ColumnDef.coltyp = ConfigTable[ Index].ColumnType; JetError = JetAddColumn( SesId, ConfigTableId, ConfigTable[ Index].ColumnName, &ColumnDef, NULL, 0, &ConfigTable[ Index].ColumnId); if( JetError != ERROR_SUCCESS ) { return( MapJetError( JetError)); } } Offset = AddKey( IndexKey, '+', ConfigTable[ CONFIG_ConfigName].ColumnName); IndexKey[ Offset++] = '\0'; JetError = JetCreateIndex( SesId, ConfigTableId, CONFIG_INDEX_ConfigName, JET_bitIndexPrimary, IndexKey, Offset, 50); if ( JetError != JET_errSuccess) { RplAssert( TRUE, ("CreateIndex failed err=%d", JetError)); return( MapJetError( JetError)); } // // +BootName+ConfigName index is used to enumerate all configurations for // a given VendorId. // Offset = AddKey( IndexKey, '+', ConfigTable[ CONFIG_BootName].ColumnName); Offset += AddKey( IndexKey + Offset, '+', ConfigTable[ CONFIG_ConfigName].ColumnName); IndexKey[ Offset++] = '\0'; JetError = JetCreateIndex( SesId, ConfigTableId, CONFIG_INDEX_BootNameConfigName, JET_bitIndexUnique, IndexKey, Offset, 50); if ( JetError != JET_errSuccess) { RplAssert( TRUE, ("CreateIndex failed err=%d", JetError)); return( MapJetError( JetError)); } // // Make config name a current index - used to validate profiles. // JetError = JetSetCurrentIndex( SesId, ConfigTableId, CONFIG_INDEX_ConfigName); if ( JetError != JET_errSuccess) { RplAssert( TRUE, ("SetCurrentIndex failed err=%d", JetError)); return( MapJetError( JetError)); } String = ReadTextFile( FilePath, RplmgrIniFile, MAX_RPLMGR_INI_FILE_SIZE); if ( String == NULL) { return( GetLastError()); } // // If current line is the beginning of configuration, we process // that configuration (note that this processing has the side effect of // advancing the cursor), else we just advance the cursor. // for ( Cursor = GetFirstLine( String); *Cursor != 0; NOTHING) { Offset = OffsetAfterComment( Cursor); if ( StringISpaceEqual( Cursor+Offset, CONFIG_BEGIN)) { Cursor = ProcessConfig( Cursor); } else { Cursor = GetNextLine( Cursor); } } if ( GlobalFree( String) != NULL) { RplAssert( TRUE, ("GlobalFree: Error=%d", GetLastError())); } return( ERROR_SUCCESS); } VOID ConfigPruneTable( VOID) /*++ Eliminate config records that do not have a corresponding boot block record defined. --*/ { WCHAR Name[ 20]; DWORD NameSize; JET_ERR ForJetError; JET_ERR JetError; for ( ForJetError = JetMove( SesId, ConfigTableId, JET_MoveFirst, 0); ForJetError == JET_errSuccess; ForJetError = JetMove( SesId, ConfigTableId, JET_MoveNext, 0)) { JetError = JetRetrieveColumn( SesId, ConfigTableId, ConfigTable[ CONFIG_BootName].ColumnId, Name, sizeof( Name), &NameSize, 0, NULL); if ( JetError != JET_errSuccess) { RplAssert( TRUE, ("RetriveColumn failed err=%d", JetError)); Call( JetDelete( SesId, ConfigTableId)); continue; } if ( !FindBoot( Name)) { #ifdef RPL_DEBUG_ALL WCHAR Value[ 20]; JetRetrieveColumn( SesId, ConfigTableId, ConfigTable[ CONFIG_ConfigName].ColumnId, Value, sizeof( Value), &NameSize, 0, NULL); printf("Deleting config %ws since boot %ws was not found\n", Value, Name); #endif Call( JetDelete( SesId, ConfigTableId)); continue; } } } BOOL FindConfig( IN PWCHAR Name) { JET_ERR JetError; JetError = JetMove( SesId, ConfigTableId, JET_MoveFirst, 0); if ( JetError != JET_errSuccess) { RplAssert( TRUE, ("JetMove failed err=%d", JetError)); return( FALSE); } JetError = JetMakeKey( SesId, ConfigTableId, Name, ( wcslen( Name) + 1) * sizeof(WCHAR), JET_bitNewKey); if ( JetError != JET_errSuccess) { RplAssert( TRUE, ("MakeKey failed err=%d", JetError)); return( FALSE); } JetError = JetSeek( SesId, ConfigTableId, JET_bitSeekEQ); if ( JetError != JET_errSuccess) { RplAssert( TRUE, ("JetSeek for %ws failed err=%d", Name, JetError)); return( FALSE); } return( TRUE); } VOID ConfigListTable( VOID) { ListTable( CONFIG_TABLE_NAME, ConfigTable[ CONFIG_ConfigName].ColumnName, CONFIG_INDEX_ConfigName); }