Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

998 lines
33 KiB

/*++
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;
}