summaryrefslogtreecommitdiffstats
path: root/private/net/svcdlls/rpl/server/open.c
blob: eb4b1c4e0366f96c1218d13ff691e42616884799 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
/*++

Copyright (c) 1987-1993 Microsoft Corporation

Module Name:

    _open.c

Abstract:

    Initializes workstation specific data structures and returns the handle.

    Provides similar functionality to rmapopen.c in LANMAN 2.1 code.

Author:

    Vladimir Z. Vulovic     27 - July - 1993

Environment:

    User mode

Revision History :

--*/

#include "local.h"
#include "database.h"
#include "bbcfile.h"
#include "fitfile.h"
#include "open.h"

// translates 32 bit physical address to 16-bit paragraphs
#define PHYS_TO_PARA( physaddr)    ((WORD)((physaddr) >> 4))

#define MAX_WKSTA_PROFILES  10          // rplmgr supports now only 2!
#define PROF_DATA_SIZE      (sizeof(MBOOTDATA)+80)   // include comment size!
#define MAX_WKSTA_BUF       ((DWORD)0xff00)



DWORD FillString( OUT PCHAR Buffer, IN PCHAR String)
{
    strcpy( Buffer, String);
    return( strlen( Buffer));
}


BOOL RplCreateWkstaLine(
    IN OUT  PRPL_WORKER_DATA    pWorkerData,
    OUT     PDWORD              pWkstaLineSize
    )
