/*++ Copyright (c) 1993 Microsoft Corporation Module Name: database.c Abstract: Routines for non-api _access to the database. This includes initialization and shutdown code on the database. Exports: BOOL RplDbInit( VOID) VOID RplDbTerm( VOID) BOOL RplDbFindWksta( BOOL RplDbFillWksta( BOOL RplDbHaveWksta( Author: Vladimir Z. Vulovic (vladimv) 19 - November - 1993 Environment: User mode Revision History : --*/ #include "local.h" #include "rpldb.h" #include "database.h" #include "db.h" #include "dblib.h" #include "adapter.h" #include "boot.h" #include "config.h" #include "profile.h" #include "resume.h" #include "vendor.h" #include "wksta.h" #include "report.h" // for RplReportEventEx #include "winsock.h" // for INADDR_NONE DWORD RplStartJet500Conversion(); #define RPL_BACKUP_SUBDIR L"BACKUP" // // File names must be complete, i.e. extensions are not optional. (This is unlike // the OS/2 behavior where we would append ".FIT" if extension is absent). // BOOL RplDbInitColumnInfo( IN PCHAR TableName, IN OUT PRPL_COLUMN_INFO ColumnInfoTable, IN DWORD ColumnInfoTableLength, IN JET_TABLEID TableId, IN JET_SESID SesId ) { JET_COLUMNDEF ColumnDef; DWORD index; for ( index = 0; index < ColumnInfoTableLength; index++) { CallB( JetGetTableColumnInfo( SesId, TableId, ColumnInfoTable[ index].ColumnName, &ColumnDef, sizeof( ColumnDef), JET_ColInfo)); RPL_ASSERT( ColumnInfoTable[ index].ColumnType == ColumnDef.coltyp); ColumnInfoTable[ index].ColumnId = ColumnDef.columnid; } return( TRUE); } // // Code templated from WINS:WinMscDelFiles(). JonN 8/7/94 // VOID RplDeleteLogFiles() { WCHAR Path[ MAX_PATH]; // must hold terminating NULL char too WIN32_FIND_DATA FileInfo; HANDLE SearchHandle = INVALID_HANDLE_VALUE; DWORD ErrCode = NO_ERROR; memcpy( Path, RG_Directory, RG_DirectoryLength * sizeof(WCHAR)); memcpy( Path+RG_DirectoryLength, L"jet*.log", 9*sizeof(WCHAR)); SearchHandle = FindFirstFile(Path, &FileInfo); if (SearchHandle == INVALID_HANDLE_VALUE) { RplDump( RG_DebugLevel & RPL_DEBUG_REQUEST, ( "RplDeleteLogFiles: FindFirstFile( %ws) returned %d", Path, GetLastError())); goto cleanup; } do { memcpy( Path + RG_DirectoryLength, FileInfo.cFileName, (wcslen(FileInfo.cFileName)+1) * sizeof(WCHAR) ); if (!DeleteFile(Path)) { RplDump( RG_DebugLevel & RPL_DEBUG_REQUEST, ( "RplDeleteLogFiles: DeleteFile( %ws) returned %d", Path, GetLastError())); goto cleanup; } } while(FindNextFile(SearchHandle, &FileInfo)); if ((ErrCode = GetLastError()) != ERROR_NO_MORE_FILES) { RplDump( RG_DebugLevel & RPL_DEBUG_REQUEST, ( "RplDeleteLogFiles: FindNextFile() returned %d", ErrCode)); } cleanup: if ( SearchHandle != INVALID_HANDLE_VALUE && !FindClose(SearchHandle)) { RplDump( RG_DebugLevel & RPL_DEBUG_REQUEST, ( "RplDeleteLogFiles: FindClose() returned %d", GetLastError())); } return; } BOOL RplDbInitPath( IN OUT PWCHAR Path, IN PWCHAR Name, OUT PCHAR * pDbcsPath ) /*++ Routine Description: Allocates DBCS string corresponding to a UNICODE string obtained via concatenation of Path & Name strings. Arguments: Path - first UNICODE string Name - second UNICODE string pDbcsPath - pointer to a DBCS string corresponding to a concatenation of above two UNICODE strings Return Value: TRUE if success, FALSE otherwise. --*/ { DWORD NameLength; DWORD PathLength; // not count terminating NULL char NameLength = wcslen( Name); PathLength = RG_DirectoryLength + NameLength; if ( PathLength >= MAX_PATH) { RPL_RETURN( FALSE); } memcpy( Path + RG_DirectoryLength, Name, (NameLength+1)*sizeof(WCHAR)); NameLength = RplUnicodeToDbcs( RG_MemoryHandle, Path, PathLength, MAX_PATH * sizeof(WCHAR), pDbcsPath); if ( NameLength == 0) { RPL_RETURN( FALSE); } return( TRUE); } BOOL RplDbSessionInit( IN BOOL MainSession, OUT PRPL_SESSION pSession, OUT BOOL * pErrorReported ) { CallB( JetBeginSession( RG_Instance, &pSession->SesId, "admin", "")); if ( MainSession) { JET_ERR err = JetAttachDatabase( pSession->SesId, RG_Mdb, 0); if ( err == JET_errSuccess ) { // // JonN 6/16/95 This code works around a JET bug in cases // where the JET database has moved. The code fragment was // suggested by Ian Jose. JetAttachDatabase will return // JET_wrnDatabaseAttached under normal circumstances. // RplDump( RG_DebugLevel & RPL_DEBUG_REQUEST, ( "RplDbSessionInit: JetAttachDatabase returned JET_errSuccess, engaging workaround" )); // Detach(NULL) detached all databases, new to NT 3.51 and up Call( JetDetachDatabase( pSession->SesId, NULL)); // // It is OK if this call returns JET_errSuccess since // we explicitly detached. Note that we do not normally // detach at all. // CallB( JetAttachDatabase( pSession->SesId, RG_Mdb, 0)); } else if ( err == JET_errDatabase200Format ) { // // JetInit will succeed if no 200-series logs exist, and the // problem will not be caught until here. // DWORD converr; converr = RplStartJet500Conversion(); RplReportEvent( NELOG_RplUpgradeDBTo40, NULL, sizeof(DWORD), &converr); *pErrorReported = TRUE; return( FALSE); } else { CallB( err ); } RG_DetachDatabase = TRUE; } CallB( JetOpenDatabase( pSession->SesId, RG_Mdb, NULL, &pSession->DbId, 0)); CallB( JetOpenTable( pSession->SesId, pSession->DbId, ADAPTER_TABLE_NAME, NULL, 0, 0, &pSession->AdapterTableId)); CallB( JetOpenTable( pSession->SesId, pSession->DbId, BOOT_TABLE_NAME, NULL, 0, 0, &pSession->BootTableId)); CallB( JetOpenTable( pSession->SesId, pSession->DbId, CONFIG_TABLE_NAME, NULL, 0, 0, &pSession->ConfigTableId)); CallB( JetOpenTable( pSession->SesId, pSession->DbId, PROFILE_TABLE_NAME, NULL, 0, 0, &pSession->ProfileTableId)); if ( MainSession) { DWORD Error; Error = ResumeCreateTable( pSession); // initializes ResumeTable also if ( Error != NO_ERROR) { RplDump( ++RG_Assert,( "Error=%d", Error)); return( FALSE); } } CallB( JetOpenTable( pSession->SesId, pSession->DbId, RESUME_TABLE_NAME, NULL, 0, 0, &pSession->ResumeTableId)); CallB( JetOpenTable( pSession->SesId, pSession->DbId, VENDOR_TABLE_NAME, NULL, 0, 0, &pSession->VendorTableId)); CallB( JetOpenTable( pSession->SesId, pSession->DbId, WKSTA_TABLE_NAME, NULL, 0, 0, &pSession->WkstaTableId)); if ( MainSession) { if ( !RplDbInitColumnInfo( ADAPTER_TABLE_NAME, AdapterTable, ADAPTER_TABLE_LENGTH, pSession->AdapterTableId, pSession->SesId)) { return( FALSE); } if ( !RplDbInitColumnInfo( BOOT_TABLE_NAME, BootTable, BOOT_TABLE_LENGTH, pSession->BootTableId, pSession->SesId)) { return( FALSE); } if ( !RplDbInitColumnInfo( CONFIG_TABLE_NAME, ConfigTable, CONFIG_TABLE_LENGTH, pSession->ConfigTableId, pSession->SesId)) { return( FALSE); } if ( !RplDbInitColumnInfo( PROFILE_TABLE_NAME, ProfileTable, PROFILE_TABLE_LENGTH, pSession->ProfileTableId, pSession->SesId)) { return( FALSE); } // // ColumnInfo for resume table has been initialized already. // if ( !RplDbInitColumnInfo( VENDOR_TABLE_NAME, VendorTable, VENDOR_TABLE_LENGTH, pSession->VendorTableId, pSession->SesId)) { return( FALSE); } if ( !RplDbInitColumnInfo( WKSTA_TABLE_NAME, WkstaTable, WKSTA_TABLE_LENGTH, pSession->WkstaTableId, pSession->SesId)) { return( FALSE); } } return( TRUE); } VOID RplDbSessionTerm( IN BOOL MainSession, IN PRPL_SESSION pSession ) { if ( pSession->AdapterTableId != 0) { Call( JetCloseTable( pSession->SesId, pSession->AdapterTableId)); } if ( pSession->BootTableId != 0) { Call( JetCloseTable( pSession->SesId, pSession->BootTableId)); } if ( pSession->ConfigTableId != 0) { Call( JetCloseTable( pSession->SesId, pSession->ConfigTableId)); } if ( pSession->ProfileTableId != 0) { Call( JetCloseTable( pSession->SesId, pSession->ProfileTableId)); } if ( pSession->ResumeTableId != 0) { Call( JetCloseTable( pSession->SesId, pSession->ResumeTableId)); if ( MainSession) { Call( JetDeleteTable( pSession->SesId, pSession->DbId, RESUME_TABLE_NAME)); } } if ( pSession->VendorTableId != 0) { Call( JetCloseTable( pSession->SesId, pSession->VendorTableId)); } if ( pSession->WkstaTableId != 0) { Call( JetCloseTable( pSession->SesId, pSession->WkstaTableId)); } if ( pSession->DbId != 0) { Call( JetCloseDatabase( pSession->SesId, pSession->DbId, 0)); } if ( pSession->SesId != 0) { if ( MainSession && RG_DetachDatabase) { #if 0 // // Because of JET restore bugs we are advised NOT TO // detach database ever. // Call( JetDetachDatabase( pSession->SesId, RG_Mdb)); #endif RG_DetachDatabase = FALSE; } Call( JetEndSession( pSession->SesId, 0)); } } BOOL RplDbFindBoot( IN PRPL_SESSION pSession, IN PWCHAR BootName, IN PWCHAR AdapterName ) /*++ Return TRUE if it finds server record for input BootName & AdapterName. Returns FALSE otherwise. Same comment as for RplDbFindWksta. --*/ { JET_ERR JetError; DWORD Vendor; WCHAR SaveChar; JetError = JetSetCurrentIndex( pSession->SesId, pSession->BootTableId, BOOT_INDEX_VendorIdBootName); if ( JetError != JET_errSuccess) { RplDump( ++RG_Assert, ("SetCurrentIndex failed err=%d", JetError)); return( FALSE); } SaveChar = AdapterName[ RPL_VENDOR_NAME_LENGTH]; AdapterName[ RPL_VENDOR_NAME_LENGTH] = 0; Vendor = wcstoul( AdapterName, NULL, 16); AdapterName[ RPL_VENDOR_NAME_LENGTH] = SaveChar; JetError = JetMakeKey( pSession->SesId, pSession->BootTableId, &Vendor, sizeof( Vendor), JET_bitNewKey); if ( JetError != JET_errSuccess) { RplDump( ++RG_Assert, ("MakeKey failed err=%d", JetError)); return( FALSE); } JetError = JetMakeKey( pSession->SesId, pSession->BootTableId, BootName, ( wcslen( BootName) + 1) * sizeof(WCHAR), 0); if ( JetError != JET_errSuccess) { RplDump( ++RG_Assert, ("MakeKey failed err=%d", JetError)); return( FALSE); } JetError = JetSeek( pSession->SesId, pSession->BootTableId, JET_bitSeekEQ); if ( JetError != JET_errSuccess) { if ( JetError == JET_errRecordNotFound) { // // This is an expected error, do not break for this. // RplDump( RG_DebugLevel & RPL_DEBUG_REQUEST, ( "DbFindWksta( %ws) failed", AdapterName)); } else { RplDump( ++RG_Assert, ("JetSeek failed err=%d", JetError)); } return( FALSE); } return( TRUE); } BOOL RplDbAddAdapterName( IN PRPL_SESSION pSession, IN LPWSTR AdapterName ) /*++ Try to add the adapter record for input AdapterName. CODEWORK Should use different comments for different VendorName-s. Return Value: TRUE if adapter record for input AdapterName was added FALSE otherwise --*/ { #define ADAPTER_GENERIC_COMMENT L"An unknown client network adapter id." JET_ERR JetError; DWORD Flags = 0; BYTE LocalBuffer[ 300]; DWORD DataSize; PWCHAR AdapterComment; WCHAR VendorName[ RPL_VENDOR_NAME_LENGTH + 1]; if ( RplFind( pSession, ADAPTER_TABLE_TAG, AdapterName)) { return( FALSE); // adapter record is already present } memcpy( VendorName, AdapterName, RPL_VENDOR_NAME_LENGTH*sizeof(WCHAR)); VendorName[ RPL_VENDOR_NAME_LENGTH] = 0; if ( RplFind( pSession, VENDOR_TABLE_TAG, VendorName)) { CallB( JetRetrieveColumn( pSession->SesId, pSession->VendorTableId, VendorTable[ VENDOR_VendorComment].ColumnId, LocalBuffer, sizeof( LocalBuffer), &DataSize, 0, NULL)); if ( DataSize > sizeof( LocalBuffer)) { AdapterComment = ADAPTER_GENERIC_COMMENT; } else { AdapterComment = (PWCHAR)LocalBuffer; } } else { AdapterComment = ADAPTER_GENERIC_COMMENT; } CallB( JetPrepareUpdate( pSession->SesId, pSession->AdapterTableId, JET_prepInsert)); CallB( JetSetColumn( pSession->SesId, pSession->AdapterTableId, AdapterTable[ ADAPTER_AdapterName].ColumnId, AdapterName, ( wcslen( AdapterName) + 1) * sizeof(WCHAR), 0, NULL)); CallB( JetSetColumn( pSession->SesId, pSession->AdapterTableId, AdapterTable[ ADAPTER_AdapterComment].ColumnId, AdapterComment, ( wcslen( AdapterComment) + 1) * sizeof(WCHAR), 0, NULL)); CallB( JetSetColumn( pSession->SesId, pSession->AdapterTableId, AdapterTable[ ADAPTER_Flags].ColumnId, &Flags, sizeof(Flags), 0, NULL)); JetError = JetUpdate( pSession->SesId, pSession->AdapterTableId, NULL, 0, NULL); if ( JetError < 0) { if ( JetError != JET_errKeyDuplicate) { RplDump( ++RG_Assert, ( "JetError=%d", JetError)); } return( FALSE); } return( TRUE); } VOID RplDbInstanceTerm( VOID) { if ( !RG_InstanceAllocated) { return; } RplDbSessionTerm( FALSE, &RG_ApiSession); RplDbSessionTerm( FALSE, &RG_WorkerSession); RplDbSessionTerm( TRUE, &RG_RequestSession); Call( JetTerm2( RG_Instance, JET_bitTermComplete)); RG_InstanceAllocated = FALSE; } BOOL RplDbInstanceInit( PCHAR SystemMdb, PCHAR TempMdb, PCHAR LogFilePath, BOOL * pErrorReported ) { RG_InstanceAllocated = FALSE; RG_DetachDatabase = FALSE; memset( &RG_RequestSession, 0, sizeof( RG_RequestSession)); memset( &RG_WorkerSession, 0, sizeof( RG_WorkerSession)); memset( &RG_ApiSession, 0, sizeof( RG_ApiSession)); #ifdef __JET500 CallB( JetSetSystemParameter( &RG_Instance, 0, JET_paramSystemPath, 0, LogFilePath)); #else CallB( JetSetSystemParameter( &RG_Instance, 0, JET_paramSysDbPath, 0, SystemMdb)); #endif RG_InstanceAllocated = TRUE; CallB( JetSetSystemParameter( &RG_Instance, 0, JET_paramTempPath, 0, TempMdb)); CallB( JetSetSystemParameter( &RG_Instance, 0, JET_paramLogFilePath, 0, LogFilePath)); CallB( JetSetSystemParameter( &RG_Instance, 0, JET_paramMaxBuffers, 250, NULL)); CallB( JetSetSystemParameter( &RG_Instance, 0, JET_paramBfThrshldLowPrcnt, 0, NULL)); CallB( JetSetSystemParameter( &RG_Instance, 0, JET_paramBfThrshldHighPrcnt, 100, NULL)); CallB( JetSetSystemParameter( &RG_Instance, 0, JET_paramMaxOpenTables, 30, NULL)); CallB( JetSetSystemParameter( &RG_Instance, 0, JET_paramMaxOpenTableIndexes, 105, NULL)); CallB( JetSetSystemParameter( &RG_Instance, 0, JET_paramMaxCursors, 100, NULL)); CallB( JetSetSystemParameter( &RG_Instance, 0, JET_paramMaxSessions, 10, NULL)); CallB( JetSetSystemParameter( &RG_Instance, 0, JET_paramMaxVerPages, 64, NULL)); CallB( JetSetSystemParameter( &RG_Instance, 0, JET_paramMaxTemporaryTables, 5, NULL)); CallB( JetSetSystemParameter( &RG_Instance, 0, JET_paramLogBuffers, 41, NULL)); #ifdef __JET500 CallB( JetSetSystemParameter( &RG_Instance, 0, JET_paramLogFileSize, 1000, NULL)); #else CallB( JetSetSystemParameter( &RG_Instance, 0, JET_paramLogFileSectors, 1000, NULL)); #endif CallB( JetSetSystemParameter( &RG_Instance, 0, JET_paramLogFlushThreshold, 10, NULL)); #ifdef __JET500 CallB( JetSetSystemParameter( &RG_Instance, 0, JET_paramBaseName, 0, "j50")); { JET_ERR JetError = JetInit( &RG_Instance); // // JetInit will fail if 200-series logs exist. // if ( JetError == JET_errDatabase200Format ) { DWORD converr; converr = RplStartJet500Conversion(); RplReportEvent( NELOG_RplUpgradeDBTo40, NULL, sizeof(DWORD), &converr); *pErrorReported = TRUE; return( FALSE); } else { CallB( JetError ); } } #else CallB( JetSetSystemParameter( &RG_Instance, 0, JET_paramRecovery, 0, "on")); CallB( JetInit( &RG_Instance)); #endif if ( !RplDbSessionInit( TRUE, &RG_RequestSession, pErrorReported)) { return( FALSE); } if ( !RplDbSessionInit( FALSE, &RG_WorkerSession, pErrorReported)) { return( FALSE); } if ( !RplDbSessionInit( FALSE, &RG_ApiSession, pErrorReported)) { return( FALSE); } return( TRUE); } BOOL RplDbInit() { WCHAR Path[ MAX_PATH]; // must hold terminating NULL char too JET_ERR JetError; PCHAR SystemMdb = NULL; // needed for cleanup below PCHAR TempMdb = NULL; // needed for cleanup below PCHAR LogFilePath = NULL; // needed for cleanup below BOOL Success = FALSE; BOOL ErrorReported = FALSE; memcpy( Path, RG_Directory, RG_DirectoryLength * sizeof(WCHAR)); if ( !RplDbInitPath( Path, RPL_BACKUP_SUBDIR, &RG_BackupPath)) { goto cleanup; } if ( !RplDbInitPath( Path, RPL_SERVICE_DATABASE_W, &RG_Mdb)) { goto cleanup; } if ( !RplDbInitPath( Path, RPL_SYSTEM_DATABASE_W, &SystemMdb)) { goto cleanup; } if ( !RplDbInitPath( Path, RPL_TEMP_DATABASE_W, &TempMdb)) { goto cleanup; } if ( !RplDbInitPath( Path, L"", &LogFilePath)) { goto cleanup; } #if 1 if ( !RplDbInstanceInit( SystemMdb, TempMdb, LogFilePath, &ErrorReported)) { if (ErrorReported) { goto cleanup; } RplReportEvent( NELOG_RplInitDatabase, NULL, 0, NULL); RplDbInstanceTerm(); #else // // Used only for testing purposes (to restore without attempt to init first) // if ( TRUE) { #endif #ifdef __JET500 JetError = JetRestore( RG_BackupPath, 0); #else JetError = JetRestore( RG_BackupPath, 0, NULL, 0); #endif if ( JetError == JET_errBadLogVersion // // JonN 11/28/95 According to JLiem, the old BadNextLogVersion is broken up // into two errors and two warnings in JET500. If we get either of the // warnings (558 or 559) then JET took care of deleting the old log files // and we can continue. We handle the errors as we handled BadNextLogVersion. // #ifdef __JET500 || JetError == JET_errGivenLogFileHasBadSignature || JetError == JET_errGivenLogFileIsNotContiguous #else || JetError == JET_errBadNextLogVersion #endif ) { RplDeleteLogFiles(); #ifdef __JET500 JetError = JetRestore( RG_BackupPath, 0); #else JetError = JetRestore( RG_BackupPath, 0, NULL, 0); #endif } #ifdef __JET500 #ifndef JET_ATTACH_CATCHES_ERROR if ( JetError == JET_errDatabase200Format ) { RplReportEvent( NELOG_RplUpgradeDBTo40, NULL, sizeof(DWORD), &JetError); RplDump( ++RG_Assert,( "200-fmt from JetRestore" )); goto cleanup; } #endif #endif if ( JetError < 0) { RplDump( ++RG_Assert, ("JetRestore( %s) failed err=%d", RG_BackupPath, JetError)); RplReportEvent( NELOG_RplRestoreDatabaseFailure, NULL, sizeof(DWORD), &JetError); goto cleanup; } RplReportEvent( NELOG_RplRestoreDatabaseSuccess, NULL, 0, NULL); if ( !RplDbInstanceInit( SystemMdb, TempMdb, LogFilePath, &ErrorReported)) { if (ErrorReported) { goto cleanup; } RplReportEvent( NELOG_RplInitRestoredDatabase, NULL, 0, NULL); goto cleanup; } } Success = TRUE; cleanup: if ( SystemMdb != NULL) { RplMemFree( RG_MemoryHandle, SystemMdb); } if ( TempMdb != NULL) { RplMemFree( RG_MemoryHandle, TempMdb); } if ( LogFilePath != NULL) { RplMemFree( RG_MemoryHandle, LogFilePath); } return( Success); } VOID RplDbTerm( VOID) /*++ Save changes that may have been made to the database. Without this the database may be left in an unusable state where any subsequent attempt of calling JetInit() for this database would fail. --*/ { RplDbInstanceTerm(); RplMemFree( RG_MemoryHandle, RG_Mdb); RplMemFree( RG_MemoryHandle, RG_BackupPath); } BOOL RplDbFindWksta( IN PRPL_SESSION pSession, IN LPWSTR AdapterName ) /*++ Return TRUE if it finds wksta record for input AdapterName. Returns FALSE otherwise. This code could be make more efficient by defining AdapterName to be jet currency data (it is silly now taking wcslen of AdapterName since it is a fixed length string. It is ASSUMED that the caller of this function will ensure transaction processing. --*/ { JET_ERR JetError; JetError = JetSetCurrentIndex( pSession->SesId, pSession->WkstaTableId, WKSTA_INDEX_AdapterName); if ( JetError != JET_errSuccess) { RplDump( ++RG_Assert, ("SetCurrentIndex failed err=%d", JetError)); return( FALSE); } JetError = JetMakeKey( pSession->SesId, pSession->WkstaTableId, AdapterName, ( wcslen( AdapterName) + 1) * sizeof(WCHAR), JET_bitNewKey); if ( JetError != JET_errSuccess) { RplDump( ++RG_Assert, ("MakeKey failed err=%d", JetError)); return( FALSE); } JetError = JetSeek( pSession->SesId, pSession->WkstaTableId, JET_bitSeekEQ); if ( JetError != JET_errSuccess) { #ifdef RPL_DEBUG // // Do not assert for expected errors ( empty table or // failure to find a record). // if ( JetError == JET_errNoCurrentRecord || JetError == JET_errRecordNotFound) { RplDump( RG_DebugLevel & RPL_DEBUG_REQUEST, ( "DbFindWksta( %ws) failed", AdapterName)); } else { RplDump( ++RG_Assert, ("JetSeek failed err=%d", JetError)); } #endif return( FALSE); } return( TRUE); } BOOL RplDbFillWksta( IN PRPL_SESSION pSession, IN OUT PRPL_WORKER_DATA pWorkerData ) /*++ Returns TRUE if it can find all the information needed to boot the client. Returns FALSE otherwise. This routine should be modified to use ConfigGetInfo() - but without the penalty of memory allocations. --*/ { DWORD DataSize; PWCHAR AdapterName; WCHAR BootName[ RPL_MAX_BOOT_NAME_LENGTH + 1]; WCHAR FilePath[ MAX_PATH]; DWORD Length; DWORD Flags; AdapterName = pWorkerData->pRcb->AdapterName; if ( !RplDbFindWksta( pSession, AdapterName)) { RplDump( ++RG_Assert, ("FindWksta( %ws) failed", AdapterName)); pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; pWorkerData->EventId = NERR_RplWkstaNotFound; return( FALSE); } CallB( JetRetrieveColumn( pSession->SesId, pSession->WkstaTableId, WkstaTable[ WKSTA_WkstaName].ColumnId, pWorkerData->WkstaName, sizeof( pWorkerData->WkstaName), &DataSize, 0, NULL)); CallB( JetRetrieveColumn( pSession->SesId, pSession->WkstaTableId, WkstaTable[ WKSTA_ProfileName].ColumnId, pWorkerData->ProfileName, sizeof( pWorkerData->ProfileName), &DataSize, 0, NULL)); CallB( JetRetrieveColumn( pSession->SesId, pSession->WkstaTableId, WkstaTable[ WKSTA_FitFile].ColumnId, FilePath, sizeof( FilePath), &DataSize, 0, NULL)); Length = DataSize / sizeof( WCHAR) - 1; if ( DataSize > sizeof( FilePath) || FilePath[ Length] != 0) { RplDump( ++RG_Assert, ( "FitFile is bad %ws", FilePath)); return( FALSE); } pWorkerData->FitFile = RplMemAlloc( pWorkerData->MemoryHandle, RG_DirectoryLength * sizeof(WCHAR) + DataSize); if ( pWorkerData->FitFile == NULL) { pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; pWorkerData->EventId = NELOG_RplWkstaMemory; return( FALSE); } memcpy( pWorkerData->FitFile, RG_Directory, RG_DirectoryLength * sizeof(WCHAR)); memcpy( pWorkerData->FitFile + RG_DirectoryLength, FilePath, DataSize); CallB( JetRetrieveColumn( pSession->SesId, pSession->WkstaTableId, WkstaTable[ WKSTA_BootName].ColumnId, BootName, sizeof( BootName), &DataSize, 0, NULL)); CallB( JetRetrieveColumn( pSession->SesId, pSession->WkstaTableId, WkstaTable[ WKSTA_Flags].ColumnId, &Flags, sizeof( Flags), &DataSize, 0, NULL)); switch ( Flags & WKSTA_FLAGS_MASK_LOGON_INPUT) { case WKSTA_FLAGS_LOGON_INPUT_REQUIRED: pWorkerData->LogonInput = WKSTA_LOGON_INPUT_REQUIRED; break; case WKSTA_FLAGS_LOGON_INPUT_OPTIONAL: pWorkerData->LogonInput = WKSTA_LOGON_INPUT_OPTIONAL; break; case WKSTA_FLAGS_LOGON_INPUT_IMPOSSIBLE: pWorkerData->LogonInput = WKSTA_LOGON_INPUT_IMPOSSIBLE; break; default: RplDump( ++RG_Assert, ("Flags=0x%x", Flags)); return( FALSE); break; } switch ( Flags & WKSTA_FLAGS_MASK_DHCP) { default: case WKSTA_FLAGS_DHCP_TRUE: pWorkerData->TcpIpAddress = INADDR_NONE; pWorkerData->TcpIpSubnet = INADDR_NONE; pWorkerData->TcpIpGateway = INADDR_NONE; pWorkerData->DisableDhcp = WKSTA_DISABLE_DHCP_FALSE; break; case WKSTA_FLAGS_DHCP_FALSE: CallB( JetRetrieveColumn( pSession->SesId, pSession->WkstaTableId, WkstaTable[ WKSTA_TcpIpAddress].ColumnId, &pWorkerData->TcpIpAddress, sizeof( pWorkerData->TcpIpAddress), &DataSize, 0, NULL)); CallB( JetRetrieveColumn( pSession->SesId, pSession->WkstaTableId, WkstaTable[ WKSTA_TcpIpSubnet].ColumnId, &pWorkerData->TcpIpSubnet, sizeof( pWorkerData->TcpIpSubnet), &DataSize, 0, NULL)); CallB( JetRetrieveColumn( pSession->SesId, pSession->WkstaTableId, WkstaTable[ WKSTA_TcpIpGateway].ColumnId, &pWorkerData->TcpIpGateway, sizeof( pWorkerData->TcpIpGateway), &DataSize, 0, NULL)); pWorkerData->DisableDhcp = WKSTA_DISABLE_DHCP_TRUE; break; #if 0 // to help testing with old style records this is commented out default: RplDump( ++RG_Assert, ("Flags=0x%x", Flags)); return( FALSE); break; #endif } CallB( JetRetrieveColumn( pSession->SesId, pSession->WkstaTableId, WkstaTable[ WKSTA_TcpIpAddress].ColumnId, &pWorkerData->TcpIpAddress, sizeof( pWorkerData->TcpIpAddress), &DataSize, 0, NULL)); CallB( JetRetrieveColumn( pSession->SesId, pSession->WkstaTableId, WkstaTable[ WKSTA_TcpIpSubnet].ColumnId, &pWorkerData->TcpIpSubnet, sizeof( pWorkerData->TcpIpSubnet), &DataSize, 0, NULL)); CallB( JetRetrieveColumn( pSession->SesId, pSession->WkstaTableId, WkstaTable[ WKSTA_TcpIpGateway].ColumnId, &pWorkerData->TcpIpGateway, sizeof( pWorkerData->TcpIpGateway), &DataSize, 0, NULL)); if ( !RplDbFindBoot( pSession, BootName, AdapterName)) { RplDump( ++RG_Assert, ("FindBoot failed")); return( FALSE); } CallB( JetRetrieveColumn( pSession->SesId, pSession->BootTableId, BootTable[ BOOT_BbcFile].ColumnId, FilePath, sizeof( FilePath), &DataSize, 0, NULL)); Length = DataSize / sizeof( WCHAR) - 1; if ( DataSize > sizeof( FilePath) || FilePath[ Length] != 0) { RplDump( ++RG_Assert, ( "BbcFile is bad %ws", FilePath)); return( FALSE); } pWorkerData->BbcFile = RplMemAlloc( pWorkerData->MemoryHandle, RG_DirectoryLength * sizeof(WCHAR) + DataSize); if ( pWorkerData->BbcFile == NULL) { pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; pWorkerData->EventId = NELOG_RplWkstaMemory; return( FALSE); } memcpy( pWorkerData->BbcFile, RG_Directory, RG_DirectoryLength * sizeof(WCHAR)); memcpy( pWorkerData->BbcFile + RG_DirectoryLength, FilePath, DataSize); CallB( JetRetrieveColumn( pSession->SesId, pSession->BootTableId, BootTable[ BOOT_WindowSize].ColumnId, &pWorkerData->WindowSize, sizeof( pWorkerData->WindowSize), &DataSize, 0, NULL)); CallB( JetRetrieveColumn( pSession->SesId, pSession->BootTableId, BootTable[ BOOT_Flags].ColumnId, &Flags, sizeof( Flags), &DataSize, 0, NULL)); switch( Flags & BOOT_FLAGS_MASK_FINAL_ACKNOWLEDGMENT) { case BOOT_FLAGS_FINAL_ACKNOWLEDGMENT_TRUE: pWorkerData->FinalAck = TRUE; break; case BOOT_FLAGS_FINAL_ACKNOWLEDGMENT_FALSE: pWorkerData->FinalAck = FALSE; break; default: RplDump( ++RG_Assert, ("Flags=0x%x", Flags)); return( FALSE); break; } return( TRUE); } BOOL RplWorkerFillWksta( IN OUT PRPL_WORKER_DATA pWorkerData) { PRPL_SESSION pSession = &RG_WorkerSession; BOOL Success; EnterCriticalSection( &RG_ProtectWorkerSession); Call( JetBeginTransaction( pSession->SesId)); Success = RplDbFillWksta( pSession, pWorkerData); JetCommitTransaction( pSession->SesId, 0); LeaveCriticalSection( &RG_ProtectWorkerSession); return( Success); } BOOL RplRequestHaveWksta( IN LPWSTR AdapterName) /*++ Routine Description: If it finds wksta record for input AdapterName then it returns TRUE. Else, it tries to add the adapter record for input AdapterName, then returns FALSE. This code could be make more efficient by defining AdapterName to be jet currency data (it is silly now taking wcslen of AdapterName since it is a fixed length string. Return Value: TRUE if wksta record for input AdapterName is found FALSE otherwise --*/ { PRPL_SESSION pSession = &RG_RequestSession; BOOL WkstaFound; BOOL AdapterAdded; EnterCriticalSection( &RG_ProtectRequestSession); Call( JetBeginTransaction( pSession->SesId)); WkstaFound = RplDbFindWksta( pSession, AdapterName); if ( !WkstaFound) { // // Failed to find it. Try to add adapter record then. // AdapterAdded = RplDbAddAdapterName( pSession, AdapterName); } else { AdapterAdded = FALSE; } if ( AdapterAdded) { // // We do not flush newly added adapter records since we do // not want to slow down request threads. // Call( JetCommitTransaction( pSession->SesId, 0)); } else { Call( JetRollback( pSession->SesId, JET_bitRollbackAll)); } LeaveCriticalSection( &RG_ProtectRequestSession); return( WkstaFound); } // // Trmplated from DHCP's database.c 12/13/95 JonN // DWORD RplStartJet500Conversion( ) /*++ Routine Description: This function starts the process to convert the jet200 version database to jet500 version database. The Dhcp will terminate after starting this process. When the conversion completes, the dhcp service would be restarted by the convert process itself. Arguments: Return Value: Windows Error. --*/ { DWORD ExLen; STARTUPINFOA StartupInfo = {0}; PROCESS_INFORMATION ProcessInfo = {0}; CHAR szCmdLine[MAX_PATH]; #define JET_CONV_MODULE_NAME "%SystemRoot%\\system32\\jetconv REMOTEBOOT /@" ExLen = ExpandEnvironmentStringsA( JET_CONV_MODULE_NAME, szCmdLine, MAX_PATH ); if( (ExLen == 0) || (ExLen > MAX_PATH) ) { if( ExLen == 0 ) { return GetLastError(); } else { return ERROR_META_EXPANSION_TOO_LONG; } } StartupInfo.cb = sizeof(STARTUPINFOA); RplDump( RG_DebugLevel & RPL_DEBUG_REQUEST, ( "Calling %s\n",szCmdLine )); if ( !CreateProcessA( NULL, szCmdLine, NULL, NULL, FALSE, DETACHED_PROCESS, // CREATE_NEW_CONSOLE, NULL, NULL, &StartupInfo, &ProcessInfo) ) { return GetLastError(); } return ERROR_SUCCESS; }