/*++ Copyright (c) 1987-1993 Microsoft Corporation Module Name: bbcfile.c Abstract: Processes boot block configuration file. Provides bbcfile functionality similar to that contained in init.c & patch.c of LANMAN 2.1 code. Author: Vladimir Z. Vulovic (vladimv) 19 - November - 1993 Environment: User mode Revision History : --*/ #include "local.h" #include "bbcfile.h" // // Checksum buffer size is chosen to be a multiple of 8 * sizeof( DWORD). // to speed up checksum algorithm below. This is not a requirement though. // #define CHK_SUM_BUF_SIZE ( 8 * sizeof( DWORD) * 256) // 8K #define NO_PATCH_OFFSET ((DWORD)-1) #define PARAM_INDEX 2 // index of parameters in sys/com/exe line // // PARAM_INDEX string when expressed in DBCS should not exceed 0xFF bytes. // #define MAX_SIZE_DBCS_PARAMS (0xFF+1) #define MEM_INDEX 3 // index of extra memory in sys/com/exe line #define MOVEABLE_INDEX 4 // set if driver can be moved after init // // MOVABLE_INDEX string may be take one of the following two values. // #define MOVEABLE_SWITCH L'M' #define EXEC_IN_LOW_MEM_SWITCH L'L' // undocumented switch value #define MAX_FLIST_LEN 255 // // Indices used for parsing of lines in boot block configuration files. // #define CONF_LINE_ID 0 // index of line type #define CONF_LINE_FILE 1 // index of file (rel path) in config line #define CONF_LINE_BASE_ADDRESS 1 // index of file (rel path) in config line #define FIRST_FILE_NAME 3 // index of the first file name in LDR line #define MAX_CONFIG_FIELDS 8 // maximum number of fields in config line #define MIN_BBLOCK_BASE_SEG 0xc0 #define TILDE_STRING L"~" #define SPACE_STRING L" " DWORD StringToDword( IN PWCHAR String) /*++ We would like to use generic base (0) but it does not work for strings like "D0H". That is the reason why we first check if the last character is 'H' or 'h'. --*/ { DWORD Length; Length = wcslen( String); if ( Length == 0) { return( 0); } if ( String[ Length-1] == L'H' || String[ Length-1] == L'h') { return( wcstoul( String, NULL, 16)); } else { return( wcstoul( String, NULL, 0)); } } BOOL RplInitExeOrSys( IN PRPL_WORKER_DATA pWorkerData, IN OUT PFLIST_TBL pFlist ) /*++ Routine Description: Retreives the file type of a binary (exe/com/sys) file. Arguments: pFlist - pointer to FLIST_TBL element Return Value: TRUE if successful, else FALSE. --*/ { BYTE id_tbl[2]; HANDLE FileHandle; DWORD bytes_read; DWORD DbcsSize; LPSTR DbcsString; PWCHAR * WordTable; FileHandle = RplFileOpen( pFlist->path_name); if ( FileHandle == INVALID_HANDLE_VALUE) { RplDump( ++RG_Assert, ( "path_name=%ws", pFlist->path_name)); pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; pWorkerData->EventStrings[ 1] = pFlist->path_name; pWorkerData->EventId = NELOG_RplWkstaFileOpen; return( FALSE); } if ( !ReadFile( FileHandle, id_tbl, 2, &bytes_read, NULL)) { RplDump( ++RG_Assert, ( "Error = %d", GetLastError())); pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; pWorkerData->EventStrings[ 1] = pFlist->path_name; pWorkerData->EventId = NELOG_RplWkstaFileRead; (VOID)CloseHandle( FileHandle); return( FALSE); } (VOID)CloseHandle( FileHandle); if ( bytes_read == 2 && id_tbl[0] == 0x4d && id_tbl[1] == 0x5a) { // // Driver or executable file is in exe-format, set the bit in // the type field. This info will be used on the client side. // pFlist->FileData.file_type |= IS_EXE_SYS; } WordTable = pWorkerData->WordTable; if ( *WordTable[ PARAM_INDEX] == 0) { pFlist->FileData.param_len = 0; pFlist->param_list = (LPSTR)&RG_Null; } else { DbcsSize = RplUnicodeToDbcs( pWorkerData->MemoryHandle, WordTable[ PARAM_INDEX], -1, // UNICODE string length not available MAX_SIZE_DBCS_PARAMS, &DbcsString ); if ( DbcsSize == 0) { RplDump( ++RG_Assert, ("WordTable=0x%x, string=%ws", WordTable, WordTable[ PARAM_INDEX])); pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; pWorkerData->EventStrings[ 1] = pFlist->path_name; pWorkerData->EventId = NELOG_RplWkstaFileSize; return( FALSE); } pFlist->FileData.param_len = (BYTE)(DbcsSize - 1); pFlist->param_list = DbcsString; } pFlist->FileData.extra_mem = StringToDword( WordTable[ MEM_INDEX]); if ( *WordTable[ MOVEABLE_INDEX] == MOVEABLE_SWITCH) { pFlist->FileData.file_type |= IS_MOVEABLE; } else if ( *WordTable[ MOVEABLE_INDEX] == EXEC_IN_LOW_MEM_SWITCH) { pFlist->FileData.file_type |= EXEC_IN_LOW_MEM; } return( TRUE); } BOOL RplChecksum( IN OUT PRPL_WORKER_DATA pWorkerData, IN HANDLE FileHandle, OUT PWORD pChecksum ) /*++ Routine Description: If successful returns sum of all words in a file. Arguments: FileHandle - handle of file to checksum pChecksum - pointer to calculated checksum Return Value: TRUE if success, FALSE otherwise --*/ { DWORD Checksum; DWORD BytesRead; PDWORD pDword; DWORD Length; if ( pWorkerData->ChecksumBuffer == NULL) { pWorkerData->ChecksumBuffer = RplMemAlloc( pWorkerData->MemoryHandle, CHK_SUM_BUF_SIZE); if ( pWorkerData->ChecksumBuffer == NULL) { return( FALSE); } } Checksum = 0; do { // // These are usually binary files so there are no DBCS/UNICODE // issues. But even if we had a text file here, we should read // it & checksum it raw (i.e. no conversion from DBCS to UNICODE) // since it is the raw data that gets shipped to the client. // if ( !ReadFile( FileHandle, pWorkerData->ChecksumBuffer, CHK_SUM_BUF_SIZE, &BytesRead, NULL)) { RplDump( ++RG_Assert, ( "Error = %d", GetLastError())); return( FALSE); } // // Round up to make it divisible by 4 == sizeof( *pDword). // Note that extra bytes are set zero in the 'boot' block, // the files are always on the boundary of paragraph. // if ( BytesRead & 1) { // make it divisible by 2 pWorkerData->ChecksumBuffer[ BytesRead++] = 0; } if ( BytesRead & 2) { // make it divisible by 4 pWorkerData->ChecksumBuffer[ BytesRead++] = 0; pWorkerData->ChecksumBuffer[ BytesRead++] = 0; } // // Checksum in chunks of 8, for speed. // for ( Length = BytesRead / 4, pDword = (PDWORD)pWorkerData->ChecksumBuffer + Length; Length > 8; Length -= 8) { pDword -= 8; Checksum += pDword[ 0]; Checksum += pDword[ 1]; Checksum += pDword[ 2]; Checksum += pDword[ 3]; Checksum += pDword[ 4]; Checksum += pDword[ 5]; Checksum += pDword[ 6]; Checksum += pDword[ 7]; } // Then finish the checksum. // for ( ; Length > 0; Length--) { Checksum += *(--pDword); } } while (BytesRead == CHK_SUM_BUF_SIZE); // exit read loop when all read *pChecksum = LOWORD( Checksum) + HIWORD( Checksum); return( TRUE); } BOOL RplInitFileList( IN PRPL_WORKER_DATA pWorkerData, IN LPWSTR rel_path, IN OUT PFLIST_TBL pFlist, IN OUT PDWORD cur_para_ptr, IN DWORD file_type ) /*++ Routine Description: Opens a file and initalizes the parameter item of the file list table. It reads the file only if checksum is required and file is not of RPL_BOOT_TYPE. Arguments: rel_path - relative path name of file pFlist - pointer to current element in file list table cur_para_ptr - current paragraph file_type - file type Return Value: TRUE if success, FALSE otherwise. --*/ { HANDLE FileHandle; LPSTR DbcsFileName; DWORD DbcsFileNameSize; DWORD Size; BOOL Success; Success = FALSE; FileHandle = INVALID_HANDLE_VALUE; RplDump( RG_DebugLevel & RPL_DEBUG_FLOW,( "++InitFileList(0x%x)", pWorkerData)); // // get the full path name and the actual file name // Size = ( RG_DirectoryLength + wcslen( rel_path) + 1) * sizeof(WCHAR); pFlist->path_name = RplMemAlloc( pWorkerData->MemoryHandle, Size); if ( pFlist->path_name == NULL) { pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; pWorkerData->EventId = NELOG_RplWkstaMemory; goto cleanup; } wcscpy( pFlist->path_name, RG_Directory); wcscat( pFlist->path_name, rel_path); // // Open the BBC file and get its length. // FileHandle = RplFileOpen( pFlist->path_name); if ( FileHandle == INVALID_HANDLE_VALUE) { RplDump( ++RG_Assert, ("path_name=%ws", pFlist->path_name)); pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; pWorkerData->EventStrings[ 1] = pFlist->path_name; pWorkerData->EventId = NELOG_RplWkstaFileOpen; goto cleanup; } Size = GetFileSize( FileHandle, NULL); if ( Size == INVALID_FILE_SIZE) { RplDump( ++RG_Assert, ( "Error=%d, path_name=%ws", GetLastError(), pFlist->path_name)); pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; pWorkerData->EventStrings[ 1] = pFlist->path_name; pWorkerData->EventId = NELOG_RplWkstaFileSize; goto cleanup; } pFlist->FileData.file_len = Size; // // Calculate checksum for the file, if cheksums are done. Note that // RPLBOOT.SYS is never checksummed because it modifies its own code // before the checking the checksum. // if ( RG_ReadChecksum && file_type != RPL_BOOT_TYPE) { if ( !RplChecksum( pWorkerData, FileHandle, &pFlist->FileData.chk_sum)) { pFlist->FileData.chk_sum = NO_CHKSUM_USED; // for RPLBOOT to ingore checksum pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; pWorkerData->EventStrings[ 1] = pFlist->path_name; pWorkerData->EventId = NELOG_RplWkstaFileChecksum; } } else { pFlist->FileData.chk_sum = NO_CHKSUM_USED; // RPLBOOT is never checksummed } // // Note that FileName is UNICODE, while client needs to receive a DBCS // version of this name // pFlist->FileName = RplGetLastPathComponent( pFlist->path_name); DbcsFileNameSize = RplUnicodeToDbcs( pWorkerData->MemoryHandle, pFlist->FileName, // UNICODE string to convert -1, // UNICODE string length not available MAX_SIZEOF_DBCS_PATH, &DbcsFileName ); if ( DbcsFileNameSize == 0) { RplDump( ++RG_Assert, ("FileName=%ws", pFlist->FileName)); pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; pWorkerData->EventStrings[ 1] = pFlist->path_name; pWorkerData->EventId = NELOG_RplWkstaFileSize; goto cleanup; } pFlist->DbcsFileName = DbcsFileName; pFlist->DbcsFileNameSize = DbcsFileNameSize; // // Length of file in paragraphs, rounded up to the next paragraph. // The maximum length could be checked, but let it be. // Set the relative position of file from the start of file block // pFlist->FileData.file_len = (pFlist->FileData.file_len + 15) & 0xfffffff0L; pFlist->FileData.file_type = (WORD)file_type; pFlist->FileData.param_len = 0; pFlist->FileData.extra_mem = 0; pFlist->FileData.param_offset = 0; pFlist->FileData.name_offset = 0; pFlist->param_list = NULL; // // There may be several instances of the same file in the boot block. // For example, Nokia NetStation memory extender LOADHI.SYS can load // device drivers to memory between C000 - FFFF. PROTMAN.SYS, NDIS and // NETBEUI may all be loaded to there. These boot block lines // load the whole DOS NDIS stack to the memory above C000 // DAT NETBEUI.DOS // DRV LOADHI.SYS NETBEUI.DOS ~ // DAT IBMTOK.DOS // DRV LOADHI.SYS IBMTOK.DOS ~ // DAT PROTMAN.DOS // DRV LOADHI.SYS PROTMAN.DOS~I:\ ~ // // The code to send LOADHI.SYS once (instead of three times) in the boot // block, is not worth of effort, since LOADHI.SYS is small (~4kB). // pFlist->FileData.file_addr = *cur_para_ptr * 16; *cur_para_ptr += (pFlist->FileData.file_len / 16); RplDump( RG_DebugLevel & RPL_DEBUG_FLOW,( "--InitFileList(0x%x)", pWorkerData)); Success = TRUE; cleanup: if ( FileHandle != INVALID_HANDLE_VALUE) { (VOID)CloseHandle( FileHandle); } return( Success); } LPWSTR * RplBbcFileToTable( IN OUT PRPL_WORKER_DATA pWorkerData) /*++ Routine Description: Reads boot block file to a buffer. Skips comment lines and copies non-comment lines to the string buffer. Returns pointer to the array of pointers to lines, and the length of table. Arguments: Return Value: Pointer to line table if successful, NULL otherwise. --*/ { #define RPL_LINE_END L"\n\r" DWORD index; LPWSTR * Table; PWCHAR UnicodeString; PWCHAR pWchar; RplDump( RG_DebugLevel & RPL_DEBUG_FLOW,( "++BbcFileToTable(0x%x)", pWorkerData)); UnicodeString = RplReadTextFile( pWorkerData->MemoryHandle, pWorkerData->BbcFile, MAX_BBC_FILE_SIZE); if ( UnicodeString == NULL) { RplDump( ++RG_Assert, ( "BbcFile=%ws", pWorkerData->BbcFile)); pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; pWorkerData->EventStrings[ 1] = pWorkerData->BbcFile; pWorkerData->EventId = NELOG_RplWkstaFileRead; return( NULL); } Table = RplMemAlloc( pWorkerData->MemoryHandle, (MAX_FLIST_LEN+1)* sizeof( LPWSTR)); if ( Table == NULL) { pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; pWorkerData->EventId = NELOG_RplWkstaMemory; return( NULL); } for ( pWchar = wcstok( UnicodeString, RPL_LINE_END), index = 0; pWchar != NULL && index < MAX_FLIST_LEN; pWchar = wcstok( NULL, RPL_LINE_END)) { while( iswspace( *pWchar)) { // skip empty chars at the beginning pWchar++; } if ( *pWchar == 0 || *pWchar == L';') { continue; // don't save blank or comment lines } Table[ index++] = pWchar; } if ( pWchar != NULL) { // // Error case. Too many lines in the file. // RplDump( ++RG_Assert, ( "pWchar=0x%x", pWchar)); pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; pWorkerData->EventStrings[ 1] = pWorkerData->BbcFile; pWorkerData->EventId = NELOG_RplWkstaFileLineCount; Table = NULL; } else { Table[ index] = NULL; // terminate the table } RplDump( RG_DebugLevel & RPL_DEBUG_FLOW,( "--BbcFileToTable(0x%x)", pWorkerData)); return( Table); } // RplBbcFileToTable() BOOL RplBbcLineToTable( IN OUT PRPL_WORKER_DATA pWorkerData, IN LPWSTR Line ) /*++ Routine Description: Copies a line into a buffer. Breaks the copy into "words" (substrings). Makes an array of pointers to "words". The original line string is kept unchanged because it is needed for error reporting in the caller. Arguments: Line - ptr to line string Return Value: TRUE if success, FALSE otherwise. FALSE is returned if we ran out of memory, or if line has too many words. --*/ { DWORD index; DWORD BufferSize; LPWSTR Cursor; RplDump( RG_DebugLevel & RPL_DEBUG_FLOW,( "++BbcLineToTable(0x%x):%ws", pWorkerData, Line)); BufferSize = (wcslen( Line) + 1) * sizeof( WCHAR); if ( pWorkerData->LineBuffer == NULL) { pWorkerData->LineBuffer = RplMemAlloc( pWorkerData->MemoryHandle, BufferSize); if ( pWorkerData->LineBuffer == NULL) { pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; pWorkerData->EventId = NELOG_RplWkstaMemory; return( FALSE); } pWorkerData->LineBufferSize = BufferSize; } else if ( BufferSize > pWorkerData->LineBufferSize) { RplMemFree( pWorkerData->MemoryHandle, pWorkerData->LineBuffer); pWorkerData->LineBuffer = RplMemAlloc( pWorkerData->MemoryHandle, BufferSize); if ( pWorkerData->LineBuffer == NULL) { pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; pWorkerData->EventId = NELOG_RplWkstaMemory; return( FALSE); } pWorkerData->LineBufferSize = BufferSize; } if ( pWorkerData->WordTable == NULL) { pWorkerData->WordTable = RplMemAlloc( pWorkerData->MemoryHandle, (MAX_CONFIG_FIELDS + 1) * sizeof(LPWSTR) ); if ( pWorkerData->WordTable == NULL) { pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; pWorkerData->EventId = NELOG_RplWkstaMemory; return( FALSE); } } memcpy( pWorkerData->LineBuffer, Line, BufferSize); for ( index = 0, Cursor = wcstok( pWorkerData->LineBuffer, SPACE_STRING); index < MAX_CONFIG_FIELDS && Cursor != NULL; index++, Cursor = wcstok( NULL, SPACE_STRING)) { if ( wcscmp( Cursor, TILDE_STRING) == 0) { // // Single tilda is just an empty placeholder. // pWorkerData->WordTable[ index] = (LPWSTR)&RG_Null; } else { pWorkerData->WordTable[ index] = Cursor; // // In unlikely case there are tildas embedded with a filename // (e.g. driver with its parameters), replace them tildas with spaces. // while ( (Cursor = wcsrchr( Cursor, TILDE_CHAR)) != NULL) { *Cursor++ = SPACE_CHAR; } } } if ( Cursor != NULL) { // // Boot block config line has too many items. // RplDump( ++RG_Assert, ( "Cursor=0x%x", Cursor)); pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; pWorkerData->EventStrings[ 1] = pWorkerData->BbcFile; pWorkerData->EventStrings[ 2] = Line; pWorkerData->EventId = NELOG_Invalid_Config_Line; return( FALSE); } while ( index < MAX_CONFIG_FIELDS) { pWorkerData->WordTable[ index++] = (LPWSTR)&RG_Null; // fill in the rest } pWorkerData->WordTable[ index] = NULL; // then null terminate RplDump( RG_DebugLevel & RPL_DEBUG_FLOW,( "--BbcLineToTable(0x%x):%ws", pWorkerData, Line)); return( TRUE); } CONFIG_TYPE ConfigTypeTable[] = { { L"RPL", RPL_BOOT_TYPE}, { L"ORG", ORG_TYPE}, { L"DAT", DATA_FILE}, { L"LDR", BINARY_LOADER}, { L"DRV", DRV_TYPE}, { L"EXE", EXE_TYPE}, { L"BASE", BASE_TYPE}, { NULL, UNKNOWN_CONFIG_TYPE} }; DWORD RplConfigLineType( IN LPWSTR ConfigLineId) /*++ Routine Description: Returns the type of the current line in boot block config file. Arguments: Pointer to identifier for the current line. Return Value: Config line type. --*/ { DWORD Type; PCONFIG_TYPE pConfigType; for ( Type = UNKNOWN_CONFIG_TYPE, pConfigType = ConfigTypeTable; pConfigType->id != 0; pConfigType++) { if ( !wcscmp( ConfigLineId, pConfigType->id )) { Type = pConfigType->type; break; } } return( Type); } BOOL RplCheckBootHeader( IN PRPL_WORKER_DATA pWorkerData, IN LPWSTR FilePath, OUT PDWORD pFirstOffset ) /*++ Routine Description: Reads patch offsets from the start of DLCLOADR.COM file. Arguments: FilePath - path name of DLCLOADR.COM pFirstOffset - ptr to first NLS patch offset Return Value: TRUE if successful, FALSE otherwise. --*/ { HANDLE FileHandle; DWORD read_len; WORD offset_buf[ OFFSET_BUF_LEN]; PRPLBOOT_HEADER pRplbootHdr; BOOL Success; Success = FALSE; FileHandle = RplFileOpen( FilePath); if ( FileHandle == INVALID_HANDLE_VALUE) { RplDump( ++RG_Assert, ( "FilePath=%ws", FilePath)); pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; pWorkerData->EventStrings[ 1] = FilePath; pWorkerData->EventId = NELOG_RplWkstaFileOpen; goto cleanup; } if ( !ReadFile( FileHandle, (PBYTE)offset_buf, OFFSET_BUF_LEN * sizeof(WORD), &read_len, NULL)) { RplDump( ++RG_Assert, ( "Error=%d", GetLastError())); pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; pWorkerData->EventStrings[ 1] = FilePath; pWorkerData->EventId = NELOG_RplWkstaFileRead; goto cleanup; } pRplbootHdr = (PRPLBOOT_HEADER)((PBYTE)offset_buf + OFFSET_RPLBOOT_HDR); if ( !strcmp( pRplbootHdr->achIdStamp, "RPL" ) && // BUGBUG hardcoded constants pRplbootHdr->bBbVersion == BBVERSION_10 ) { // // check that rplboot.sys nls patch version match or // it does not require NLS patching at all // if (pRplbootHdr->bNlsVersion == NLS_VERSION_10) { // // get the offset of NLS patches in RPLBOOT.SYS // *pFirstOffset = pRplbootHdr->usNlsPatchOff; } else if (pRplbootHdr->bNlsVersion == 0) { // // No NLS patching, if version number is 0, that's OK. // *pFirstOffset = NO_PATCH_OFFSET; } else { // // Configuration error: RPLBOOT.SYS expects to get a // different NLS patching from one that RPLSERVR can provide, // the versions are incompatible. // RplDump( ++RG_Assert, ( "FilePath=%ws", FilePath)); pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; pWorkerData->EventStrings[ 1] = FilePath; pWorkerData->EventId = NELOG_RplWkstaWrongVersion; goto cleanup; } } else { // // Configuration error: the header is missing, this is an old // (or wrong) RPLBOOT.sys. // RplDump( ++RG_Assert, ( "FilePath=%ws", FilePath)); pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; pWorkerData->EventStrings[ 1] = FilePath; pWorkerData->EventId = NELOG_RplWkstaWrongVersion; goto cleanup; } Success = TRUE; cleanup: if ( FileHandle != INVALID_HANDLE_VALUE) { (VOID)CloseHandle( FileHandle); } return( Success); } BOOL RplBbcFile( IN OUT PRPL_WORKER_DATA pWorkerData) /*++ Routine Description: Processes the boot block configuration file. Initializes file list table. Arguments: Return Value: TRUE if success, FALSE otherwise --*/ { LPWSTR * LineTable; // ptr to array of line-strings for BBC file DWORD LoaderLineIndex; // index of a loader line in BBC file LPWSTR * LoaderWordTable; // ptr to array of word-strings for loader line LPWSTR LoaderBuffer; // buffer for LoaderWordTable PRESOURCE_TBL resource_tbl; DWORD resource_tbl_size; DWORD resource_tbl_len; LPWSTR String; DWORD Index; DWORD org_addr; DWORD cur_para; // current length of boot block image in paragraphs DWORD fblock_base; DWORD bblock_base; // no default base address PFLIST_TBL flist_tbl; // file list array DWORD flist_tbl_len; // # of elements in flist_tbl[] DWORD flist_tbl_size; // size in bytes of flist_tbl[] DWORD FileIndex; // index entries in flist_tbl[] BOOL org_is_set; DWORD line_type; DWORD PatchOffset; RplDump( RG_DebugLevel & RPL_DEBUG_FLOW,( "++BbcFile(0x%x)", pWorkerData)); pWorkerData->loader_i = pWorkerData->rplboot_i = MAXWORD; fblock_base = bblock_base = 0; resource_tbl_size = resource_tbl_len = 0; org_is_set = FALSE; cur_para = 0; // // Read boot block configuration file to a UNICODE string table, where // each string from this table contains a single line from BBC file. // This table is null terminated. // LineTable = RplBbcFileToTable( pWorkerData); if ( LineTable == NULL) { return( FALSE); } flist_tbl = RplMemAlloc( pWorkerData->MemoryHandle, sizeof(FLIST_TBL) * MAX_FLIST_LEN); if ( flist_tbl == NULL) { pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; pWorkerData->EventId = NELOG_RplWkstaMemory; return( FALSE); } // // Process lines in the boot block configuration file and // insert data to file list // for ( Index = FileIndex = 0; (String = LineTable[ Index]) != NULL; Index++) { // // Break up single line from boot block config file into word table. // if ( !RplBbcLineToTable( pWorkerData, String)) { return( FALSE); } line_type = RplConfigLineType( pWorkerData->WordTable[ CONF_LINE_ID]); switch ( line_type) { case RPL_BOOT_TYPE: // There must be a single entry like this. if ( pWorkerData->rplboot_i != MAXWORD) { RplDump( ++RG_Assert, ( "BbcFile=%ws, String=%ws", pWorkerData->BbcFile, String)); pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; pWorkerData->EventStrings[ 1] = pWorkerData->BbcFile; pWorkerData->EventStrings[ 2] = String; pWorkerData->EventId = NELOG_Invalid_Config_Line; return( FALSE); } pWorkerData->rplboot_i = FileIndex; // fall through !! case BINARY_LOADER: // There must be a single entry like this. if (line_type == BINARY_LOADER) { if ( pWorkerData->loader_i != MAXWORD) { RplDump( ++RG_Assert, ( "BbcFile=%ws, String=%ws, loader_i=0x%x", pWorkerData->BbcFile, String, pWorkerData->loader_i)); pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; pWorkerData->EventStrings[ 1] = pWorkerData->BbcFile; pWorkerData->EventStrings[ 2] = String; pWorkerData->EventId = NELOG_Invalid_Config_Line; return( FALSE); } pWorkerData->loader_i = FileIndex; } // fall through !! case EXE_TYPE: case DRV_TYPE: case DATA_FILE: if ( !RplInitFileList( pWorkerData, pWorkerData->WordTable[ CONF_LINE_FILE], &flist_tbl[ FileIndex], &cur_para, line_type)) { return( FALSE); } if ( line_type == DRV_TYPE || line_type == EXE_TYPE) { if ( !RplInitExeOrSys( pWorkerData, &flist_tbl[ FileIndex])) { return( FALSE ); } } // // Update the minimum size of header. // Reserve space for 0xa 0xd in the end of param list // if ( flist_tbl[ FileIndex].FileData.param_len) { pWorkerData->min_wksta_buf += (flist_tbl[ FileIndex].FileData.param_len + 2); } pWorkerData->min_wksta_buf += flist_tbl[ FileIndex].DbcsFileNameSize; FileIndex++; break; case ORG_TYPE: org_addr = StringToDword( pWorkerData->WordTable[ CONF_LINE_FILE]); // // file block base must be above 0C0 (paras) // fblock_base = org_addr - cur_para - bblock_base; org_is_set = TRUE; if ( cur_para + bblock_base > org_addr) { RplDump( ++RG_Assert, ( "BbcFile=%ws, cur_para=0x%x," " bblock_base=0x%x, org_addr=0x%x", pWorkerData->BbcFile, cur_para, bblock_base, org_addr)); pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; pWorkerData->EventStrings[ 1] = pWorkerData->BbcFile; pWorkerData->EventId = NELOG_Files_Dont_Fit; return( FALSE); } break; case BASE_TYPE: bblock_base = StringToDword( pWorkerData->WordTable[ CONF_LINE_BASE_ADDRESS]); if ( org_is_set || bblock_base < MIN_BBLOCK_BASE_SEG) { // // Origin has been set to a wrong address or // boot block base address is too low. // RplDump( ++RG_Assert, ( "BbcFile=%ws, org_is_set=%d, bblock_base=0x%x", pWorkerData->BbcFile, org_is_set, bblock_base)); pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; pWorkerData->EventStrings[ 1] = pWorkerData->BbcFile; pWorkerData->EventId = NELOG_Files_Dont_Fit; return( FALSE); } break; default: RplDump( ++RG_Assert, ( "BbcFile=%ws, String=%ws", pWorkerData->BbcFile, String)); pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; pWorkerData->EventStrings[ 1] = pWorkerData->BbcFile; pWorkerData->EventStrings[ 2] = String; pWorkerData->EventId = NELOG_Invalid_Config_Line; return( FALSE); } // switch( line_type) if ( line_type == BINARY_LOADER) { // // We have to save loader line data for processing below. // LoaderWordTable = pWorkerData->WordTable; LoaderBuffer = pWorkerData->LineBuffer; pWorkerData->LineBuffer = NULL; pWorkerData->WordTable = NULL; LoaderLineIndex = Index; } } // // Boot block configuration file must contain a boot line (RPLBOOT.SYS) // and a loader line (RPLSTART.COM or OS2LDR). // if ( pWorkerData->rplboot_i == MAXWORD || pWorkerData->loader_i == MAXWORD) { RplDump( ++RG_Assert, ( "BbcFile=%ws, rplboot_i=0x%x, loader_i=0x%x\n", pWorkerData->BbcFile, pWorkerData->rplboot_i, pWorkerData->loader_i)); pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; pWorkerData->EventStrings[ 1] = pWorkerData->BbcFile; pWorkerData->EventId = NELOG_RplWkstaBbcFile; return( FALSE); } // // Do not bother to resize file list table - it will be freed shortly // anyway, just save the relevant size of table for later use. // flist_tbl_len = FileIndex; flist_tbl_size = flist_tbl_len * sizeof(FLIST_TBL); // // Check the loader parameters. This code does real work for OS/2 only. // For DOS it just fills the null table entry. // // // Count number of items in the resource table. // for ( resource_tbl_len = 0; *LoaderWordTable[ FIRST_FILE_NAME + resource_tbl_len]; resource_tbl_len++) { NOTHING; } resource_tbl_len++; // leave space for terminating null resource_tbl_size = resource_tbl_len * sizeof( RESOURCE) + sizeof( WORD); resource_tbl = RplMemAlloc( pWorkerData->MemoryHandle, resource_tbl_size); if ( resource_tbl == NULL) { pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; pWorkerData->EventId = NELOG_RplWkstaMemory; return( FALSE); } if ( resource_tbl_len > MAXWORD) { RplDump( ++RG_Assert, ( "resource_tbl_len=%d", resource_tbl_len)); return( FALSE); } resource_tbl->entries = (WORD)resource_tbl_len; // // get the file names in the reource table of OS2LDR // for ( Index = 0; *(String = LoaderWordTable[ FIRST_FILE_NAME + Index]) != 0; Index++) { String = RplGetLastPathComponent( String); // convert file path to file name // // Verify that resource file is a part of a boot block. // for ( FileIndex = 0; FileIndex < flist_tbl_len && _wcsicmp( String, flist_tbl[ FileIndex].FileName); FileIndex++) { NOTHING; } if ( FileIndex == flist_tbl_len) { // // resource file is not a part of a boot block // RplDump( ++RG_Assert, ( "BbcFile=%ws, Line=%ws", pWorkerData->BbcFile, LineTable[ LoaderLineIndex])); pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; pWorkerData->EventStrings[ 1] = pWorkerData->BbcFile; pWorkerData->EventStrings[ 2] = LineTable[ LoaderLineIndex]; pWorkerData->EventId = NELOG_Invalid_Config_Line; return( FALSE); } // // initialize the next item in resource table // resource_tbl->file_tbl[ Index].pos_in_paras = (WORD)( flist_tbl[ FileIndex].FileData.file_addr >> 4); resource_tbl->file_tbl[ Index].file_len = flist_tbl[ FileIndex].FileData.file_len; } resource_tbl->file_tbl[ Index].pos_in_paras = 0; resource_tbl->file_tbl[ Index].file_len = 0L; // // Clean up. // RplMemFree( pWorkerData->MemoryHandle, LoaderWordTable); RplMemFree( pWorkerData->MemoryHandle, LoaderBuffer); // // Get the minimum size of workstation specific data // pWorkerData->min_wksta_buf += flist_tbl_size + resource_tbl_size; pWorkerData->file_block_base = fblock_base << 4; pWorkerData->boot_block_base = bblock_base << 4; pWorkerData->flist_tbl = flist_tbl; pWorkerData->flist_tbl_len = flist_tbl_len; pWorkerData->resource_tbl = resource_tbl; pWorkerData->resource_tbl_size = resource_tbl_size; // // Check header of RPLBOOT.SYS. // if( !RplCheckBootHeader( pWorkerData, flist_tbl->path_name, &PatchOffset)) { return( FALSE); } // // RPLBOOT.SYS has a good header, see if it requires patching. // if ( PatchOffset == NO_PATCH_OFFSET) { pWorkerData->MakePatch = FALSE; // RPLBOOT.SYS requires no patching. } else { pWorkerData->MakePatch = TRUE; pWorkerData->PatchOffset = flist_tbl[ pWorkerData->rplboot_i].FileData.file_addr + PatchOffset; flist_tbl[ pWorkerData->rplboot_i].FileData.chk_sum = NO_CHKSUM_USED; } RplDump( RG_DebugLevel & RPL_DEBUG_FLOW,( "--BbcFile(0x%x)", pWorkerData)); return( TRUE); } // RplBbcFile()