/*++
    LANMAN 2.1 wksta record in RPL.MAP contained the following information:

    Field 1:    AdapterId - NO
    Field 2:    WkstaName
    Field 3:    Username/Password prompting field.
    Field 4:    Fit file name. - NO
    Field 5:    Name of server used to access files for booting. - NO (DLC server)
    Field 6:    Shared or Personal profile. - NO
    Field 7:    '~'
    Field 8:    '~'
    Field 9:    '~'
    Field 10:   ',,,'
    Field 11:   '~'
    Field 12:   Tag of associated LANMAN 2.1 boot block configuration (server) record. - NO
    Field 13:   '~'     (but see below)
    Field 14:   Name of associtated profile. - NO
    Field 15:   Descriptive comment. - NO
    Field 16:   Optional IP address of a workstation.
    Field 17:   Optional TCP/IP subnet mask.
    Field 18:   Optional TCP/IP gateway address.

    Out of the above, client side only needs Fields # 2, 3, 15, 16, 17 & 18.
    All the other fields can be replaced with tildas.  And of course if this
    does not work we can always go back to the original wksta line & send him
    all then cut back on the amount of info.

    All of these lines worked fine for VLADIMV7 client.  Checked "dir c:",
    logging as vladimv on Redmond, treeconnecting & dir on remote drives.

#define RPLTEST_WKSTALINE   "02608C1B87A5 VLADIMV7 N fits\\dos500 VLADIMV3 S ~ ~ ~ ,,, ~ RDOST  ~ d5elnk2 VLADIMV1~=>~shared~dos~profile ~ ~ ~"
#define RPLTEST_WKSTALINE   "~ VLADIMV7 N fits\\dos500 VLADIMV3 S ~ ~ ~ ,,, ~ RDOST  ~ d5elnk2 VLADIMV1~=>~shared~dos~profile ~ ~ ~"
#define RPLTEST_WKSTALINE   "~ VLADIMV7 N fits\\dos500 VLADIMV3 S ~ ~ ~ ,,, ~ ~ ~ d5elnk2 VLADIMV1~=>~shared~dos~profile ~ ~ ~"
#define RPLTEST_WKSTALINE   "~ VLADIMV7 N ~ VLADIMV3 S ~ ~ ~ ,,, ~ ~ ~ d5elnk2 VLADIMV1~=>~shared~dos~profile ~ ~ ~"
#define RPLTEST_WKSTALINE   "~ VLADIMV7 N ~ ~ S ~ ~ ~ ,,, ~ ~ ~ d5elnk2 VLADIMV1~=>~shared~dos~profile ~ ~ ~"
#define RPLTEST_WKSTALINE   "~ VLADIMV7 N ~ ~ S ~ ~ ~ ,,, ~ ~ ~ d5elnk2 ~ ~ ~ ~"
#define RPLTEST_WKSTALINE   "~ VLADIMV7 N ~ ~ ~ ~ ~ ~ ,,, ~ ~ ~ d5elnk2 ~ ~ ~ ~"
#define RPLTEST_WKSTALINE   "~ VLADIMV7 N ~ ~ ~ ~ ~ ~ ,,, ~ ~ ~ ~ ~ ~ ~ ~"
#define RPLTEST_WKSTALINE   "~ VLADIMV7 N ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~"
Field                        1 2        3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8

More changes:
    Client side software RPLBOOT.SYS has been changed to receive value for
    TCPIP_NO_DHCP macro in Field 13 above.  Sending value 1 will disable DHCP
    on the client.  Sending value 0 will enable DCHP on the client.  But the
    value of this field matters only if TCPIP is enabled for this client by
    appropriate changes in boot block configuration file, config.sys and
    autoexec.bat that this client uses.
--*/
{
#define BLANK_FIELD                 "~ "
#define COMMON_FIELD_LENGTH          2 // except for WkstaName & TcpIp strings
#define MAX_TCPIP_ADDRESS_LENGTH    15

    CHAR    Buffer[ 14 * COMMON_FIELD_LENGTH + MAX_COMPUTERNAME_LENGTH + 1
        + 3 * (MAX_TCPIP_ADDRESS_LENGTH + 1) + 1];
    DWORD   Length;
    DWORD   ByteCount;
    DWORD   Index;

    //
    //  Field 1:
    //
    Length  = FillString( Buffer, BLANK_FIELD);

    //
    //  Field 2:
    //
    ByteCount = WideCharToMultiByte(    //  this counts the terminal null byte
             CP_OEMCP,
             0,
             pWorkerData->WkstaName,
             -1,                            //  WkstaName is null terminated
             Buffer + Length,               //  output buffer
             MAX_COMPUTERNAME_LENGTH + 1,   //  output buffer size
             NULL,                          //  no default character
             NULL                           //  no default character flag
             );
    if ( ByteCount == 0) {
        RplDump( ++RG_Assert, ("Error=%d", GetLastError()));
        pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName;
        pWorkerData->EventId = NELOG_RplWkstaInternal;
        return( FALSE);
    }
    Length += ByteCount - 1;
    Buffer[ Length++] = ' ';

    //
    //  Field 3:
    //
    Buffer[ Length++] = (char)pWorkerData->LogonInput;
    Buffer[ Length++] = ' ';

    //
    //  Fields 4-12:
    //
    for ( Index = 4; Index <= 12;  Index++) {
        Length += FillString( Buffer + Length, BLANK_FIELD);
    }

    //
    //  Field 13:
    //
    Buffer[ Length++] = pWorkerData->DisableDhcp;
    Buffer[ Length++] = ' ';

    //
    //  Fields 14-15:
    //
    for ( Index = 14; Index <= 15;  Index++) {
        Length += FillString( Buffer + Length, BLANK_FIELD);
    }

    Length += FillTcpIpString( Buffer + Length, pWorkerData->TcpIpAddress);
    Length += FillTcpIpString( Buffer + Length, pWorkerData->TcpIpSubnet);
    Length += FillTcpIpString( Buffer + Length, pWorkerData->TcpIpGateway);

    Buffer[ --Length] = 0;   // overwrite last space

//#define RPL_ELNK
#ifdef RPL_ELNK
    if ( !wcscmp( pWorkerData->pRcb->AdapterName, L"02608C0A9B37")) {
        strcpy( Buffer, "02608C0A9B37 ELNK N fits\\dos500 VLADIMV3 S ~ ~ ~ ,,, ~ RDOSL ~ DOS500L ~ ~ ~ ~ ");
        Length = strlen( Buffer);
    }
#endif

    pWorkerData->WkstaLine = RplMemAlloc( pWorkerData->MemoryHandle, Length + 1);
    if ( pWorkerData->WkstaLine == NULL) {
        pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName;
        pWorkerData->EventId = NELOG_RplWkstaMemory;
        return( FALSE);
    }
    memcpy( pWorkerData->WkstaLine, Buffer, Length + 1);
    *pWkstaLineSize = Length + 1;
    return( TRUE);
}


