mirror of https://github.com/lianthony/NT4.0
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.
1059 lines
35 KiB
1059 lines
35 KiB
/*++
|
|
|
|
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()
|
|
|
|
|
|
|