BOOL RplMakeWkstaBuf( IN OUT PRPL_WORKER_DATA pWorkerData)
/*++

Routine Description:

    Procedure allocates and initializes bblock header and wksta specific
    data.  pWorkerData->wksta_buf will be set to point to this buffer.

    Procedure:
     - allocates and shrinks the file index table
     - setup the boot block header and saves its static parameters
     - makes the file list table and saves the parameters of DOS EXE/SYS/COMs
     - builds the boot data for RPL MFSD
     - fixes up the 32 bits physical boot block base and file block base addr
     - copies and binds the resource table to the memory
     - binds the files in the files list to the PC memory

Arguments:

Return Value:
    TRUE if successful.
    FALSE if unsuccessful (then we usually set termination event also).

--*/
{
    DWORD           index;
    PBOOT_DATA      pBootData;          //  ptr to boot data structure used by RPL MFSD
    PRESOURCE_TBL   resource_tbl;       //  OS2LDR parameters
    PBOOT_BLOCK_HDR pBBH;               //  ptr to boot block header
    DWORD           wbuf_i;             //  running offset from boot block header
    PBYTE           pBuf;               //  a misc string
    DWORD           resource_tbl_len;   //
    DWORD           WkstaLineSize;      //  for old style rpl.map wksta line
    PBYTE           wksta_buf;          //  space for the wksta specific data
    DWORD           wksta_buf_len;      //  length of wksta specific data
    DWORD           offData;
    DWORD           cbBootDataSize;
    //
    //  boot_block_base is offset to the boottom of the lowest file in memory
    //
    DWORD           boot_block_base = pWorkerData->boot_block_base;
    DWORD           file_block_base = pWorkerData->file_block_base;
    PFLIST_TBL      pFlistTbl       = pWorkerData->flist_tbl;
    DWORD           lenFlistTbl     = pWorkerData->flist_tbl_len;

    RplDump( RG_DebugLevel & RPL_DEBUG_FLOW,( "++MakeWkstaBuf(0x%x", pWorkerData));

    if ( !RplFitFile( pWorkerData)) {
        return( FALSE);
    }

    //
    //  Clients still expect old style (rpl.map) wksta line.
    //
    if ( !RplCreateWkstaLine( pWorkerData, &WkstaLineSize)) {
        return( FALSE);
    }

    cbBootDataSize =
        sizeof(BOOT_DATA) +             //  size of RPL MiniFSD parameters
        WkstaLineSize +                 //  wksta record size, DBCS data
        pWorkerData->ClientFitSize +    //  FIT file image size, DBCS data
#ifdef RPL_ELNK
#define RPL_ELNK_7_SPACES   "       "
        sizeof( RPL_ELNK_7_SPACES) +    //  Pad with spaces after wksta line.
        1 +                             //  Include 0x1A at the end of fit file.
#endif
        RG_CodePageSize;                //  code page size

    wksta_buf_len =
        cbBootDataSize +
        pWorkerData->min_wksta_buf +
        sizeof(BOOT_BLOCK_HDR) +        // size of standard header structure
        PATHLEN + 1 +                   // space for UNC name of DOS FAT hdr
        MAX_WKSTA_PROFILES * PROF_DATA_SIZE; // max size of multiboot data


    if ( wksta_buf_len > MAX_WKSTA_BUF) {
        RplDump( ++RG_Assert, ( "wksta_buf_len=%d", wksta_buf_len));
        pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName;
        pWorkerData->EventStrings[ 1] = pWorkerData->BbcFile;
        pWorkerData->EventId = NELOG_Files_Dont_Fit;
        return( FALSE);
    }

    //
    //  allocate wksta specific data, set the header base pointer and
    //  the base offset of dynamic data (wbuf_i)
    //

    //  DbgUserBreakPoint();    // for debugging

    pBBH = RplMemAlloc( pWorkerData->MemoryHandle, wksta_buf_len );
    if( pBBH == NULL) {
        pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName;
        pWorkerData->EventId = NELOG_RplWkstaMemory;
        return( FALSE);
    }

    wksta_buf = (PBYTE)pBBH;
    memset( wksta_buf, 0, wksta_buf_len);
    wbuf_i = sizeof(BOOT_BLOCK_HDR) + (lenFlistTbl - 1) * sizeof(FILE_DATA);
    //
    //  "id_stamp" is the first byte of boot block sent to the client
    //
    pBBH->id_stamp = 0x18cd;            // reboot with int 18, if called
    pBBH->usInfoLevel = 1;              // version number of boot block
    pBBH->file_list_len = (BYTE)lenFlistTbl;

    //
    //  Copy the file names and parameters of the files in the boot block.
    //

    for (  index = 0;  index < lenFlistTbl;  index++) {

        pBBH->aFileData[ index] = pFlistTbl[ index].FileData;
        //
        //  Copy the file names that were saved in pFlistTbl element.
        //
        pBBH->aFileData[ index].name_offset = (WORD)wbuf_i;

        memcpy( wksta_buf + wbuf_i, pFlistTbl[ index].DbcsFileName, pFlistTbl[ index].DbcsFileNameSize);
        wbuf_i += pFlistTbl[ index].DbcsFileNameSize;

        //  Copy data from Boot Block Configuration file.

        pBBH->aFileData[ index].param_offset = (WORD)wbuf_i;

        //
        // exe/com/sys files must have MS-DOS parameter format
        //
        if ((pFlistTbl[ index].FileData.file_type & OTHER_FILES_MASK) == 0) {
            //
            //  Get length of EXE/SYS/COM DOS parameters.
            //
            BYTE    length = pFlistTbl[ index].FileData.param_len;

            if ( length) {
                wksta_buf[ wbuf_i++] = (BYTE)( length + 1);
                wksta_buf[ wbuf_i++] = ' ';     // space before params
                memcpy( wksta_buf + wbuf_i, pFlistTbl[ index].param_list, length);
                wbuf_i += length;
                wksta_buf[ wbuf_i++] = 0xD;
                wksta_buf[ wbuf_i++] = 0xA;
                wksta_buf[ wbuf_i++] = 0;     // null terminated
                pBBH->aFileData[ index].param_len = (BYTE)( length + 4);
            } else {
                wksta_buf[ wbuf_i++] = 0;
                if ( pFlistTbl[ index].FileData.file_type & IS_EXECUTABLE_FILE) {
                    //
                    //  For device drivers with no parameters, the parameter
                    //  line is terminated by 0xA not 0xD,0xA
                    //  BUGBUG Should param_len for them below be 2 instead of 3 ?
                    //
                    wksta_buf[ wbuf_i++] = 0xD;
                }
                wksta_buf[ wbuf_i++] = 0xA;
                wksta_buf[ wbuf_i++] = 0;     // null terminated
                pBBH->aFileData[ index].param_len = 3;
            }
        }
    }

    //
    //  Set up the resource table.  Here we copy data that describes the
    //  loader line in Boot Block Configuration file.
    //
    resource_tbl = (PRESOURCE_TBL)(wksta_buf + wbuf_i);
    pBBH->offResourceTbl = (WORD)wbuf_i;
    pBBH->cbResourceTbl = (WORD)pWorkerData->resource_tbl_size;
    wbuf_i += pWorkerData->resource_tbl_size;
    memcpy( resource_tbl, pWorkerData->resource_tbl, pWorkerData->resource_tbl_size);

    //
    //  Round up the boot data offset (resource table format requires it).
    //
    wbuf_i = (wbuf_i + 15) & 0xfff0;
    pBBH->offBootData = (WORD)wbuf_i;
    pBootData = (PBOOT_DATA)(wksta_buf + wbuf_i);
    pBootData->cbSize = (WORD)cbBootDataSize; // alignment OK
    pBuf = wksta_buf + wbuf_i;

    //  offData will be used to walk & copy data structures mentioned
    //  in cbBootDataSize formula above.

    offData =  sizeof( BOOT_DATA); // initialize

    //
    //  Copy the wksta record line from RPL.map (dbcs string).
    //
    strcpy( pBuf + offData, pWorkerData->WkstaLine);

    pBootData->offWkstaLine = (WORD)offData;
    pBootData->cbWkstaLine = (WORD)WkstaLineSize;
    pBBH->offRplWkstaLine = (WORD)(wbuf_i + offData);
    offData += WkstaLineSize;

#ifdef RPL_ELNK
    //
    //  Pad with spaces after wksta line.
    //
    memcpy( pBuf + offData, RPL_ELNK_7_SPACES, sizeof( RPL_ELNK_7_SPACES));
    offData += sizeof( RPL_ELNK_7_SPACES);
    pBootData->cbWkstaLine += sizeof( RPL_ELNK_7_SPACES);
#endif

    //  Copy the FIT file image.

    memcpy( pBuf + offData, pWorkerData->ClientFit, pWorkerData->ClientFitSize);
    pBootData->offFit = (WORD)offData;
    pBootData->cbFit = (WORD)pWorkerData->ClientFitSize;
    offData += pWorkerData->ClientFitSize;
#ifdef RPL_ELNK
    //
    //  Append 0x1A at the end of fit file.
    //
    *( pBuf + offData - 1) = 0x1A;
    *( pBuf + offData) = 0;
    offData++;
    pBootData->cbFit++;
#endif

    //  Copy the code page.

    memcpy( pBuf + offData, RG_CodePageBuffer, RG_CodePageSize);
    pBootData->cbCodePage = (WORD)RG_CodePageSize;
    pBootData->offCodePage = (WORD)offData;

    wbuf_i += cbBootDataSize;
    pBBH->offMBootData = (WORD)wbuf_i;

    //
    //  Send no multiboot data - i.e. send NULL multiboot data by setting the
    //  size field of the first record to zero.

#ifdef RPL_ELNK
    if ( !wcscmp( pWorkerData->pRcb->AdapterName, L"02608C0A9B37")) {
        MBOOTDATA UNALIGNED * pMbootData = (wksta_buf + wbuf_i);
        pMbootData->cbSize = 0x2a;
        strcpy( pMbootData->achProfile, "DOS500L");
        strcpy( pMbootData->achProfileComment, "DOS 5.00 3Com Etherlink");
        wbuf_i += 0x2a;
        wbuf_i++;   //  or RPLBOOT.SYS would begin at 24e
    } else {
        *(WORD UNALIGNED *)(wksta_buf + wbuf_i) = 0;
        wbuf_i += sizeof(WORD);
    }
#else
    *(WORD UNALIGNED *)(wksta_buf + wbuf_i) = 0;
    wbuf_i += sizeof(WORD);
#endif


    //
    //  DON'T SAVE ANY MORE DATA TO WKSTA BUFFER, WE MAY BE OUT OF MEMORY
    //  (do it before RplBuildMultiBootData)
    //

    //
    //  Set up the final size.
    //
    wksta_buf_len = (wbuf_i + 15) & 0xfff0;
    pBBH->cbSize = (WORD)wksta_buf_len;

    //
    //  FIX UP AND CHECK THE BOOT BLOCK TO THE WORKSTATION MEMORY !!!
    //  get the base address of the file list and boot block
    //

    if ( file_block_base == 0) {

        //  no ORG type line in BB.CFG file

        if (boot_block_base == 0) {

            //  no BASE type line in BB.CFG file

            boot_block_base = MIN_BBLOCK_BASE;
        }
        file_block_base = boot_block_base + wksta_buf_len;

    } else if (boot_block_base == 0) {

        boot_block_base = file_block_base - wksta_buf_len;
    }

    //  Verify that the boot block is valid:
    //  - there must be space for wksta specific data in the boot block
    //  - boot block base must be above or equal the minimum value

    if ( file_block_base < boot_block_base + wksta_buf_len
                || boot_block_base < MIN_BBLOCK_BASE) {
        RplDump( ++RG_Assert, (
            "file_block_base=%d boot_block_base=%d wksta_buf_len=%d",
            file_block_base, boot_block_base, wksta_buf_len));
        pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName;
        pWorkerData->EventStrings[ 1] = pWorkerData->BbcFile;
        pWorkerData->EventId = NELOG_Files_Dont_Fit;
        return( FALSE);
    }

    //
    //  Get the resource table pointer (table is in wksta specific data),
    // decrement length, because BootData is not included

    if ( pWorkerData->loader_i != INVALID_FILE_OFFSET) {

        // locate segments of resource table

        resource_tbl_len = resource_tbl->entries - 1;
        for ( index = 0; index < resource_tbl_len; index++) {

            resource_tbl->file_tbl[ index].pos_in_paras
                                        += PHYS_TO_PARA( file_block_base);
        }

        // the boot data must be in the resource table,

        resource_tbl->file_tbl[ index].pos_in_paras
                        = PHYS_TO_PARA( boot_block_base + pBBH->offBootData);
        resource_tbl->file_tbl[ index].file_len = cbBootDataSize;
    }

    // locate the boot block files to the PC memory

    for ( index = 0; index < lenFlistTbl; index++) {
        pBBH->aFileData[ index].file_addr += file_block_base;
    }

    //
    //  Do not bother to reallocate wksta_buf to its new smaller size.
    //  This would be a waste of time since wksta_buf will be freed
    //  when we are done with booting this client.
    //

    pWorkerData->wksta_buf = wksta_buf;
    pWorkerData->wksta_buf_len = (WORD)wksta_buf_len;

    //
    //  get file block base offset relative from the base of the boot block
    //

    pWorkerData->fblock_base_offset = file_block_base - boot_block_base;

    pWorkerData->base_address = boot_block_base;
    pWorkerData->jump_address = pBBH->aFileData[pWorkerData->rplboot_i].file_addr;

    RplDump( RG_DebugLevel & RPL_DEBUG_FLOW,( "--MakeWkstaBuf(0x%x", pWorkerData));
    return( TRUE);

} // RplMakeWkstaBuf



BOOL RplOpenData( IN OUT PRPL_WORKER_DATA pWorkerData)
/*++

Routine Description:
    Opens rpl.map data for reading by a workstation thread.

Arguments:
    pWorkerData     -       worker data

Return Value:
    TRUE if success, else FALSE.

--*/
{
    RplDump( RG_DebugLevel & RPL_DEBUG_FLOW,( "++OpenData(0x%x", pWorkerData));

    //
    //  Retrive wksta database info.
    //
    if ( !RplWorkerFillWksta( pWorkerData)) {
        if ( pWorkerData->EventId == NO_ERROR) {
            pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName;
            pWorkerData->EventId = NERR_RplWkstaInfoCorrupted;
        }
        return( FALSE);
    }

    //
    //  Process boot block configuration file.
    //
    if ( !RplBbcFile( pWorkerData)) {
        return( FALSE);
    }

    //
    //  Make wksta specific data buffer.
    //
    if ( !RplMakeWkstaBuf( pWorkerData)) {
        return( FALSE);
    }

    //
    //  Initialize file list table (includes all downloaded files)
    //

    pWorkerData->pDataBuffer = NULL;
    pWorkerData->cur_flist_i = 0;
    pWorkerData->cur_offset = INVALID_FILE_OFFSET;
    pWorkerData->cur_file_base_offset = INVALID_FILE_OFFSET;
    pWorkerData->is_end_of_bblock = FALSE;
    pWorkerData->hFile = INVALID_HANDLE_VALUE;

    RplDump( RG_DebugLevel & RPL_DEBUG_FLOW,( "--OpenData(0x%x", pWorkerData));
    return( TRUE);
}