summaryrefslogtreecommitdiffstats
path: root/private/nw/nw16
diff options
context:
space:
mode:
Diffstat (limited to 'private/nw/nw16')
-rw-r--r--private/nw/nw16/dirs23
-rw-r--r--private/nw/nw16/dll/debug.c584
-rw-r--r--private/nw/nw16/dll/locks.c677
-rw-r--r--private/nw/nw16/dll/makefile6
-rw-r--r--private/nw/nw16/dll/ncp.c3383
-rw-r--r--private/nw/nw16/dll/nwapi16.rc12
-rw-r--r--private/nw/nw16/dll/nwapi16.src10
-rw-r--r--private/nw/nw16/dll/procs.h159
-rw-r--r--private/nw/nw16/dll/sources71
-rw-r--r--private/nw/nw16/drv/dllentry.asm81
-rw-r--r--private/nw/nw16/drv/ints.asm368
-rw-r--r--private/nw/nw16/drv/makefile127
-rw-r--r--private/nw/nw16/drv/netware.def21
-rw-r--r--private/nw/nw16/drv/netware.h61
-rw-r--r--private/nw/nw16/drv/nwasmutl.asm70
-rw-r--r--private/nw/nw16/drv/nwerror.h46
-rw-r--r--private/nw/nw16/drv/nwinit.c81
-rw-r--r--private/nw/nw16/inc/makefile34
-rw-r--r--private/nw/nw16/inc/nwdos.h220
-rw-r--r--private/nw/nw16/tsr/asmmacro.inc343
-rw-r--r--private/nw/nw16/tsr/debugmac.inc356
-rw-r--r--private/nw/nw16/tsr/makefile192
-rw-r--r--private/nw/nw16/tsr/nw16.asm517
-rw-r--r--private/nw/nw16/tsr/resident.asm1039
-rw-r--r--private/nw/nw16/tsr/segorder.inc113
25 files changed, 8594 insertions, 0 deletions
diff --git a/private/nw/nw16/dirs b/private/nw/nw16/dirs
new file mode 100644
index 000000000..5c948bcc1
--- /dev/null
+++ b/private/nw/nw16/dirs
@@ -0,0 +1,23 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+ Steve Wood (stevewo) 17-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS= dll
diff --git a/private/nw/nw16/dll/debug.c b/private/nw/nw16/dll/debug.c
new file mode 100644
index 000000000..886acd75d
--- /dev/null
+++ b/private/nw/nw16/dll/debug.c
@@ -0,0 +1,584 @@
+/*++
+
+Copyright (c) 1991-3 Microsoft Corporation
+
+Module Name:
+
+ debug.c
+
+Abstract:
+
+ This component of netbios runs in the user process and can ( when
+ built in a debug kernel) will log to either the console or through the
+ kernel debugger.
+
+Author:
+
+ Colin Watson (ColinW) 24-Jun-91
+
+Revision History:
+
+--*/
+
+#include "procs.h"
+
+#if NWDBG
+
+//
+// Set DebugControl to 1 to open the logfile on the first NW call and close it
+// on process exit.
+//
+
+int DebugCtrl = 0;
+
+BOOL UseConsole = FALSE;
+BOOL UseLogFile = FALSE;
+BOOL Verbose = FALSE;
+
+HANDLE LogFile = INVALID_HANDLE_VALUE;
+#define LOGNAME (LPTSTR) TEXT("c:\\nwapi16.log")
+
+LONG NwMaxDump = SERVERNAME_LENGTH * MC; //128;
+
+#define ERR_BUF_SIZE 260
+#define NAME_BUF_SIZE 260
+
+extern UCHAR CpuInProtectMode;
+
+LPSTR
+ConvertFlagsToString(
+ IN WORD FlagsRegister,
+ OUT LPSTR Buffer
+ );
+
+WORD
+GetFlags(
+ VOID
+ );
+
+VOID
+HexDumpLine(
+ PCHAR pch,
+ ULONG len,
+ PCHAR s,
+ PCHAR t
+ );
+
+VOID
+DebugControl(
+ int Command
+ )
+/*++
+
+Routine Description:
+
+ This routine controls what we output as debug information and where.
+
+Arguments:
+
+ IN int Command
+
+Return Value:
+
+ none.
+
+--*/
+{
+
+ switch (Command) {
+ case 0:
+ UseLogFile = TRUE;
+ break;
+
+ case 1:
+ UseConsole = TRUE;
+ break;
+
+ case 2:
+ if (LogFile != INVALID_HANDLE_VALUE) {
+ CloseHandle(LogFile);
+ LogFile = INVALID_HANDLE_VALUE;
+ }
+ UseLogFile = FALSE;
+ UseConsole = FALSE;
+ break;
+
+ case 8:
+ Verbose = TRUE; // Same as 4 only chatty
+ DebugCtrl = 4;
+
+ case 4:
+ UseLogFile = TRUE;
+ break;
+
+ }
+ NwPrint(("DebugControl %x\n", Command ));
+}
+
+VOID
+NwPrintf(
+ char *Format,
+ ...
+ )
+/*++
+
+Routine Description:
+
+ This routine is equivalent to printf with the output being directed to
+ stdout.
+
+Arguments:
+
+ IN char *Format - Supplies string to be output and describes following
+ (optional) parameters.
+
+Return Value:
+
+ none.
+
+--*/
+{
+ va_list arglist;
+ char OutputBuffer[200];
+ int length;
+
+ if (( UseConsole == FALSE ) &&
+ ( UseLogFile == FALSE )) {
+ return;
+ }
+
+
+ va_start( arglist, Format );
+
+ length = _vsnprintf( OutputBuffer, sizeof(OutputBuffer)-1, Format, arglist );
+ if (length < 0) {
+ return;
+ }
+
+ OutputBuffer[sizeof(OutputBuffer)-1] = '\0'; // in-case length= 199;
+
+ va_end( arglist );
+
+ if ( UseConsole ) {
+ DbgPrint( "%s", OutputBuffer );
+ } else {
+
+ if ( LogFile == INVALID_HANDLE_VALUE ) {
+ if ( UseLogFile ) {
+ LogFile = CreateFile( LOGNAME,
+ GENERIC_WRITE,
+ FILE_SHARE_WRITE | FILE_SHARE_READ,
+ NULL,
+ TRUNCATE_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL );
+
+ if (LogFile == INVALID_HANDLE_VALUE) {
+ LogFile = CreateFile( LOGNAME,
+ GENERIC_WRITE,
+ FILE_SHARE_WRITE | FILE_SHARE_READ,
+ NULL,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL );
+ }
+
+ if ( LogFile == INVALID_HANDLE_VALUE ) {
+ UseLogFile = FALSE;
+ return;
+ }
+ }
+ }
+
+ WriteFile( LogFile , (LPVOID )OutputBuffer, length, &length, NULL );
+ }
+
+} // NwPrintf
+
+void
+FormattedDump(
+ PCHAR far_p,
+ LONG len
+ )
+/*++
+
+Routine Description:
+
+ This routine outputs a buffer in lines of text containing hex and
+ printable characters.
+
+Arguments:
+
+ IN far_p - Supplies buffer to be displayed.
+ IN len - Supplies the length of the buffer in bytes.
+
+Return Value:
+
+ none.
+
+--*/
+{
+ ULONG l;
+ char s[80], t[80];
+
+ if (( UseConsole == FALSE ) &&
+ ( UseLogFile == FALSE )) {
+ return;
+ }
+
+ if (( len > NwMaxDump ) ||
+ ( len < 0 )) {
+ len = NwMaxDump;
+ }
+
+ while (len) {
+ l = len < 16 ? len : 16;
+
+ NwPrint(("%lx ", far_p));
+ HexDumpLine (far_p, l, s, t);
+ NwPrint(("%s%.*s%s\n", s, 1 + ((16 - l) * 3), "", t));
+
+ len -= l;
+ far_p += l;
+ }
+}
+
+VOID
+HexDumpLine(
+ PCHAR pch,
+ ULONG len,
+ PCHAR s,
+ PCHAR t
+ )
+/*++
+
+Routine Description:
+
+ This routine builds a line of text containing hex and printable characters.
+
+Arguments:
+
+ IN pch - Supplies buffer to be displayed.
+ IN len - Supplies the length of the buffer in bytes.
+ IN s - Supplies the start of the buffer to be loaded with the string
+ of hex characters.
+ IN t - Supplies the start of the buffer to be loaded with the string
+ of printable ascii characters.
+
+
+Return Value:
+
+ none.
+
+--*/
+{
+ static UCHAR rghex[] = "0123456789ABCDEF";
+
+ UCHAR c;
+ UCHAR *hex, *asc;
+
+
+ hex = s;
+ asc = t;
+
+ *(asc++) = '*';
+ while (len--) {
+ c = *(pch++);
+ *(hex++) = rghex [c >> 4] ;
+ *(hex++) = rghex [c & 0x0F];
+ *(hex++) = ' ';
+ *(asc++) = (c < ' ' || c > '~') ? (CHAR )'.' : c;
+ }
+ *(asc++) = '*';
+ *asc = 0;
+ *hex = 0;
+
+}
+
+
+VOID
+DisplayExtendedError(VOID)
+{
+ TCHAR errorBuf[ERR_BUF_SIZE];
+ TCHAR nameBuf[NAME_BUF_SIZE];
+ DWORD errorCode;
+ DWORD status;
+
+ status = WNetGetLastError(
+ &errorCode,
+ errorBuf,
+ ERR_BUF_SIZE,
+ nameBuf,
+ NAME_BUF_SIZE);
+
+ if(status != WN_SUCCESS) {
+ NwPrint(("nwapi32: WNetGetLastError failed %d\n",status));
+ return;
+ }
+ NwPrint(("nwapi32: EXTENDED ERROR INFORMATION: (from GetLastError)\n"));
+ NwPrint(("nwapi32: Code: %d\n",errorCode));
+ NwPrint(("nwapi32: Description: "FORMAT_LPSTR"\n",errorBuf));
+ NwPrint(("nwapi32: Provider: "FORMAT_LPSTR"\n\n",nameBuf));
+ return;
+}
+
+VOID
+VrDumpRealMode16BitRegisters(
+ IN BOOL DebugStyle
+ )
+
+/*++
+
+Routine Description:
+
+ Displays dump of 16-bit
+ real-mode 80286 registers - gp registers (8), segment registers (4), flags
+ register (1) instruction pointer register (1)
+
+Arguments:
+
+ DebugStyle - determines look of output:
+
+DebugStyle == TRUE:
+
+ax=1111 bx=2222 cx=3333 dx=4444 sp=5555 bp=6666 si=7777 di=8888
+ds=aaaa es=bbbb ss=cccc cs=dddd ip=iiii fl fl fl fl fl fl fl fl
+
+DebugStyle == FALSE:
+
+cs:ip=cccc:iiii ss:sp=ssss:pppp bp=bbbb ax=1111 bx=2222 cx=3333 dx=4444
+ds:si=dddd:ssss es:di=eeee:dddd flags[ODIxSZxAxPxC]=fl fl fl fl fl fl fl fl
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ char flags_string[25];
+
+ if (( UseConsole == FALSE ) &&
+ ( UseLogFile == FALSE )) {
+ return;
+ }
+
+ if (CpuInProtectMode) {
+ NwPrint(( "Protect Mode:\n"));
+ }
+
+ if (DebugStyle) {
+ NwPrint((
+ "ax=%04x bx=%04x cx=%04x dx=%04x sp=%04x bp=%04x si=%04x di=%04x\n"
+ "ds=%04x es=%04x ss=%04x cs=%04x ip=%04x %s\n\n",
+
+ pNwDosTable->SavedAx, //getAX(),
+ getBX(),
+ getCX(),
+ getDX(),
+ getSP(),
+ getBP(),
+ getSI(),
+ getDI(),
+ getDS(),
+ getES(),
+ getSS(),
+ getCS(),
+ getIP(),
+ ConvertFlagsToString(GetFlags(), flags_string)
+ ));
+ } else {
+ NwPrint((
+ "cs:ip=%04x:%04x ss:sp=%04x:%04x bp=%04x ax=%04x bx=%04x cx=%04x dx=%04x\n"
+ "ds:si=%04x:%04x es:di=%04x:%04x flags[ODITSZxAxPxC]=%s\n\n",
+ getCS(),
+ getIP(),
+ getSS(),
+ getSP(),
+ getBP(),
+ pNwDosTable->SavedAx, //getAX(),
+ getBX(),
+ getCX(),
+ getDX(),
+ getDS(),
+ getSI(),
+ getES(),
+ getDI(),
+ ConvertFlagsToString(GetFlags(), flags_string)
+ ));
+ }
+}
+
+LPSTR
+ConvertFlagsToString(
+ IN WORD FlagsRegister,
+ OUT LPSTR Buffer
+ )
+
+/*++
+
+Routine Description:
+
+ Given a 16-bit word, interpret bit positions as for x86 Flags register
+ and produce descriptive string of flags state (as per debug) eg:
+
+ NV UP DI PL NZ NA PO NC ODItSZxAxPxC = 000000000000b
+ OV DN EI NG ZR AC PE CY ODItSZxAxPxC = 111111111111b
+
+ Trap Flag (t) is not dumped since this has no interest for programs which
+ are not debuggers or don't examine program execution (ie virtually none)
+
+Arguments:
+
+ FlagsRegister - 16-bit flags
+ Buffer - place to store string. Requires 25 bytes inc \0
+
+Return Value:
+
+ Address of <Buffer>
+
+--*/
+
+{
+ static char* flags_states[16][2] = {
+ //0 1
+ "NC", "CY", // CF (0x0001) - Carry
+ "", "", // x (0x0002)
+ "PO", "PE", // PF (0x0004) - Parity
+ "", "", // x (0x0008)
+ "NA", "AC", // AF (0x0010) - Aux (half) carry
+ "", "", // x (0x0020)
+ "NZ", "ZR", // ZF (0x0040) - Zero
+ "PL", "NG", // SF (0x0080) - Sign
+ "", "", // TF (0x0100) - Trap (not dumped)
+ "DI", "EI", // IF (0x0200) - Interrupt
+ "UP", "DN", // DF (0x0400) - Direction
+ "NV", "OV", // OF (0x0800) - Overflow
+ "", "", // x (0x1000) - (I/O Privilege Level) (not dumped)
+ "", "", // x (0x2000) - (I/O Privilege Level) (not dumped)
+ "", "", // x (0x4000) - (Nested Task) (not dumped)
+ "", "" // x (0x8000)
+ };
+ int i;
+ WORD bit;
+ BOOL on;
+
+ *Buffer = 0;
+ for (bit=0x0800, i=11; bit; bit >>= 1, --i) {
+ on = (BOOL)((FlagsRegister & bit) == bit);
+ if (flags_states[i][on][0]) {
+ strcat(Buffer, flags_states[i][on]);
+ strcat(Buffer, " ");
+ }
+ }
+ return Buffer;
+}
+
+WORD
+GetFlags(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Supplies the missing softpc function
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Conglomerates softpc flags into x86 flags word
+
+--*/
+
+{
+ WORD flags;
+
+ flags = (WORD)getCF();
+ flags |= (WORD)getPF() << 2;
+ flags |= (WORD)getAF() << 4;
+ flags |= (WORD)getZF() << 6;
+ flags |= (WORD)getSF() << 7;
+ flags |= (WORD)getIF() << 9;
+ flags |= (WORD)getDF() << 10;
+ flags |= (WORD)getOF() << 11;
+
+ return flags;
+}
+
+VOID
+VrDumpNwData(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Dumps out the state of the 16 bit datastructures.
+
+Arguments:
+
+ none.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ int index;
+ int Drive;
+
+ if (Verbose == FALSE) {
+ return;
+ }
+
+ NwPrint(( "Preferred = %x, Primary = %x\n",
+ pNwDosTable->PreferredServer,
+ pNwDosTable->PrimaryServer));
+
+ for (index = 0; index < MC; index++) {
+
+
+ if ((PUCHAR)pNwDosTable->ServerNameTable[index][0] != 0 ) {
+
+ if (pNwDosTable->ConnectionIdTable[index].ci_InUse != IN_USE) {
+ NwPrint(("Warning Connection not in use %x: %x\n",
+ index,
+ pNwDosTable->ConnectionIdTable[index].ci_InUse));
+ }
+
+ NwPrint((" Server %d = %s, Connection = %d\n",
+ index,
+ (PUCHAR)pNwDosTable-> ServerNameTable[index],
+ (((pNwDosTable->ConnectionIdTable[index]).ci_ConnectionHi * 256) +
+ ( pNwDosTable-> ConnectionIdTable[index]).ci_ConnectionLo )));
+ } else {
+ if (pNwDosTable->ConnectionIdTable[index].ci_InUse != FREE) {
+ NwPrint(("Warning Connection in use but name is null %x: %x\n",
+ index,
+ pNwDosTable->ConnectionIdTable[index]));
+ }
+ }
+ }
+
+ for (Drive = 0; Drive < MD; Drive++ ) {
+
+
+ if (pNwDosTable->DriveFlagTable[Drive] & 3) {
+ NwPrint(("%c=%x on server %d,",'A' + Drive,
+ pNwDosTable->DriveFlagTable[Drive],
+ pNwDosTable->DriveIdTable[ Drive ] ));
+ }
+
+ }
+ NwPrint(("\n"));
+}
+#endif
+
diff --git a/private/nw/nw16/dll/locks.c b/private/nw/nw16/dll/locks.c
new file mode 100644
index 000000000..f3d9ff362
--- /dev/null
+++ b/private/nw/nw16/dll/locks.c
@@ -0,0 +1,677 @@
+
+/*++
+
+Copyright (c) 1993/4 Microsoft Corporation
+
+Module Name:
+
+ Locks.c
+
+Abstract:
+
+ This module implements the routines for the NetWare
+ 16 bit support to perform the synchonization api's
+
+Author:
+
+ Colin Watson [ColinW] 07-Dec-1993
+
+Revision History:
+
+--*/
+
+#include "Procs.h"
+UCHAR LockMode = 0;
+
+BOOLEAN Tickle[MC];
+
+NTSTATUS
+Sem(
+ UCHAR Function,
+ UCHAR Connection
+ );
+
+VOID
+Locks(
+ USHORT Command
+ )
+/*++
+
+Routine Description:
+
+ Implements all the locking operations
+
+Arguments:
+
+ Command - supplies Applications AX.
+
+Return Value:
+
+ Return status.
+
+--*/
+{
+ UCHAR Function = Command & 0x00ff;
+ USHORT Operation = Command & 0xff00;
+ CONN_INDEX Connection;
+ NTSTATUS status = STATUS_SUCCESS;
+ PUCHAR Request;
+ ULONG RequestLength;
+ WORD Timeout;
+
+ if ( Operation != 0xCF00) {
+
+ //
+ // Connection does not need to be initialised for CF00 because
+ // we have to loop through all connections. Its harmful because
+ // a CF00 is created during ProcessExit(). If we call selectconnection
+ // and there is no server available this will make process exit
+ // really slow.
+ //
+
+ Connection = SelectConnection();
+ if (Connection == 0xff) {
+ setAL(0xff);
+ return;
+ }
+
+ if ( ServerHandles[Connection] == NULL ) {
+
+ status = OpenConnection( Connection );
+
+ if (!NT_SUCCESS(status)) {
+ setAL((UCHAR)RtlNtStatusToDosError(status));
+ return;
+ }
+ }
+ }
+
+ switch ( Operation ) {
+
+ case 0xBC00: // Log physical record
+
+ status = NwlibMakeNcp(
+ GET_NT_HANDLE(),
+ NWR_ANY_HANDLE_NCP(0x1A),
+ 17, // RequestSize
+ 0, // ResponseSize
+ "b_wwwww",
+ Function,
+ 6, // Leave space for NetWare handle
+ getCX(),getDX(),
+ getSI(),getDI(),
+ getBP());
+ break;
+
+ case 0xBD00: // Physical Unlock
+ status = NwlibMakeNcp(
+ GET_NT_HANDLE(),
+ NWR_ANY_HANDLE_NCP(0x1C),
+ 15, // RequestSize
+ 0, // ResponseSize
+ "b_wwww",
+ Function,
+ 6, // Leave space for NetWare handle
+ getCX(),getDX(),
+ getSI(),getDI());
+
+ break;
+
+ case 0xBE00: // Clear physical record
+
+ status = NwlibMakeNcp(
+ GET_NT_HANDLE(),
+ NWR_ANY_HANDLE_NCP(0x1E),
+ 15, // RequestSize
+ 0, // ResponseSize
+ "b_wwww",
+ Function,
+ 6, // Leave space for NetWare handle
+ getCX(),getDX(),
+ getSI(),getDI());
+
+ break;
+
+ case 0xC200: // Physical Lock set
+ status = NwlibMakeNcp(
+ ServerHandles[Connection],
+ NWR_ANY_F2_NCP(0x1B),
+ 3, // RequestSize
+ 0, // ResponseSize
+ "bw",
+ Function,
+ getBP());
+ break;
+
+ case 0xC300: // Release Physical Record Set
+ status = NwlibMakeNcp(
+ ServerHandles[Connection],
+ NWR_ANY_F2_NCP(0x1D),
+ 0, // RequestSize
+ 0, // ResponseSize
+ "");
+ break;
+
+ case 0xC400: // Clear Physical Record Set
+ status = NwlibMakeNcp(
+ ServerHandles[Connection],
+ NWR_ANY_F2_NCP(0x1F), // Clear Physical Record Set
+ 0, // RequestSize
+ 0, // ResponseSize
+ "");
+ break;
+
+ case 0xC500: // All Semaphore operations
+ status = Sem(Function, Connection);
+ break;
+
+ case 0xC600: // Set/Get Lock mode
+
+ if (Function != 2) {
+ LockMode = Function;
+ }
+
+ setAL(LockMode);
+ return; // avoid setting AL to status at the end of this routine
+ break;
+
+ case 0xCB00: // Lock File Set
+
+ if (LockMode == 0) {
+ if (getDL()) {
+ Timeout = 0xffff;
+ } else {
+ Timeout = 0;
+ }
+ } else {
+ Timeout = getBP();
+ }
+
+ for (Connection = 0; Connection < MC; Connection++) {
+ if (Tickle[Connection]) {
+ status = NwlibMakeNcp(
+ ServerHandles[Connection],
+ NWR_ANY_F2_NCP(0x04),
+ 2, // RequestSize
+ 0, // ResponseSize
+ "w",
+ Timeout);
+ if (!NT_SUCCESS(status)) {
+ break;
+ }
+ }
+ }
+ break;
+
+ case 0xCD00: // Release File Set
+ case 0xCF00: // Clear File Set
+ for (Connection = 0; Connection < MC; Connection++) {
+ if (Tickle[Connection]) {
+ status = NwlibMakeNcp(
+ ServerHandles[Connection],
+ (Operation == 0xCD00) ? NWR_ANY_F2_NCP(0x06): NWR_ANY_F2_NCP(0x08),
+ 0, // RequestSize
+ 0, // ResponseSize
+ "");
+ if (!NT_SUCCESS(status)) {
+ break;
+ }
+
+ if (Operation == 0xCF00) {
+ Tickle[Connection] = FALSE;
+ }
+ }
+ }
+
+ break;
+
+ case 0xD000: // Log Logical Record
+
+ Request = GetVDMPointer (
+ (ULONG)((getDS() << 16)|getDX()),
+ sizeof(UCHAR),
+ IS_PROTECT_MODE());
+
+ RequestLength = Request[0] + 1;
+
+ Request = GetVDMPointer (
+ (ULONG)((getDS() << 16)|getDX()),
+ RequestLength,
+ IS_PROTECT_MODE());
+
+ status = NwlibMakeNcp(
+ ServerHandles[Connection],
+ NWR_ANY_F2_NCP(0x09),
+ RequestLength + 5, // RequestSize
+ 0, // ResponseSize
+ "bwbr",
+ (LockMode) ? Function : 0,
+ (LockMode) ? getBP() : 0,
+ RequestLength,
+ Request, RequestLength );
+ break;
+
+ case 0xD100: // Lock Logical Record Set
+
+ if (LockMode == 0) {
+ if (getDL()) {
+ Timeout = 0xffff;
+ } else {
+ Timeout = 0;
+ }
+ } else {
+ Timeout = getBP();
+ }
+
+ status = NwlibMakeNcp(
+ ServerHandles[Connection],
+ NWR_ANY_F2_NCP(0x0A),
+ 3, // RequestSize
+ 0, // ResponseSize
+ "bw",
+ (LockMode) ? Function : 0,
+ Timeout);
+ break;
+
+ case 0xD200: // Release File
+ case 0xD400: // Clear Logical Record
+ Request = GetVDMPointer (
+ (ULONG)((getDS() << 16)|getDX()),
+ sizeof(UCHAR),
+ IS_PROTECT_MODE());
+
+ RequestLength = Request[0]+1;
+
+ Request = GetVDMPointer (
+ (ULONG)((getDS() << 16)|getDX()),
+ RequestLength,
+ IS_PROTECT_MODE());
+
+ status = NwlibMakeNcp(
+ ServerHandles[Connection],
+ (Operation == 0xD200) ? NWR_ANY_F2_NCP(0x0C) :
+ NWR_ANY_F2_NCP(0x0B),
+ RequestLength+1,
+ 0, // ResponseSize
+ "br",
+ RequestLength,
+ Request, RequestLength );
+ break;
+
+ case 0xD300:
+ status = NwlibMakeNcp(
+ ServerHandles[Connection],
+ NWR_ANY_F2_NCP(0x13),
+ 0, // RequestSize
+ 0, // ResponseSize
+ "");
+ break;
+
+
+ case 0xD500: // Clear Logical Record Set
+ status = NwlibMakeNcp(
+ ServerHandles[Connection],
+ NWR_ANY_F2_NCP(0x0E),
+ 0, // RequestSize
+ 0, // ResponseSize
+ "");
+ break;
+
+ case 0xEB00: // Log File
+ case 0xEC00: // Release File
+ case 0xED00: // Clear File
+ {
+ UCHAR DirHandle;
+ HANDLE Win32DirectoryHandle = 0;
+ PUCHAR ptr;
+
+ Request = GetVDMPointer (
+ (ULONG)((getDS() << 16)|getDX()),
+ 256 * sizeof(UCHAR),
+ IS_PROTECT_MODE());
+
+ RequestLength = strlen(Request);
+
+ // Find DirHandle
+ ptr = Request;
+ while ( (*ptr != 0) &&
+ (!IS_ASCII_PATH_SEPARATOR(*ptr)) &&
+ (*ptr != ':' )) {
+ ptr++;
+ }
+
+ if (IS_ASCII_PATH_SEPARATOR(*ptr)) {
+ int ServerNameLength = ptr - Request;
+ PUCHAR scanptr = ptr;
+
+ //
+ // Make sure there is a ":" further up the name otherwise
+ // we could confuse foo\bar.txt with a server called foo
+ //
+
+ while ( (*scanptr != 0) &&
+ (*scanptr != ':' )) {
+ scanptr++;
+ }
+
+ if (*scanptr) {
+ //
+ // Name is of the form server\sys:foo\bar.txt
+ // set connection appropriately.
+ //
+
+ for (Connection = 0; Connection < MC ; Connection++ ) {
+
+ //
+ // Look for server foo avoiding foobar.
+ //
+
+ if ((pNwDosTable->ConnectionIdTable[Connection].ci_InUse ==
+ IN_USE) &&
+ (!memcmp( pNwDosTable->ServerNameTable[Connection],
+ Request,
+ ServerNameLength)) &&
+ (pNwDosTable->ServerNameTable[Connection][ServerNameLength] ==
+ '\0')) {
+ break; // Connection is the correct server
+ }
+ }
+
+ //
+ // Move Request to after the seperator and ptr to the ":"
+ //
+
+ RequestLength -= ptr + sizeof(UCHAR) - Request;
+ Request = ptr + sizeof(UCHAR);
+ ptr = scanptr;
+ }
+ }
+
+ if (*ptr) {
+
+ //
+ // Name of form "sys:foo\bar.txt" this gives the server
+ // all the information required.
+ //
+
+ DirHandle = 0;
+
+ if (Request[1] == ':') {
+
+ UCHAR Drive = tolower(Request[0])-'a';
+
+ //
+ // Its a normal (redirected) drive k:foo\bar.txt.
+ // Use the drive tables to give the connection and handle.
+ //
+
+ Connection = pNwDosTable->DriveIdTable[ Drive ] - 1;
+ DirHandle = pNwDosTable->DriveHandleTable[Drive];
+
+ if (DirHandle == 0) {
+ DirHandle = (UCHAR)GetDirectoryHandle2(Drive);
+ }
+ Request += 2; // skip "k:"
+ RequestLength -= 2;
+ }
+
+ } else {
+
+ WCHAR Curdir[256];
+
+ //
+ // Name of form "foo\bar.txt"
+ //
+
+ GetCurrentDirectory(sizeof(Curdir), Curdir);
+
+ Win32DirectoryHandle =
+ CreateFileW( Curdir,
+ 0,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS,
+ 0);
+
+ if (Win32DirectoryHandle != INVALID_HANDLE_VALUE) {
+ DWORD BytesReturned;
+
+ if ( DeviceIoControl(
+ Win32DirectoryHandle,
+ IOCTL_NWR_RAW_HANDLE,
+ NULL,
+ 0,
+ (PUCHAR)&DirHandle,
+ sizeof(DirHandle),
+ &BytesReturned,
+ NULL ) == FALSE ) {
+
+ CloseHandle( Win32DirectoryHandle );
+ setAL(0xff);
+ return;
+
+ }
+
+ } else {
+
+ setAL(0xff);
+ return;
+ }
+ }
+
+ if (Operation == 0xEB00) {
+ status = NwlibMakeNcp(
+ ServerHandles[Connection],
+ NWR_ANY_F2_NCP(0x03),
+ RequestLength + 5,
+ 0, // ResponseSize
+ "bbwbr",
+ DirHandle,
+ (LockMode) ? Function : 0,
+ (LockMode) ? getBP() : 0,
+ RequestLength,
+ Request, RequestLength );
+
+ Tickle[Connection] = TRUE;
+
+ } else {
+ status = NwlibMakeNcp(
+ ServerHandles[Connection],
+ (Operation == 0xEC00 ) ?
+ NWR_ANY_F2_NCP(0x07) :
+ NWR_ANY_F2_NCP(0x05),
+ RequestLength + 2,
+ 0, // ResponseSize
+ "bbr",
+ DirHandle,
+ RequestLength,
+ Request, RequestLength );
+ }
+
+ if (Win32DirectoryHandle) {
+ CloseHandle( Win32DirectoryHandle );
+ }
+ }
+ break;
+
+ }
+
+ if (!NT_SUCCESS(status)) {
+ setAL((UCHAR)RtlNtStatusToDosError(status));
+ return;
+ } else {
+ setAL(0);
+ }
+}
+
+VOID
+InitLocks(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Reset the Tickle internal variables
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ ZeroMemory( Tickle, sizeof(Tickle));
+}
+
+VOID
+ResetLocks(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Reset the Locks for the current VDM. Called during process exit.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ Locks(0xCF00); // Clear all File sets.
+
+}
+
+NTSTATUS
+Sem(
+ UCHAR Function,
+ UCHAR Connection
+ )
+/*++
+
+Routine Description:
+
+ Build all NCPs for Semaphore support
+
+Arguments:
+
+ Function - Supplies the subfunction from AL
+
+ Connection - Supplies the server for the request
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PUCHAR Request;
+ NTSTATUS status;
+
+ switch (Function) {
+
+ UCHAR Value;
+ UCHAR OpenCount;
+ WORD HandleHigh, HandleLow;
+
+ case 0: //OpenSemaphore
+
+ Request = GetVDMPointer (
+ (ULONG)((getDS() << 16)|getDX()),
+ 256 * sizeof(UCHAR),
+ IS_PROTECT_MODE());
+
+ NwPrint(("Nw16: OpenSemaphore\n"));
+
+ status = NwlibMakeNcp(
+ ServerHandles[Connection],
+ NWR_ANY_F2_NCP(0x20),
+ Request[0] + 3, // RequestSize
+ 5, // ResponseSize
+ "bbr|wwb",
+ 0,
+ getCL(), // Semaphore Value
+ Request, Request[0] + 1,
+
+ &HandleHigh, &HandleLow,
+ &OpenCount);
+
+
+ if (NT_SUCCESS(status)) {
+ setBL(OpenCount);
+ setCX(HandleHigh);
+ setDX(HandleLow);
+ }
+
+ break;
+
+ case 1: // ExamineSemaphore
+
+ NwPrint(("Nw16: ExamineSemaphore\n"));
+ status = NwlibMakeNcp(
+ ServerHandles[Connection],
+ NWR_ANY_F2_NCP(0x20),
+ 5, // RequestSize
+ 2, // ResponseSize
+ "bww|bb",
+ 1,
+ getCX(),getDX(),
+
+ &Value,
+ &OpenCount);
+
+ if (NT_SUCCESS(status)) {
+ setCX(Value);
+ setDL(OpenCount);
+ }
+ break;
+
+ case 2: // WaitOnSemaphore
+ NwPrint(("Nw16: WaitOnSemaphore\n"));
+ status = NwlibMakeNcp(
+ ServerHandles[Connection],
+ NWR_ANY_F2_NCP(0x20),
+ 7, // RequestSize
+ 0, // ResponseSize
+ "bwww",
+ 2,
+ getCX(),getDX(),
+ getBP());
+ break;
+
+ case 3: // SignalSemaphore
+ NwPrint(("Nw16: SignalSemaphore\n"));
+ case 4: // CloseSemaphore
+
+ if (Function == 4) {
+ NwPrint(("Nw16: CloseSemaphore\n"));
+ }
+
+ status = NwlibMakeNcp( // Close and Signal
+ ServerHandles[Connection],
+ NWR_ANY_F2_NCP(0x20),
+ 5, // RequestSize
+ 0, // ResponseSize
+ "bww",
+ Function,
+ getCX(),getDX());
+ break;
+
+ default:
+ NwPrint(("Nw16: Unknown Semaphore operation %d\n", Function));
+ break;
+ }
+ return status;
+}
diff --git a/private/nw/nw16/dll/makefile b/private/nw/nw16/dll/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/nw/nw16/dll/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/nw/nw16/dll/ncp.c b/private/nw/nw16/dll/ncp.c
new file mode 100644
index 000000000..c82cca43b
--- /dev/null
+++ b/private/nw/nw16/dll/ncp.c
@@ -0,0 +1,3383 @@
+/*++
+
+Copyright (c) 1993/4 Microsoft Corporation
+
+Module Name:
+
+ ncp.c
+
+Abstract:
+
+ Contains routine which accepts the bop from a 16 bit
+ application and processes the request appropriately.
+ Normally it performes an NCP exchange on behalf of the
+ application.
+
+Author:
+
+ Colin Watson (colinw) 07-Jul-1993
+
+Environment:
+
+
+Revision History:
+
+
+--*/
+
+#include "procs.h"
+
+#define BASE_DOS_ERROR ((NTSTATUS )0xC0010000L)
+#define CLIENT_ID_STRING "MSDOS\0V5.00\0IBM_PC\0IBM"
+
+#include <packon.h>
+typedef struct _TTSOUTPACKET {
+ UCHAR SubFunction;
+ USHORT cx;
+ USHORT dx;
+} TTSOUTPACKET, *PTTSOUTPACKET ;
+
+typedef struct _TTSINPACKET{
+ USHORT cx;
+ USHORT dx;
+} TTSINPACKET, *PTTSINPACKET;
+
+#include <packoff.h>
+
+VOID
+InitDosTable(
+ PNWDOSTABLE pdt
+ );
+
+VOID
+LoadPreferredServerName(
+ VOID
+ );
+
+VOID
+ProcessResourceArray(
+ LPNETRESOURCE NetResource,
+ DWORD NumElements
+ );
+
+VOID
+ProcessResource(
+ LPNETRESOURCE NetResource
+ );
+
+VOID
+SendNCP(
+ ULONG Command
+ );
+
+VOID
+SendF2NCP(
+ ULONG Command
+ );
+
+UCHAR
+AttachmentControl(
+ ULONG Command
+ );
+
+VOID
+SendNCP2(
+ ULONG Command,
+ PUCHAR Request,
+ ULONG RequestLength,
+ PUCHAR Reply,
+ ULONG ReplyLength
+ );
+
+VOID
+CloseConnection(
+ CONN_INDEX Connection
+ );
+
+NTSTATUS
+InitConnection(
+ CONN_INDEX Connection
+ );
+
+VOID
+GetDirectoryHandle(
+ VOID
+ );
+
+VOID
+LoadDriveHandleTable(
+ VOID
+ );
+
+VOID
+AllocateDirectoryHandle(
+ VOID
+ );
+
+VOID
+ResetDrive(
+ UCHAR Drive
+ );
+
+VOID
+AllocateDirectoryHandle2(
+ VOID
+ );
+
+PWCHAR
+BuildUNC(
+ IN PUCHAR aName,
+ IN ULONG aLength
+ );
+
+VOID
+GetServerDateAndTime(
+ VOID
+ );
+
+VOID
+GetShellVersion(
+ IN USHORT Command
+ );
+
+VOID
+TTS(
+ VOID
+ );
+
+VOID
+OpenCreateFile(
+ VOID
+ );
+
+BOOL
+IsItNetWare(
+ PUCHAR Name
+ );
+
+VOID
+SetCompatibility(
+ VOID
+ );
+
+VOID
+OpenQueueFile(
+ VOID
+ );
+
+VOID
+AttachHandle(
+ VOID
+ );
+
+VOID
+ProcessExit(
+ VOID
+ );
+
+VOID
+SystemLogout(
+ VOID
+ );
+
+VOID
+ServerFileCopy(
+ VOID
+ );
+
+VOID
+SetStatus(
+ NTSTATUS Status
+ );
+
+//
+// The following pointer contains the 32 bit virtual address of where
+// the nw16.exe tsr holds the workstation structures.
+//
+
+PNWDOSTABLE pNwDosTable;
+
+//
+// Global variables used to hold the state for this process
+//
+
+UCHAR OriginalPrimary = 0;
+HANDLE ServerHandles[MC];
+
+HANDLE Win32DirectoryHandleTable[MD];
+PWCHAR Drives[MD]; // Strings such as R: or a unc name
+
+UCHAR SearchDriveTable[16];
+
+
+BOOLEAN Initialized = FALSE;
+BOOLEAN TablesValid = FALSE; // Reload each time a process starts
+BOOLEAN DriveHandleTableValid = FALSE; // Reload first time process does NW API
+
+WORD DosTableSegment;
+WORD DosTableOffset;
+
+extern UCHAR LockMode;
+
+#if NWDBG
+BOOL GotDebugState = FALSE;
+extern int DebugCtrl;
+#endif
+
+
+VOID
+Nw16Register(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This function is called by wow when nw16.sys is loaded.
+
+Arguments:
+
+
+Return Value:
+
+ None.
+
+--*/
+{
+ DWORD status;
+ HANDLE enumHandle;
+ LPNETRESOURCE netResource;
+ DWORD numElements;
+ DWORD bufferSize;
+ DWORD dwScope = RESOURCE_CONNECTED;
+
+ NwPrint(("Nw16Register\n"));
+
+ if ( !Initialized) {
+ UCHAR CurDir[256];
+ DosTableSegment = getAX();
+ DosTableOffset = getDX();
+
+ //
+ // this call always made from Real Mode (hence FALSE for last param)
+ //
+
+ pNwDosTable = (PNWDOSTABLE) GetVDMPointer (
+ (ULONG)((DosTableSegment << 16)|DosTableOffset),
+ sizeof(NWDOSTABLE),
+ FALSE
+ );
+
+ InitDosTable( pNwDosTable );
+
+ if ((GetCurrentDirectoryA(sizeof(CurDir)-1, CurDir) >= 2) &&
+ (CurDir[1] = ':')) {
+ pNwDosTable->CurrentDrive = tolower(CurDir[0]) - 'a';
+ }
+
+ InitLocks();
+ }
+
+
+#if NWDBG
+ {
+ WCHAR Value[80];
+
+ if (GetEnvironmentVariableW(L"NWDEBUG",
+ Value,
+ sizeof(Value)/sizeof(Value[0]) - 1)) {
+
+ DebugCtrl = Value[0] - '0';
+
+ // 0 Use logfile
+ // 1 Use debugger
+ // 2/undefined No debug output
+ // 4 Use logfile, close on process exit
+ // 8 Use logfile, verbose, close on process exit
+
+ DebugControl( DebugCtrl );
+
+ GotDebugState = TRUE; // Don't look again until process exits vdm
+ }
+ }
+#endif
+
+ LoadPreferredServerName();
+
+ //
+ // Attempt to allow for MD drives
+ //
+
+ bufferSize = (MD*sizeof(NETRESOURCE))+1024;
+
+ netResource = (LPNETRESOURCE) LocalAlloc(LPTR, bufferSize);
+
+ if (netResource == NULL) {
+
+ NwPrint(("Nw16Register: LocalAlloc Failed %d\n",GetLastError));
+ setCF(1);
+ return;
+ }
+
+ //-----------------------------------//
+ // Get a handle for a top level enum //
+ //-----------------------------------//
+ status = NPOpenEnum(
+ dwScope,
+ RESOURCETYPE_DISK,
+ 0,
+ NULL,
+ &enumHandle);
+
+ if ( status != WN_SUCCESS) {
+ NwPrint(("Nw16Register:WNetOpenEnum failed %d\n",status));
+
+ //
+ // If there is an extended error, display it.
+ //
+ if (status == WN_EXTENDED_ERROR) {
+ DisplayExtendedError();
+ }
+ goto LoadLocal;
+ }
+
+ //-----------------------------//
+ // Enumerate the disk devices. //
+ //-----------------------------//
+
+ numElements = 0xffffffff;
+
+ status = NwEnumConnections(
+ enumHandle,
+ &numElements,
+ netResource,
+ &bufferSize,
+ TRUE); // Include implicit connections
+
+ if ( status != WN_SUCCESS) {
+ NwPrint(("Nw16Register:NwEnumResource failed %d\n",status));
+
+ //
+ // If there is an extended error, display it.
+ //
+ if (status == WN_EXTENDED_ERROR) {
+ DisplayExtendedError();
+ }
+ WNetCloseEnum(enumHandle);
+ goto LoadLocal;
+ }
+
+ //------------------------------------------//
+ // Close the EnumHandle & print the results //
+ //------------------------------------------//
+
+ status = NPCloseEnum(enumHandle);
+ if (status != WN_SUCCESS) {
+ NwPrint(("Nw16Register:WNetCloseEnum failed %d\n",status));
+ //
+ // If there is an extended error, display it.
+ //
+ if (status == WN_EXTENDED_ERROR) {
+ DisplayExtendedError();
+ }
+ goto LoadLocal;
+
+ }
+
+ //----------------------------------------//
+ // Insert the results in the Nw Dos Table //
+ //----------------------------------------//
+
+ ProcessResourceArray( netResource, numElements);
+
+LoadLocal:
+
+ //
+ // Add the local devices so that NetWare apps don't try to map them
+ // to remote servers.
+ //
+
+ {
+ USHORT Drive;
+ WCHAR DriveString[4];
+ UINT Type;
+
+ DriveString[1] = L':';
+ DriveString[2] = L'\\';
+ DriveString[3] = L'\0';
+
+ //
+ // Hardwire A: and B: because hitting the floppy drive with
+ // GetDriveType takes too long.
+ //
+
+ pNwDosTable->DriveFlagTable[0] = LOCAL_DRIVE;
+ pNwDosTable->DriveFlagTable[1] = LOCAL_DRIVE;
+
+
+ for (Drive = 2; Drive <= 'Z' - 'A'; Drive++ ) {
+
+ if (pNwDosTable->DriveFlagTable[Drive] == 0) {
+ DriveString[0] = L'A' + Drive;
+ Type = GetDriveTypeW( DriveString );
+
+ //
+ // 0 means drive type cannot be determined, all others are
+ // provided by other filesystems.
+ //
+
+ if (Type != 1) {
+ pNwDosTable->DriveFlagTable[Drive] = LOCAL_DRIVE;
+ }
+ }
+ }
+
+#ifdef NWDBG
+ for (Drive = 0; Drive < MD; Drive++ ) {
+
+ DriveString[0] = L'A' + Drive;
+
+ NwPrint(("%c(%d)=%x,",'A' + Drive,
+ GetDriveTypeW( DriveString ),
+ pNwDosTable->DriveFlagTable[Drive] ));
+
+ if (!((Drive + 1) % 8)) {
+ NwPrint(("\n",0));
+ }
+ }
+
+ NwPrint(("\n"));
+#endif
+
+ }
+
+ if ( !Initialized ) {
+ Initialized = TRUE;
+ pNwDosTable->PrimaryServer = OriginalPrimary;
+ }
+
+ TablesValid = TRUE;
+
+ LocalFree(netResource);
+ setCF(0);
+
+ NwPrint(("Nw16Register: End\n"));
+}
+
+VOID
+LoadPreferredServerName(
+ VOID
+ )
+{
+
+ //
+ // If we already have a connection to somewhere then we already have a
+ // preferred servername of some sort.
+ //
+
+ if (pNwDosTable->ConnectionIdTable[0].ci_InUse == IN_USE) {
+ return;
+ }
+
+ //
+ // Load the server name table with the preferred/nearest server.
+ //
+
+ CopyMemory( pNwDosTable->ServerNameTable[0], "*", sizeof("*"));
+
+ if (NT_SUCCESS(OpenConnection( 0 ))) {
+
+ if( NT_SUCCESS(InitConnection(0)) ) {
+
+ //
+ // Close the handle so that the rdr can be stopped if
+ // user is not running a netware aware application.
+ //
+
+ CloseConnection(0);
+
+ pNwDosTable->PrimaryServer = 1;
+
+ return;
+
+ }
+
+ }
+
+ pNwDosTable->PrimaryServer = 0;
+
+}
+
+VOID
+ProcessResourceArray(
+ LPNETRESOURCE NetResource,
+ DWORD NumElements
+ )
+{
+ DWORD i;
+
+ for (i=0; i<NumElements ;i++ ) {
+ ProcessResource(&(NetResource[i]));
+ }
+ return;
+}
+
+VOID
+ProcessResource(
+ LPNETRESOURCE NetResource
+ )
+{
+ SERVERNAME ServerName;
+ int ServerNameLength;
+ int i;
+ int Connection;
+ BOOLEAN Found = FALSE;
+
+ //
+ // Extract Server Name from RemoteName, skipping first 2 chars that
+ // contain backslashes and taking care to handle entries that only
+ // contain a servername.
+ //
+
+ ServerNameLength = wcslen( NetResource->lpRemoteName );
+
+ ASSERT(NetResource->lpRemoteName[0] == '\\');
+ ASSERT(NetResource->lpRemoteName[1] == '\\');
+
+ for (i = 2; i <= ServerNameLength; i++) {
+
+ if ((NetResource->lpRemoteName[i] == '\\') ||
+ (i == ServerNameLength )){
+
+ ServerNameLength = i - 2;
+
+ WideCharToMultiByte(
+ CP_OEMCP,
+ 0,
+ &NetResource->lpRemoteName[2],
+ ServerNameLength,
+ ServerName,
+ sizeof( ServerName ),
+ NULL,
+ NULL );
+
+ CharUpperBuffA( ServerName, ServerNameLength );
+
+ ZeroMemory( &ServerName[ServerNameLength],
+ SERVERNAME_LENGTH - ServerNameLength );
+
+ break;
+ }
+
+ }
+
+ //
+ // Now try to find ServerName in the connection table. If there are
+ // more than MC servers in the table already then skip this one.
+ //
+
+ for (Connection = 0; Connection < MC ; Connection++ ) {
+ if ((pNwDosTable->ConnectionIdTable[Connection].ci_InUse == IN_USE) &&
+ (!memcmp( pNwDosTable->ServerNameTable[Connection], ServerName, SERVERNAME_LENGTH))) {
+ Found = TRUE;
+ break;
+ }
+ }
+
+
+ NwPrint(("Nw16ProcessResource Server: %s\n",ServerName));
+
+ if ( Found == FALSE ) {
+ for (Connection = 0; Connection < MC ; Connection++ ) {
+ if (pNwDosTable->ConnectionIdTable[Connection].ci_InUse == FREE) {
+
+ CopyMemory( pNwDosTable->ServerNameTable[Connection],
+ ServerName,
+ SERVERNAME_LENGTH);
+
+ if ((NT_SUCCESS(OpenConnection( (CONN_INDEX)Connection ))) &&
+ ( NT_SUCCESS(InitConnection( (CONN_INDEX)Connection ) ))) {
+
+ Found = TRUE;
+
+ } else {
+ // Couldn't talk to the server so ignore it.
+ ZeroMemory( pNwDosTable->ServerNameTable[Connection], SERVERNAME_LENGTH );
+
+ }
+
+ break; // Escape from for (Connection =...
+ }
+ }
+ }
+
+ //
+ // Build the drive id and drive flag tables. Entries 0 - 25
+ // are reserved for drives redirected to letters. We use drives
+ // 26 - 31 for UNC drives.
+ //
+
+ if ( Found == TRUE ) {
+ DRIVE Drive;
+ DRIVE NextUncDrive = 26;
+
+ if ( NetResource->dwType != RESOURCETYPE_DISK ) {
+ return;
+ }
+
+ if ( NetResource->lpLocalName != NULL) {
+ Drive = NetResource->lpLocalName[0] - L'A';
+ } else {
+ if ( NextUncDrive < MD ) {
+ Drive = NextUncDrive++;
+ } else {
+
+ //
+ // No room in the table for this UNC drive.
+ //
+
+ return;
+ }
+ }
+
+ //
+ // We have a drive and a connection. Complete the table
+ // mappings.
+ //
+
+ pNwDosTable->DriveIdTable[ Drive ] = Connection + 1;
+ pNwDosTable->DriveFlagTable[ Drive ] = PERMANENT_NETWORK_DRIVE;
+
+ }
+
+}
+
+
+VOID
+InitDosTable(
+ PNWDOSTABLE pdt
+ )
+
+/*++
+
+Routine Description:
+
+ This routine Initializes the NetWare Dos Table to its empty values.
+
+Arguments:
+
+ pdt - Supplies the table to be initialized.
+
+Return Value:
+
+ None
+
+--*/
+{
+ ZeroMemory( ServerHandles, sizeof(ServerHandles) );
+ ZeroMemory( Drives, sizeof(Drives) );
+ ZeroMemory( (PVOID) pdt, sizeof(NWDOSTABLE) );
+ ZeroMemory( Win32DirectoryHandleTable, sizeof(Win32DirectoryHandleTable) );
+ FillMemory( SearchDriveTable, sizeof(SearchDriveTable), 0xff );
+}
+
+UCHAR CpuInProtectMode;
+
+
+VOID
+Nw16Handler(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This function is called by wow when nw16.sys traps an Int and
+ bop's into 32 bit mode.
+
+Arguments:
+
+
+Return Value:
+
+ None,
+
+--*/
+{
+ USHORT Command;
+ WORD offset;
+
+ //
+ // get the CPU mode once: the memory references it's required for won't
+ // change during this call. Cuts down number of calls to getMSW()
+ //
+
+ CpuInProtectMode = IS_PROTECT_MODE();
+
+ setCF(0);
+ if ( TablesValid == FALSE ) {
+
+ //
+ // Load the tables unless the process is exiting.
+ //
+
+ if ((pNwDosTable->SavedAx & 0xff00) != 0x4c00) {
+ Nw16Register();
+ }
+
+#if NWDBG
+ if (GotDebugState == FALSE) {
+
+ WCHAR Value[80];
+
+ if (GetEnvironmentVariableW(L"NWDEBUG",
+ Value,
+ sizeof(Value)/sizeof(Value[0]) - 1)) {
+
+ DebugCtrl = Value[0] - '0';
+
+ // 0 Use logfile
+ // 1 Use debugger
+ // 2/undefined No debug output
+ // 4 Use logfile, close on process exit
+ // 8 Use logfile, verbose, close on process exit
+
+ DebugControl( DebugCtrl );
+
+ }
+
+ GotDebugState = TRUE; // Don't look again until process exits vdm
+ }
+#endif
+ }
+
+ //
+ // Normal AX register is used to get into 32 bit code so get applications
+ // AX from the shared datastructure.
+ //
+
+ Command = pNwDosTable->SavedAx;
+
+ //
+ // set AX register so that AH gets preserved
+ //
+
+ setAX( Command );
+
+ NwPrint(("Nw16Handler process command %x\n", Command ));
+ VrDumpRealMode16BitRegisters( FALSE );
+ VrDumpNwData();
+
+ switch (Command & 0xff00) {
+
+ case 0x3C00:
+ case 0x3D00:
+ OpenCreateFile();
+ break;
+
+ case 0x4C00:
+ ProcessExit(); // Close all handles
+ goto default_dos_handler; // Let Dos handle rest of processing
+ break;
+
+ case 0x9f00:
+ OpenQueueFile();
+ break;
+
+ case 0xB300: // Packet Signing
+ setAL(0); // not supported
+ break;
+
+ case 0xB400:
+ AttachHandle();
+ break;
+
+ case 0xB500:
+ switch (Command & 0x00ff) {
+ case 03:
+ setAX((WORD)pNwDosTable->TaskModeByte);
+ break;
+
+ case 04:
+ setES((WORD)(CpuInProtectMode ? pNwDosTable->PmSelector : DosTableSegment));
+ setBX((WORD)(DosTableOffset + &((PNWDOSTABLE)0)->TaskModeByte));
+ break;
+
+ case 06:
+ setAX(2);
+ break;
+
+ default:
+ goto default_dos_handler;
+ }
+ break;
+
+ case 0xB800: // Capture - Not supported
+ setAL(0xff);
+ setCF(1);
+ break;
+
+ case 0xBB00: // Set EOJ status
+ {
+ static UCHAR EOJstatus = 1;
+ setAL(EOJstatus);
+ EOJstatus = pNwDosTable->SavedAx & 0x00ff;
+ }
+ break;
+
+ case 0xBC00:
+ case 0xBD00:
+ case 0xBE00:
+
+ case 0xC200:
+ case 0xC300:
+ case 0xC400:
+ case 0xC500:
+ case 0xC600:
+ Locks(Command);
+ break;
+
+ case 0xC700:
+ TTS();
+ break;
+
+ case 0xCB00:
+ case 0xCD00:
+ case 0xCF00:
+
+ case 0xD000:
+ case 0xD100:
+ case 0xD200:
+ case 0xD300:
+ case 0xD400:
+ case 0xD500:
+ Locks(Command);
+ break;
+
+ case 0xD700:
+ SystemLogout();
+ break;
+
+ case 0xDB00:
+ {
+ UCHAR Drive;
+ UCHAR Count = 0;
+ for (Drive = 0; Drive < MD; Drive++) {
+ if (pNwDosTable->DriveFlagTable[Drive] == LOCAL_DRIVE ) {
+ Count++;
+ }
+ }
+ setAL(Count);
+ }
+ break;
+
+ case 0xDC00: // Get station number
+ {
+ CONN_INDEX Connection = SelectConnection();
+ if (Connection == 0xff) {
+ setAL(0xff);
+ setCF(1);
+ } else {
+
+ PCONNECTIONID pConnection =
+ &pNwDosTable->ConnectionIdTable[Connection];
+
+ setAL(pConnection->ci_ConnectionLo);
+ setAH(pConnection->ci_ConnectionHi);
+ setCH( (UCHAR)((pConnection->ci_ConnectionHi == 0) ?
+ pConnection->ci_ConnectionLo / 10 + '0':
+ 'X'));
+ setCL((UCHAR)(pConnection->ci_ConnectionLo % 10 + '0'));
+ }
+ }
+ break;
+
+ case 0xDD00: // Set NetWare Error mode
+ {
+ static UCHAR ErrorMode = 0;
+ setAL( ErrorMode );
+ ErrorMode = getDL();
+ }
+ break;
+
+ case 0xDE00:
+ {
+ static UCHAR BroadCastMode = 0;
+ UCHAR OpCode = getDL();
+ if ( OpCode < 4) {
+ BroadCastMode = OpCode;
+ }
+ setAL(BroadCastMode);
+ }
+ break;
+
+ case 0xDF00: // Capture - Not supported
+ setAL(0xff);
+ setCF(1);
+ break;
+
+ case 0xE000:
+ case 0xE100:
+ case 0xE300:
+ SendNCP(Command);
+ break;
+
+ case 0xE200:
+
+ AllocateDirectoryHandle();
+ break;
+
+ case 0xE700:
+ GetServerDateAndTime();
+ break;
+
+ case 0xE900:
+
+ switch (Command & 0x00ff) {
+ PUCHAR ptr;
+ case 0:
+ GetDirectoryHandle();
+ break;
+
+ case 1:
+ ptr = GetVDMPointer (
+ (ULONG)((getDS() << 16)|getDX()),
+ sizeof(SearchDriveTable),
+ CpuInProtectMode
+ );
+
+ RtlMoveMemory( ptr, SearchDriveTable, sizeof(SearchDriveTable) );
+ break;
+
+ case 2:
+ ptr = GetVDMPointer (
+ (ULONG)((getDS() << 16)|getDX()),
+ sizeof(SearchDriveTable),
+ CpuInProtectMode
+ );
+
+ RtlMoveMemory( SearchDriveTable, ptr, sizeof(SearchDriveTable) );
+ break;
+
+ case 5:
+ AllocateDirectoryHandle2();
+ break;
+
+ case 7:
+ setAL(0xff); // Drive depth not yet implemented
+ break;
+
+#ifdef NWDBG
+ // Debug control
+ case 0xf0: // Use logfile
+ case 0xf1: // Use debugger
+ case 0xf2: // No debug output
+ DebugControl(Command & 0x000f);
+ break;
+#endif
+ default:
+ NwPrint(("Nw16Handler unprocessed interrupt %x\n", pNwDosTable->SavedAx ));
+ }
+ break;
+
+ case 0xEA00:
+ GetShellVersion(Command);
+ break;
+
+ case 0xEB00:
+ case 0xEC00:
+ case 0xED00:
+ Locks(Command);
+ break;
+
+
+ case 0xEF00:
+ NwPrint(("Nw32: %x\n", pNwDosTable->SavedAx ));
+
+ switch (Command & 0xff) {
+ case 00:
+ if (DriveHandleTableValid == FALSE) {
+ LoadDriveHandleTable();
+ }
+
+ offset = (WORD)&((PNWDOSTABLE)0)->DriveHandleTable;
+ break;
+
+ case 01:
+ offset = (WORD)&((PNWDOSTABLE)0)->DriveFlagTable;
+ break;
+
+ case 02:
+ offset = (WORD)&((PNWDOSTABLE)0)->DriveIdTable;
+ break;
+
+ case 03:
+ offset = (WORD)&((PNWDOSTABLE)0)->ConnectionIdTable;
+ break;
+
+ case 04:
+ offset = (WORD)&((PNWDOSTABLE)0)->ServerNameTable;
+ break;
+
+ default:
+ goto default_dos_handler;
+ }
+ setSI((WORD)(DosTableOffset + offset));
+ setES((WORD)(CpuInProtectMode ? pNwDosTable->PmSelector : DosTableSegment));
+ setAL(0);
+ break;
+
+ case 0xF100:
+ setAL(AttachmentControl(Command));
+ break;
+
+ case 0xF200:
+ SendF2NCP(Command);
+ break;
+
+ case 0xF300:
+ ServerFileCopy();
+ break;
+
+ default:
+
+default_dos_handler:
+
+ NwPrint(("Nw16Handler unprocessed interrupt %x\n", pNwDosTable->SavedAx ));
+
+ //
+ // if we don't handle this call, we modify the return ip to point to
+ // code that will restore the stack and jump far into dos
+ //
+
+ setIP((WORD)(getIP() + 3));
+
+ }
+
+#if NWDBG
+ pNwDosTable->SavedAx = getAX();
+#endif
+ VrDumpRealMode16BitRegisters( FALSE );
+}
+
+
+CONN_INDEX
+SelectConnection(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Pick target connection for current transaction
+
+Arguments:
+
+ None
+
+Return Value:
+
+ Index into ConnectionIdTable or 0xff,
+
+--*/
+{
+
+ UCHAR IndexConnection;
+
+ if ( pNwDosTable->PreferredServer != 0 ) {
+ return(pNwDosTable->PreferredServer - 1);
+ }
+
+ // BUGBUG: select default server if current drive is mapped by us?
+
+ if ( pNwDosTable->PrimaryServer != 0 ) {
+ return(pNwDosTable->PrimaryServer - 1);
+ }
+
+ // Need to pick another
+
+ for (IndexConnection = 0; IndexConnection < MC ; IndexConnection++ ) {
+
+ if (pNwDosTable->ConnectionIdTable[IndexConnection].ci_InUse == IN_USE) {
+
+ pNwDosTable->PrimaryServer = IndexConnection + 1;
+
+ return(pNwDosTable->PrimaryServer - 1);
+
+ }
+ }
+
+ // No servers in the table so find the nearest/preferred.
+
+ LoadPreferredServerName();
+
+ return(pNwDosTable->PrimaryServer - 1);
+
+}
+
+
+
+VOID
+SendNCP(
+ ULONG Command
+ )
+/*++
+
+Routine Description:
+
+ Implement generic Send NCP function.
+
+ ASSUMES called from Nw16Handler
+
+Arguments:
+
+ Command - Supply the opcode 0xexxx
+ DS:SI - Supply Request buffer & length
+ ES:DI - Supply Reply buffer & length
+
+ On return AL = Status of operation.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PUCHAR Request, Reply;
+ ULONG RequestLength, ReplyLength;
+ UCHAR OpCode;
+
+ OpCode = (UCHAR)((Command >> 8) - 0xcc);
+
+ Request = GetVDMPointer (
+ (ULONG)((getDS() << 16)|getSI()),
+ sizeof(WORD),
+ CpuInProtectMode
+ );
+
+ Reply = GetVDMPointer (
+ (ULONG)((getES() << 16)|getDI()),
+ sizeof(WORD),
+ CpuInProtectMode
+ );
+
+ RequestLength = *(WORD UNALIGNED*)Request;
+ ReplyLength = *(WORD UNALIGNED*)Reply;
+
+ Request = GetVDMPointer (
+ (ULONG)((getDS() << 16)|getSI() + sizeof(WORD)),
+ (USHORT)RequestLength,
+ CpuInProtectMode
+ );
+ Reply = GetVDMPointer (
+ (ULONG)((getES() << 16)|getDI()) + sizeof(WORD),
+ (USHORT)ReplyLength,
+ CpuInProtectMode
+ );
+
+ NwPrint(("SubRequest %x, RequestLength %x\n", Request[0], RequestLength ));
+
+ SendNCP2( NWR_ANY_NCP(OpCode ),
+ Request,
+ RequestLength,
+ Reply,
+ ReplyLength);
+}
+
+
+VOID
+SendF2NCP(
+ ULONG Command
+ )
+/*++
+
+Routine Description:
+
+ Implement generic Send NCP function. No length to be inseted by
+ the redirector in the request buffer.
+
+ ASSUMES called from Nw16Handler
+
+Arguments:
+
+ Command - Supply the opcode 0xf2xx
+ DS:SI CX - Supply Request buffer & length
+ ES:DI DX - Supply Reply buffer & length
+
+ On return AL = Status of operation.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PUCHAR Request, Reply;
+ ULONG RequestLength, ReplyLength;
+ UCHAR OpCode;
+
+
+ OpCode = (UCHAR)(Command & 0x00ff);
+
+ RequestLength = getCX();
+ ReplyLength = getDX();
+
+ Request = GetVDMPointer (
+ (ULONG)((getDS() << 16)|getSI()),
+ (USHORT)RequestLength,
+ CpuInProtectMode
+ );
+ Reply = GetVDMPointer (
+ (ULONG)((getES() << 16)|getDI()),
+ (USHORT)ReplyLength,
+ CpuInProtectMode
+ );
+
+ NwPrint(("F2SubRequest %x, RequestLength %x\n", Request[2], RequestLength ));
+
+#if 0
+ if ((RequestLength != 0) &&
+ (OpCode == 0x17)) {
+
+ if ((Request[2] == 0x17) ||
+ (Request[2] == 0x18)) {
+ //
+ // The request was for an encryption key. Tell the
+ // application that encryption is not supported.
+ //
+
+ setAL(0xfb);
+ return;
+
+ } else if ((Request[2] == 0x14 ) ||
+ (Request[2] == 0x3f )) {
+
+ //
+ // Plaintext login or Verify Bindery Object Password.
+ // Convert to its WNET equivalent version.
+ //
+
+ UCHAR Name[256];
+ UCHAR Password[256];
+ UCHAR ServerName[sizeof(SERVERNAME)+3];
+ PUCHAR tmp;
+ CONN_INDEX Connection;
+ NETRESOURCEA Nr;
+
+ Connection = SelectConnection();
+ if ( Connection == 0xff ) {
+ setAL(0xff);
+ setCF(1);
+ return;
+ }
+
+ ZeroMemory( &Nr, sizeof(NETRESOURCE));
+ ServerName[0] = '\\';
+ ServerName[1] = '\\';
+ RtlCopyMemory( ServerName+2, pNwDosTable->ServerNameTable[Connection], sizeof(SERVERNAME) );
+ ServerName[sizeof(ServerName)-1] = '\0';
+ Nr.lpRemoteName = ServerName;
+ Nr.dwType = RESOURCETYPE_DISK;
+
+ // point to password length.
+ tmp = &Request[6] + Request[5];
+
+ Name[Request[5]] = '\0';
+ RtlMoveMemory( Name, &Request[6], Request[5]);
+
+ Password[tmp[0]] = '\0';
+ RtlMoveMemory( Password, tmp+1, tmp[0]);
+
+ NwPrint(("Connect to %s as %s password %s\n", ServerName, Name, Password ));
+
+ if (NO_ERROR == WNetAddConnection2A( &Nr, Password, Name, 0)) {
+ setAL(0);
+ } else {
+ setAL(255);
+ }
+ return;
+ }
+ }
+
+#endif
+
+ SendNCP2( NWR_ANY_F2_NCP(OpCode ),
+ Request,
+ RequestLength,
+ Reply,
+ ReplyLength);
+}
+
+
+VOID
+SendNCP2(
+ ULONG Command,
+ PUCHAR Request,
+ ULONG RequestLength,
+ PUCHAR Reply,
+ ULONG ReplyLength
+ )
+/*++
+
+Routine Description:
+
+ Pick target connection for current transaction
+
+ This routine effectively opens a handle for each NCP sent. This means that
+ we don't keep handles open to servers unnecessarily which would cause
+ problems if a user tries to delete the connection or stop the workstation.
+
+ If this causes to much of a load then the fallback is to spin off a thread
+ that waits on an event with a timeout and periodically sweeps the
+ server handle table removing stale handles. Setting the event would cause
+ the thread to exit. Critical sections would need to be added to protect
+ handles. Dll Init/exit routine to kill the thread and close the handles
+ would also be needed.
+
+Arguments:
+
+ Command - Supply the opcode
+ Request, RequestLength - Supply Request buffer & length
+ Reply, ReplyLength - Supply Reply buffer & length
+
+ On return AL = Status of operation.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ CONN_INDEX Connection = SelectConnection();
+ NTSTATUS status;
+ IO_STATUS_BLOCK IoStatusBlock;
+ HANDLE Handle;
+
+ NwPrint(("Send NCP %x to %d:%s\n", Command, Connection, pNwDosTable->ServerNameTable[Connection] ));
+ NwPrint(("RequestLength %x\n", RequestLength ));
+ NwPrint(("Reply %x, ReplyLength %x\n", Reply, ReplyLength ));
+
+ if (Connection == 0xff) {
+ setAL(0xff);
+ setCF(1);
+ return;
+ };
+
+ if ( ServerHandles[Connection] == NULL ) {
+
+ status = OpenConnection( Connection );
+
+ if (!NT_SUCCESS(status)) {
+ SetStatus(status);
+ return;
+ } else {
+ InitConnection( Connection );
+ }
+ }
+
+ Handle = ServerHandles[Connection];
+
+ //
+ // If its a CreateJobandFile NCP then we need to use the handle
+ // created through Dos so that the writes go into the spoolfile created
+ // by this NCP.
+ //
+
+ if (Command == NWR_ANY_F2_NCP(0x17)) {
+
+ if ((Request[2] == 0x68) ||
+ (Request[2] == 0x79)) {
+
+ Handle = GET_NT_HANDLE();
+ }
+ } else if (Command == NWR_ANY_NCP(0x17)) {
+ if ((Request[0] == 0x68) ||
+ (Request[0] == 0x79)) {
+
+ Handle = GET_NT_HANDLE();
+ }
+ }
+
+ FormattedDump( Request, RequestLength );
+
+ //
+ // Make the NCP request on the appropriate handle
+ //
+
+ status = NtFsControlFile(
+ Handle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatusBlock,
+ Command,
+ (PVOID) (Request),
+ RequestLength,
+ (PVOID) Reply,
+ ReplyLength);
+
+ if (NT_SUCCESS(status)) {
+ status = IoStatusBlock.Status;
+ FormattedDump( Reply, ReplyLength );
+ }
+
+ if (!NT_SUCCESS(status)) {
+ SetStatus(status);
+ setCF(1);
+ NwPrint(("NtStatus %x, DosError %x\n", status, getAL() ));
+ } else {
+ setAL(0);
+ }
+}
+
+
+NTSTATUS
+OpenConnection(
+ CONN_INDEX Connection
+ )
+/*++
+
+Routine Description:
+
+ Open the handle to the redirector to access the specified server.
+
+Arguments:
+
+ Connection - Supplies the index to use for the handle
+
+Return Value:
+
+ Status of the operation
+
+--*/
+{
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatusBlock;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+
+ LPWSTR FullName;
+
+ UCHAR AnsiName[SERVERNAME_LENGTH+sizeof(UCHAR)];
+
+ UNICODE_STRING UServerName;
+ OEM_STRING AServerName;
+
+ if ( Connection >= MC) {
+ return( BASE_DOS_ERROR + 249 ); // No free connection slots
+ }
+
+ if (ServerHandles[Connection] != NULL ) {
+
+ CloseConnection(Connection);
+
+ }
+
+ FullName = (LPWSTR) LocalAlloc( LMEM_ZEROINIT,
+ sizeof( DD_NWFS_DEVICE_NAME_U ) +
+ (SERVERNAME_LENGTH + 1) * sizeof(WCHAR)
+ );
+
+ if ( FullName == NULL ) {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ CopyMemory(AnsiName,
+ pNwDosTable->ServerNameTable[Connection],
+ SERVERNAME_LENGTH);
+ AnsiName[SERVERNAME_LENGTH+1] = '\0';
+
+ RtlInitAnsiString( &AServerName, AnsiName );
+ Status = RtlOemStringToUnicodeString( &UServerName,
+ &AServerName,
+ TRUE);
+
+ if (!NT_SUCCESS(Status)) {
+ LocalFree( FullName );
+ return(Status);
+ }
+
+ wcscpy( FullName, DD_NWFS_DEVICE_NAME_U );
+ wcscat( FullName, L"\\");
+ wcscat( FullName, UServerName.Buffer );
+
+ RtlFreeUnicodeString(&UServerName);
+
+ RtlInitUnicodeString( &UServerName, FullName );
+
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ &UServerName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL
+ );
+
+ //
+ // Open a handle to the server.
+ //
+
+ //
+ // Try to login to the nearest server. This is necessary for
+ // the real preferred server if there are no redirections to
+ // it. The rdr can logout and disconnect. SYSCON doesn't like
+ // running from such a server.
+ //
+ Status = NtOpenFile(
+ &ServerHandles[Connection],
+ SYNCHRONIZE | FILE_READ_ATTRIBUTES,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ FILE_SHARE_VALID_FLAGS,
+ FILE_SYNCHRONOUS_IO_NONALERT
+ );
+
+ if ( NT_SUCCESS(Status)) {
+ Status = IoStatusBlock.Status;
+ }
+
+ if (!NT_SUCCESS(Status)) {
+ //
+ // Failed to login. Use the non-login method. This allows the
+ // app to do a bindery login or query the bindery.
+ //
+
+ Status = NtOpenFile(
+ &ServerHandles[Connection],
+ SYNCHRONIZE,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ FILE_SHARE_VALID_FLAGS,
+ FILE_SYNCHRONOUS_IO_NONALERT
+ );
+
+ if ( NT_SUCCESS(Status)) {
+ Status = IoStatusBlock.Status;
+ }
+ }
+
+ NwPrint(("Nw16:OpenConnection %d: %wZ status = %08lx\n", Connection, &UServerName, Status));
+
+ LocalFree( FullName );
+
+ if (!NT_SUCCESS(Status)) {
+ SetStatus(Status);
+ return Status;
+ }
+
+ return Status;
+}
+
+
+VOID
+CloseConnection(
+ CONN_INDEX Connection
+ )
+/*++
+
+Routine Description:
+
+ Close the connection handle
+
+Arguments:
+
+ Connection - Supplies the index to use for the handle
+
+Return Value:
+
+ None.
+
+--*/
+{
+ if (ServerHandles[Connection]) {
+
+ NwPrint(("CloseConnection: %d\n",Connection));
+
+ NtClose(ServerHandles[Connection]);
+
+ ServerHandles[Connection] = NULL;
+ }
+}
+
+
+NTSTATUS
+InitConnection(
+ CONN_INDEX Connection
+ )
+/*++
+
+Routine Description:
+
+ Get the connection status from the redirector.
+
+Arguments:
+
+ Connection - Supplies the index to use for the handle
+
+Return Value:
+
+ Status of the operation
+
+--*/
+{
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatusBlock;
+ NWR_GET_CONNECTION_DETAILS Details;
+
+ Status = NtFsControlFile(
+ ServerHandles[Connection],
+ NULL,
+ NULL,
+ NULL,
+ &IoStatusBlock,
+ FSCTL_NWR_GET_CONN_DETAILS,
+ NULL,
+ 0,
+ (PVOID) &Details,
+ sizeof(Details));
+
+ if (Status == STATUS_SUCCESS) {
+ Status = IoStatusBlock.Status;
+ }
+
+ NwPrint(("Nw16:InitConnection: %d status = %08lx\n",Connection, Status));
+
+ if (!NT_SUCCESS(Status)) {
+
+ SetStatus(Status);
+
+ CloseConnection(Connection);
+
+ } else {
+ PCONNECTIONID pConnection =
+ &pNwDosTable->ConnectionIdTable[Connection];
+
+ pConnection->ci_OrderNo= Details.OrderNumber;
+
+ CopyMemory(pNwDosTable->ServerNameTable[Connection],
+ Details.ServerName,
+ sizeof(SERVERNAME));
+
+ CopyMemory(pConnection->ci_ServerAddress,
+ Details.ServerAddress,
+ sizeof(pConnection->ci_ServerAddress));
+
+ pConnection->ci_ConnectionNo= Details.ConnectionNumberLo;
+ pConnection->ci_ConnectionLo= Details.ConnectionNumberLo;
+ pConnection->ci_ConnectionHi= Details.ConnectionNumberHi;
+ pConnection->ci_MajorVersion= Details.MajorVersion;
+ pConnection->ci_MinorVersion= Details.MinorVersion;
+ pConnection->ci_InUse = IN_USE;
+ pConnection->ci_1 = 0;
+ pConnection->ci_ConnectionStatus = 2;
+
+ //
+ // If this is the preferred conection then record it as special.
+ // If this is the first drive then also record it. Usually it gets
+ // overwritten by the preferred.
+ //
+
+ if (( Details.Preferred ) ||
+ ( OriginalPrimary == 0 )) {
+
+ NwPrint(("Nw16InitConnection: Primary Connection is %d\n", Connection+1));
+
+ pNwDosTable->PrimaryServer = OriginalPrimary = (UCHAR)Connection + 1;
+ }
+
+ setAL(0);
+ }
+
+ return Status;
+}
+
+VOID
+GetDirectoryHandle(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Obtain a NetWare handle for the current directory.
+
+ If a NetWare handle is assigned then the Win32 handle created for
+ the directory handle is kept open. When the process exits, the Win32
+ handle will close. When all the Win32 handles from this process are
+ closed an endjob NCP will be sent freeing the directory handle on the
+ server.
+
+Arguments:
+
+ DX supplies the drive.
+
+ AL returns the handle.
+ AH returns the status flags.
+
+
+Return Value:
+
+ None.
+
+--*/
+{
+ USHORT Drive = getDX();
+
+ NwPrint(("Nw32:GetDirectoryHandle %c: ", 'A' + Drive));
+
+ GetDirectoryHandle2( Drive );
+
+ setAL(pNwDosTable->DriveHandleTable[Drive]);
+ setAH(pNwDosTable->DriveFlagTable[Drive]);
+
+ NwPrint(("Handle = %x, Flags =%x\n", pNwDosTable->DriveHandleTable[Drive],
+ pNwDosTable->DriveFlagTable[Drive] ));
+}
+
+ULONG
+GetDirectoryHandle2(
+ DWORD Drive
+ )
+/*++
+
+Routine Description:
+
+ Obtain a NetWare handle for the current directory.
+
+ If a NetWare handle is assigned then the Win32 handle created for
+ the directory handle is kept open. When the process exits, the Win32
+ handle will close. When all the Win32 handles from this process are
+ closed an endjob NCP will be sent freeing the directory handle on the
+ server.
+
+ Note: Updates DriveHandleTable.
+
+Arguments:
+
+ Drive supplies the drive index (0 = a:).
+
+Return Value:
+
+ returns the handle.
+
+--*/
+{
+ DWORD BytesReturned;
+
+ if (Drive >= MD) {
+ setAL( 0x98 ); // Volume does not exist
+ return 0xffffffff;
+ }
+
+ NwPrint(("Nw32:GetDirectoryHandle2 %c:\n", 'A' + Drive));
+
+ //
+ // If we don't have a handle and its either a temporary or
+ // permanent drive then create it.
+ //
+
+ if (( Win32DirectoryHandleTable[Drive] == 0 ) &&
+ ( (pNwDosTable->DriveFlagTable[Drive] & 3) != 0 )){
+ WCHAR DriveString[4];
+ PWCHAR Name;
+
+ //
+ // We don't have a handle for this drive.
+ // Open an NT handle to the current directory and
+ // ask the redirector for a NetWare directory handle.
+ //
+
+ if (Drive <= ('Z' - 'A')) {
+
+ DriveString[0] = L'A' + (WCHAR)Drive;
+ DriveString[1] = L':';
+ DriveString[2] = L'.';
+ DriveString[3] = L'\0';
+
+ Name = DriveString;
+
+ } else {
+
+ Name = Drives[Drive];
+
+ if( Name == NULL ) {
+ NwPrint(("\nNw32:GetDirectoryHandle2 Drive not mapped\n",0));
+ return 0xffffffff;
+ }
+ }
+
+ Win32DirectoryHandleTable[Drive] =
+ CreateFileW( Name,
+ 0,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS,
+ 0);
+
+ if (Win32DirectoryHandleTable[Drive] != INVALID_HANDLE_VALUE) {
+
+ if ( DeviceIoControl(
+ Win32DirectoryHandleTable[Drive],
+ IOCTL_NWR_RAW_HANDLE,
+ NULL,
+ 0,
+ (PUCHAR)&pNwDosTable->DriveHandleTable[Drive],
+ sizeof(pNwDosTable->DriveHandleTable[Drive]),
+ &BytesReturned,
+ NULL ) == FALSE ) {
+
+ NwPrint(("\nNw32:GetDirectoryHandle2 DeviceIoControl %x\n", GetLastError()));
+ CloseHandle( Win32DirectoryHandleTable[Drive] );
+ Win32DirectoryHandleTable[Drive] = 0;
+ return 0xffffffff;
+
+ } else {
+ ASSERT( BytesReturned == sizeof(pNwDosTable->DriveHandleTable[Drive]));
+
+ NwPrint(("\nNw32:GetDirectoryHandle2 Success %x\n", pNwDosTable->DriveHandleTable[Drive]));
+ }
+
+ } else {
+ NwPrint(("\nNw32:GetDirectoryHandle2 CreateFile %x\n", GetLastError()));
+
+ Win32DirectoryHandleTable[Drive] = 0;
+
+ return 0xffffffff;
+ }
+
+ }
+
+ return (ULONG)pNwDosTable->DriveHandleTable[Drive];
+}
+
+VOID
+LoadDriveHandleTable(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Open handles to all the NetWare drives
+
+Arguments:
+
+ none.
+
+Return Value:
+
+ none.
+
+--*/
+{
+
+ USHORT Drive;
+ for (Drive = 0; Drive < MD; Drive++ ) {
+ GetDirectoryHandle2(Drive);
+ }
+
+ DriveHandleTableValid = TRUE;
+
+}
+
+VOID
+AllocateDirectoryHandle(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Allocate permanent or temporary handle for drive.
+
+ For a permanent handle, we map this to a "net use".
+
+ ASSUMES called from Nw16Handler
+
+
+Arguments:
+
+ DS:SI supplies the request.
+ ES:DI supplies the response.
+
+ AL returns the completion code.
+
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ PUCHAR Request=GetVDMPointer (
+ (ULONG)((getDS() << 16)|getSI()),
+ 2,
+ CpuInProtectMode
+ );
+
+ PUCHAR Reply = GetVDMPointer (
+ (ULONG)((getES() << 16)|getDI()),
+ 4,
+ CpuInProtectMode
+ );
+
+ USHORT RequestLength = *(USHORT UNALIGNED *)( Request );
+
+ Request=GetVDMPointer (
+ (ULONG)((getDS() << 16)|getSI()),
+ RequestLength+2,
+ CpuInProtectMode
+ );
+
+ FormattedDump( Request, RequestLength+2 );
+
+
+ if (( Request[2] == 0x12) ||
+ ( Request[2] == 0x13)) {
+ // BUGBUG do temp drives need different handling?
+
+ UCHAR Drive = Request[4] - 'A';
+
+ if (Drive >= MD) {
+ setAL( 0x98 ); // Volume does not exist
+ return;
+ }
+
+ if (pNwDosTable->DriveHandleTable[Drive] != 0) {
+
+ NwPrint(("Nw32: Move directory handle %d\n", Drive));
+
+ //
+ // We already have a directory handle assigned for this
+ // process. Ask the server to point the handle at the requested
+ // position.
+ //
+
+ SendNCP2(FSCTL_NWR_NCP_E2H, Request+2, RequestLength, Reply+2, 2);
+
+ if (getAL() == 0) {
+ // Record the new handle.
+
+ pNwDosTable->DriveIdTable[ Drive ] = SelectConnection()+1;
+
+ if (Request[2] == 0x12) {
+ pNwDosTable->DriveFlagTable[ Drive ] =
+ PERMANENT_NETWORK_DRIVE;
+ } else {
+ pNwDosTable->DriveFlagTable[ Drive ] =
+ TEMPORARY_NETWORK_DRIVE;
+ }
+
+ pNwDosTable->DriveHandleTable[Drive] = Reply[2];
+ NwPrint(("Nw32: Move directory handle -> %x\n", Reply[2]));
+ }
+
+ } else {
+ NETRESOURCE Nr;
+ WCHAR DriveString[3];
+ ULONG Handle;
+
+ if (Request[2] == 0x12) {
+ NwPrint(("Nw32: Allocate permanent directory handle %d\n", Drive));
+ } else {
+ NwPrint(("Nw32: Allocate temporary directory handle %d\n", Drive));
+ }
+
+ if (Drives[Drive] != NULL) {
+
+ // Tidy up the old name for this drive.
+
+ LocalFree( Drives[Drive] );
+ Drives[Drive] = NULL;
+ }
+
+ DriveString[0] = L'A' + Drive; // A through Z
+ DriveString[1] = L':';
+ DriveString[2] = L'\0';
+
+ //
+ // This is effectively a net use!
+ //
+
+ ZeroMemory( &Nr, sizeof(NETRESOURCE));
+
+ Nr.lpRemoteName = BuildUNC(&Request[6], Request[5]);
+ Nr.dwType = RESOURCETYPE_DISK;
+
+ // Save where this drive points.
+ Drives[Drive] = Nr.lpRemoteName;
+
+ if (DriveString[0] <= L'Z') {
+ Nr.lpLocalName = DriveString;
+
+ if (NO_ERROR != WNetAddConnection2W( &Nr, NULL, NULL, 0)) {
+
+ NwPrint(("Nw32: Allocate ->%d\n", GetLastError()));
+ setAL(0x98); // Volume does not exist
+ return;
+ }
+ }
+
+
+ if (Request[2] == 0x12) {
+ pNwDosTable->DriveFlagTable[ Drive ] =
+ PERMANENT_NETWORK_DRIVE;
+ } else {
+ pNwDosTable->DriveFlagTable[ Drive ] =
+ TEMPORARY_NETWORK_DRIVE;
+ }
+
+ Handle = GetDirectoryHandle2( Drive );
+
+ if (Handle == 0xffffffff) {
+
+ if (DriveString[0] <= L'Z') {
+
+ WNetCancelConnection2W( DriveString, 0, TRUE);
+
+ }
+
+ ResetDrive( Drive );
+
+ setAL(0x9c); // Invalid path
+
+ } else {
+
+ //
+ // We have a drive and a connection. Complete the table
+ // mappings.
+ //
+
+ pNwDosTable->DriveIdTable[ Drive ] = SelectConnection()+1;
+
+ Reply[2] = (UCHAR)(Handle & 0xff);
+ Reply[3] = (UCHAR)(0xff); //BUGBUG should be effective rights
+ setAL(0); // Successful
+ }
+ }
+
+ } else if ( Request[2] == 0x14 ) {
+
+ UCHAR DirHandle = Request[3];
+ UCHAR Drive;
+ CONN_INDEX Connection = SelectConnection();
+
+ NwPrint(("Nw32: Deallocate directory handle %d on Connection %d\n", DirHandle, Connection));
+
+ for (Drive = 0; Drive < MD; Drive++) {
+
+
+ NwPrint(("Nw32: Drive %c: is DirHandle %d, Connection %d\n",
+ 'A' + Drive,
+ pNwDosTable->DriveHandleTable[Drive],
+ pNwDosTable->DriveIdTable[ Drive ]-1 ));
+
+ if ((pNwDosTable->DriveHandleTable[Drive] == DirHandle) &&
+ (pNwDosTable->DriveIdTable[ Drive ] == Connection+1)) {
+
+ //
+ // This is effectively a net use del!
+ //
+
+ NwPrint(("Nw32: Deallocate directory handle %c\n", 'A' + Drive));
+
+ ResetDrive(Drive);
+
+ setAL(0);
+
+ return;
+ }
+ }
+
+ setAL(0x9b); // Bad directory handle
+ return;
+
+ } else {
+
+ SendNCP(pNwDosTable->SavedAx);
+ }
+
+ FormattedDump( Reply, Reply[0] );
+}
+
+VOID
+ResetDrive(
+ UCHAR Drive
+ )
+/*++
+
+Routine Description:
+
+ Do a net use del
+
+Arguments:
+
+ Drive - Supplies the target drive.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ NwPrint(("Nw32: Reset Drive %c:\n", 'A' + Drive ));
+
+ if ((pNwDosTable->DriveFlagTable[ Drive ] &
+ ( PERMANENT_NETWORK_DRIVE | TEMPORARY_NETWORK_DRIVE )) == 0) {
+
+ return;
+
+ }
+
+ if (Win32DirectoryHandleTable[Drive] != 0) {
+
+ CloseHandle( Win32DirectoryHandleTable[Drive] );
+ Win32DirectoryHandleTable[Drive] = 0;
+
+ }
+
+ if (Drive <= (L'Z' - L'A')) {
+
+ DWORD WStatus;
+ WCHAR DriveString[3];
+
+ DriveString[0] = L'A' + Drive;
+ DriveString[1] = L':';
+ DriveString[2] = L'\0';
+
+ WStatus = WNetCancelConnection2W( DriveString, 0, TRUE);
+
+ if( WStatus != NO_ERROR ) {
+ NwPrint(("Nw32: WNetCancelConnection2W failed %d\n", WStatus ));
+ }
+
+ }
+
+ // Turn off flags that show this drive as redirected
+
+ pNwDosTable->DriveFlagTable[ Drive ] &=
+ ~( PERMANENT_NETWORK_DRIVE | TEMPORARY_NETWORK_DRIVE );
+
+ pNwDosTable->DriveHandleTable[Drive] = 0;
+}
+
+VOID
+AllocateDirectoryHandle2(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Allocate root drive
+
+ ASSUMES called from Nw16Handler
+
+Arguments:
+
+ BL supplies drive to map.
+ DS:DX supplies the pathname
+
+ AL returns the completion code.
+
+
+Return Value:
+
+ None.
+
+--*/
+{
+ UCHAR Drive = getBL()-1;
+
+ PUCHAR Name=GetVDMPointer (
+ (ULONG)((getDS() << 16)|getDX()),
+ 256, // longest valid path
+ CpuInProtectMode
+ );
+
+ NETRESOURCE Nr;
+ WCHAR DriveString[3];
+ ULONG Handle;
+
+ NwPrint(("Nw32: e905 map drive %c to %s\n", Drive + 'A', Name ));
+
+ if (Drive >= MD) {
+ setAL( 0x98 ); // Volume does not exist
+ setCF(1);
+ return;
+ }
+
+ if (pNwDosTable->DriveHandleTable[Drive] != 0) {
+
+ NwPrint(("Nw32: Drive already redirected\n"));
+ ResetDrive(Drive);
+
+ }
+
+
+ NwPrint(("Nw32: Allocate permanent directory handle\n"));
+
+ if (Drives[Drive] != NULL) {
+
+ // Tidy up the old name for this drive.
+
+ LocalFree( Drives[Drive] );
+ Drives[Drive] = NULL;
+ }
+
+ //
+ // This is effectively a net use!
+ //
+
+ ZeroMemory( &Nr, sizeof(NETRESOURCE));
+
+ Nr.lpRemoteName = BuildUNC( Name, strlen(Name));
+ // Save where this drive points.
+ Drives[Drive] = Nr.lpRemoteName;
+
+ if (Drive <= (L'Z' - L'A')) {
+ DriveString[0] = L'A' + Drive; // A through Z
+ DriveString[1] = L':';
+ DriveString[2] = L'\0';
+ Nr.lpLocalName = DriveString;
+ Nr.dwType = RESOURCETYPE_DISK;
+
+ if (NO_ERROR != WNetAddConnection2W( &Nr, NULL, NULL, 0)) {
+
+ NwPrint(("Nw32: Allocate0 ->%d\n", GetLastError()));
+
+ if (GetLastError() == ERROR_ALREADY_ASSIGNED) {
+
+ WNetCancelConnection2W( DriveString, 0, TRUE);
+
+ if (NO_ERROR != WNetAddConnection2W( &Nr, NULL, NULL, 0)) {
+
+ NwPrint(("Nw32: Allocate1 ->%d\n", GetLastError()));
+ ResetDrive( Drive );
+ setAL(0x03); // Volume does not exist
+ setCF(1);
+ return;
+ }
+
+ } else {
+
+ NwPrint(("Nw32: Allocate2 ->%d\n", GetLastError()));
+ ResetDrive( Drive );
+ setAL(0x03); // Volume does not exist
+ setCF(1);
+ return;
+ }
+ }
+ }
+
+ //
+ // Set flags so that GetDirectory2 will open handle
+ //
+ pNwDosTable->DriveIdTable[ Drive ] = SelectConnection()+1;
+ pNwDosTable->DriveFlagTable[ Drive ] = PERMANENT_NETWORK_DRIVE;
+
+ Handle = GetDirectoryHandle2( Drive );
+
+ if (Handle == 0xffffffff) {
+
+ ResetDrive( Drive );
+ setAL(0x03); // Invalid path
+ setCF(1);
+
+ } else {
+
+ setAL(0); // Successful
+
+ }
+
+ NwPrint(("Nw32: Returning %x\n",getAL()));
+}
+
+PWCHAR
+BuildUNC(
+ IN PUCHAR aName,
+ IN ULONG aLength
+ )
+/*++
+
+Routine Description:
+
+ This routine takes the ansi name, prepends the appropriate server name
+ (if appropriate) and converts to Unicode.
+
+Arguments:
+
+ IN aName - Supplies the ansi name.
+ IN aLength - Supplies the ansi name length in bytes.
+
+Return Value:
+
+ Unicode string
+
+--*/
+{
+ UNICODE_STRING Name;
+ UCHAR ServerName[sizeof(SERVERNAME)+1];
+
+ CONN_INDEX Connection;
+ ANSI_STRING TempAnsi;
+ UNICODE_STRING TempUnicode;
+ USHORT x;
+
+ // conversion rules for aName to Name are:
+
+ // foo: "\\server\foo\"
+ // foo:bar\baz "\\server\foo\bar\baz"
+ // foo:\bar\baz "\\server\foo\bar\baz"
+
+
+#ifdef NWDBG
+ TempAnsi.Buffer = aName;
+ TempAnsi.Length = (USHORT)aLength;
+ TempAnsi.MaximumLength = (USHORT)aLength;
+ NwPrint(("Nw32: BuildUNC %Z\n", &TempAnsi));
+#endif
+
+ Connection = SelectConnection();
+ if ( Connection == 0xff ) {
+ return NULL;
+ }
+
+ Name.MaximumLength = (USHORT)(aLength + sizeof(SERVERNAME) + 5) * sizeof(WCHAR);
+ Name.Buffer = (PWSTR)LocalAlloc( LMEM_FIXED, (ULONG)Name.MaximumLength);
+
+ if (Name.Buffer == NULL) {
+ return NULL;
+ }
+
+ Name.Length = 4;
+ Name.Buffer[0] = L'\\';
+ Name.Buffer[1] = L'\\';
+
+ //
+ // Be careful because ServerName might be 48 bytes long and therefore
+ // not null terminated.
+ //
+
+ RtlCopyMemory( ServerName, pNwDosTable->ServerNameTable[Connection], sizeof(SERVERNAME) );
+ ServerName[sizeof(ServerName)-1] = '\0';
+
+ RtlInitAnsiString( &TempAnsi, ServerName );
+ RtlAnsiStringToUnicodeString( &TempUnicode, &TempAnsi, TRUE);
+ RtlAppendUnicodeStringToString( &Name, &TempUnicode );
+ RtlFreeUnicodeString( &TempUnicode );
+
+ // Now pack servername to volume seperator if necessary.
+
+ if ((aLength != 0) &&
+ (aName[0] != '\\')) {
+ RtlAppendUnicodeToString( &Name, L"\\");
+ }
+
+ // aName might not be null terminated so be careful creating TempAnsi
+ TempAnsi.Buffer = aName;
+ TempAnsi.Length = (USHORT)aLength;
+ TempAnsi.MaximumLength = (USHORT)aLength;
+
+ if (!NT_SUCCESS(RtlAnsiStringToUnicodeString( &TempUnicode, &TempAnsi, TRUE))) {
+ LocalFree( Name.Buffer );
+ return NULL;
+ }
+
+ RtlAppendUnicodeStringToString( &Name, &TempUnicode );
+
+ // If the name already has a volume seperator then don't add another.
+ for (x=0; x < (Name.Length/sizeof(WCHAR)) ; x++ ) {
+
+ if (Name.Buffer[x] == L':') {
+
+ // Strip the colon if it is immediately followed by a backslash
+
+ if (((Name.Length/sizeof(WCHAR))-1 > x) &&
+ (Name.Buffer[x+1] == L'\\')) {
+
+ RtlMoveMemory( &Name.Buffer[x],
+ &Name.Buffer[x+1],
+ Name.Length - ((x + 1) * sizeof(WCHAR)));
+ Name.Length -= sizeof(WCHAR);
+
+ } else {
+
+ // Replace the colon with a backslash
+ Name.Buffer[x] = L'\\';
+
+ }
+ goto skip;
+ }
+ }
+
+
+skip:
+
+ RtlFreeUnicodeString( &TempUnicode );
+
+ // Strip trailing backslash if present.
+
+ if ((Name.Length >= sizeof(WCHAR) ) &&
+ (Name.Buffer[(Name.Length/sizeof(WCHAR)) - 1 ] == L'\\')) {
+
+ Name.Length -= sizeof(WCHAR);
+ }
+
+ // Return pointer to a null terminated wide char string.
+
+ Name.Buffer[Name.Length/sizeof(WCHAR)] = L'\0';
+ NwPrint(("Nw32: BuildUNC %ws\n", Name.Buffer));
+
+ return Name.Buffer;
+}
+
+
+VOID
+GetServerDateAndTime(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Implement Funtion E7h
+
+ ASSUMES called from Nw16Handler
+
+Arguments:
+
+ none.
+
+Return Value:
+
+ none.
+
+--*/
+{
+
+ PUCHAR Reply = GetVDMPointer (
+ (ULONG)((getDS() << 16)|getDX()),
+ 7,
+ CpuInProtectMode
+ );
+
+ SendNCP2( NWR_ANY_NCP(0x14), NULL, 0, Reply, 7 );
+
+}
+
+VOID
+GetShellVersion(
+ IN USHORT Command
+ )
+/*++
+
+Routine Description:
+
+ Get the environment variables. Needs to be configurable for
+ Japanese machines.
+
+Arguments:
+
+ Command supplies the callers AX.
+
+Return Value:
+
+ none.
+
+--*/
+{
+
+ setAX(0); // MSDOS, PC
+ setBX(0x031a); // Shell version
+ setCX(0);
+
+ if ( (Command & 0x00ff) != 0) {
+
+ LONG tmp;
+ HKEY Key = NULL;
+ PUCHAR Reply = GetVDMPointer (
+ (ULONG)((getES() << 16)|getDI()),
+ 40,
+ CpuInProtectMode
+ );
+
+ ASSERT( sizeof(CLIENT_ID_STRING) <= 40 );
+
+ RtlMoveMemory( Reply, CLIENT_ID_STRING, sizeof(CLIENT_ID_STRING) );
+
+
+ //
+ // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
+ // \NWCWorkstation\Parameters
+ //
+ tmp = RegOpenKeyExW(
+ HKEY_LOCAL_MACHINE,
+ NW_WORKSTATION_REGKEY,
+ REG_OPTION_NON_VOLATILE, // options
+ KEY_READ, // desired access
+ &Key
+ );
+
+ if (tmp != ERROR_SUCCESS) {
+ return;
+ }
+
+ tmp = 40; // Max size for the string.
+
+ RegQueryValueExA(
+ Key,
+ "ShellVersion",
+ NULL,
+ NULL,
+ Reply,
+ &tmp);
+
+ ASSERT( tmp <= 40 );
+
+ RegCloseKey( Key );
+
+ }
+}
+
+#include <packon.h>
+
+typedef struct _TTSOUTPACKETTYPE {
+ UCHAR SubFunction;
+ USHORT cx;
+ USHORT dx;
+} TTSOUTPACKETTYPE;
+
+typedef struct _TTSINPACKETTYPE {
+ USHORT cx;
+ USHORT dx;
+} TTSINPACKETTYPE;
+
+#include <packoff.h>
+
+VOID
+TTS(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Transaction Tracking System
+
+Arguments:
+
+ none.
+
+Return Value:
+
+ none.
+
+--*/
+{
+ UCHAR bOutput;
+ UCHAR bInput[2];
+
+ TTSINPACKET TTsInPacket;
+ TTSOUTPACKET TTsOutPacket;
+
+
+ switch ( pNwDosTable->SavedAx & 0x00ff )
+ {
+ case 2:
+ // NCP Tts Available
+ bOutput = 0;
+ SendNCP2( NWR_ANY_F2_NCP(0x22), &bOutput, sizeof(UCHAR), NULL, 0);
+
+ if (getAL() == 0xFF) {
+ setAL(01);
+ }
+ break;
+
+ case 0:
+ // NCP Tts Begin/Abort
+ bOutput = 1;
+ SendNCP2( NWR_ANY_F2_NCP(0x22), &bOutput, sizeof(UCHAR), NULL, 0);
+ break;
+
+ case 3:
+ // NCP Tts Begin/Abort
+ bOutput = 3;
+ SendNCP2( NWR_ANY_F2_NCP(0x22), &bOutput, sizeof(UCHAR), NULL, 0);
+ break;
+
+ case 1:
+ // NCP Tts End
+ bOutput = 2;
+ SendNCP2( NWR_ANY_F2_NCP(0x22),
+ &bOutput, sizeof(UCHAR),
+ (PUCHAR)&TTsInPacket, sizeof(TTsInPacket));
+
+ setCX(TTsInPacket.cx);
+ setDX(TTsInPacket.dx);
+ break;
+
+ case 4:
+ // NCP Tts Status
+ TTsOutPacket.SubFunction = 4;
+ TTsOutPacket.cx = getCX();
+ TTsOutPacket.dx = getDX();
+
+ SendNCP2( NWR_ANY_F2_NCP(0x22),
+ (PUCHAR)&TTsOutPacket, sizeof(TTsOutPacket),
+ NULL, 0);
+
+ break;
+
+ case 5:
+ case 7:
+ // NCP Tts Get App/Station Thresholds
+ bOutput = (pNwDosTable->SavedAx & 0x00ff);
+
+ SendNCP2( NWR_ANY_F2_NCP(0x22),
+ &bOutput, sizeof(UCHAR),
+ bInput, sizeof(bInput));
+
+ setCX( (USHORT)((bInput[0] << 8 ) || bInput[1]) );
+ break;
+
+ case 6:
+ case 8:
+ // NCP Tts Set App/Station Thresholds
+ TTsOutPacket.SubFunction = (pNwDosTable->SavedAx & 0x00ff);
+ TTsOutPacket.cx = getCX();
+ SendNCP2( NWR_ANY_F2_NCP(0x22),
+ (PUCHAR)&TTsOutPacket, sizeof(UCHAR) + sizeof(USHORT),
+ NULL, 0);
+ break;
+
+ default:
+ pNwDosTable->SavedAx = 0xc7FF;
+ break;
+ }
+ return;
+}
+
+VOID
+OpenCreateFile(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Look at the file being opened to determine if it is
+ a compatibility mode open to a file on a NetWare drive.
+
+Arguments:
+
+ none.
+
+Return Value:
+
+ none.
+
+--*/
+{
+ WORD Command = pNwDosTable->SavedAx;
+
+ PUCHAR Name;
+
+
+ if ((Command & OF_SHARE_MASK ) != OF_SHARE_COMPAT) {
+ return;
+ }
+
+ Name = GetVDMPointer (
+ (ULONG)((getDS() << 16)|getDX()),
+ 256,
+ CpuInProtectMode
+ );
+
+
+ NwPrint(("Nw16Handler Compatibility Open of %s\n", Name ));
+
+ //
+ // We already know its a Create or Open with sharing options
+ // set to compatibility mode or the tsr wouldn't have bopped to us.
+ //
+
+
+ if (IsItNetWare(Name)) {
+
+ SetCompatibility();
+
+ }
+}
+
+BOOL
+IsItNetWare(
+ PUCHAR Name
+ )
+/*++
+
+Routine Description:
+
+ Look at the filename being opened to determine if it is on a NetWare drive.
+
+Arguments:
+
+ none.
+
+Return Value:
+
+ none.
+
+--*/
+{
+ UCHAR Drive;
+
+ Drive = tolower(Name[0])-'a';
+
+ NwPrint(("Nw16Handler IsItNetWare %s\n", Name ));
+
+ if (Name[1] == ':') {
+
+ if (pNwDosTable->DriveFlagTable[Drive] == LOCAL_DRIVE) {
+
+ // Definitely not a netware drive.
+ return FALSE;
+ }
+
+ } else if ((IS_ASCII_PATH_SEPARATOR(Name[0])) &&
+ (IS_ASCII_PATH_SEPARATOR(Name[0]))) {
+
+ // Assume only UNC names that the tsr built are NetWare
+
+ if ((getDS() == DosTableSegment ) &&
+ (getDX() == (WORD)(DosTableOffset + FIELD_OFFSET(NWDOSTABLE, DeNovellBuffer[0] )))) {
+
+ return TRUE;
+ }
+
+ return FALSE;
+
+ } else {
+
+ Drive = pNwDosTable->CurrentDrive;
+
+ }
+
+ //
+ // If this is a drive we don't know about, refresh our tables.
+ //
+
+ if (pNwDosTable->DriveFlagTable[Drive] == 0 ) {
+
+ Nw16Register();
+
+ }
+
+ if (pNwDosTable->DriveFlagTable[Drive] &
+ (TEMPORARY_NETWORK_DRIVE | PERMANENT_NETWORK_DRIVE )) {
+
+ return TRUE;
+
+ }
+
+ return FALSE;
+
+}
+
+VOID
+SetCompatibility(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Take the Create/Open file request in AX and modify appropriately
+
+Arguments:
+
+ none.
+
+Return Value:
+
+ none.
+
+--*/
+{
+ WORD Command = getAX();
+
+ if (( Command & OF_READ_WRITE_MASK) == OF_READ ) {
+
+ setAX((WORD)(Command | OF_SHARE_DENY_WRITE));
+
+ } else {
+
+ setAX((WORD)(Command | OF_SHARE_EXCLUSIVE));
+
+ }
+
+}
+
+VOID
+OpenQueueFile(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Build the UNC filename \\server\queue using the contents of the shared
+ datastructures and the CreateJobandFile NCP.
+
+Arguments:
+
+ none.
+
+Return Value:
+
+ none.
+
+--*/
+{
+
+ CONN_INDEX Connection = SelectConnection();
+ PUCHAR Request;
+ PUCHAR Buffer = pNwDosTable->DeNovellBuffer;
+ int index;
+
+ if ( Connection == 0xff ) {
+ //
+ // No need to return an errorcode. The NCP exchange
+ // will fail and give an appropriate call to the application.
+ //
+
+ return;
+ }
+
+ if ( ServerHandles[Connection] == NULL ) {
+
+ NTSTATUS status;
+
+ status = OpenConnection( Connection );
+
+ if (!NT_SUCCESS(status)) {
+ SetStatus(status);
+ return;
+ }
+ }
+
+ //
+ // CreateJobandQueue open in progress. The purpose of this
+ // open being processed is to translate the information in
+ // the CreateJob NCP into a pathname to be opened by the 16
+ // bit code.
+ //
+
+
+ //
+ // Users DS:SI points at a CreateJob NCB. Inside the request is
+ // the objectid of the queue. Ask the server for the queue name.
+ //
+
+ Request = GetVDMPointer (
+ (ULONG)((getDS() << 16)|getSI()),
+ 8,
+ CpuInProtectMode);
+
+ NwlibMakeNcp(
+ ServerHandles[Connection],
+ FSCTL_NWR_NCP_E3H,
+ 7, // RequestSize
+ 61, // ResponseSize
+ "br|_r",
+ 0x36, // Get Bindery Object Name
+ Request+3, 4,
+ 6, // Skip ObjectId and Type
+ pNwDosTable->DeNovellBuffer2, 48 );
+
+
+ pNwDosTable->DeNovellBuffer2[54] = '\0';
+
+ Buffer[0] = '\\';
+ Buffer[1] = '\\';
+ Buffer += 2; // Point to after backslashes
+
+ // Copy the servername
+ for (index = 0; index < sizeof(SERVERNAME); index++) {
+ Buffer[index] = pNwDosTable->ServerNameTable[Connection][index];
+ if (Buffer[index] == '\0') {
+ break;
+ }
+ }
+
+ Buffer[index] = '\\';
+
+ RtlCopyMemory( &Buffer[index+1], &pNwDosTable->DeNovellBuffer2[0], 48 );
+
+ NwPrint(("Nw32: CreateQueue Job and File %s\n", pNwDosTable->DeNovellBuffer));
+
+ //
+ // Set up 16 bit registers to do the DOS OpenFile for \\server\queue
+ //
+
+ setDS((WORD)(CpuInProtectMode ? pNwDosTable->PmSelector : DosTableSegment));
+ setDX( (WORD)(DosTableOffset + FIELD_OFFSET(NWDOSTABLE, DeNovellBuffer[0] )) );
+ setAX(0x3d02); // Set to OpenFile
+
+}
+
+VOID
+AttachHandle(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This routine implements Int 21 B4. Which is supposed to create a
+ Dos Handle that corresponds to a specified 6 byte NetWare handle.
+
+ This is used as a replacement for doing a DosOpen on "NETQ" and usin the
+ handle returned from there.
+
+Arguments:
+
+ none.
+
+Return Value:
+
+ none.
+
+--*/
+{
+
+ if ( pNwDosTable->CreatedJob ) {
+
+ NwPrint(("Nw32: AttachHandle %x\n", pNwDosTable->JobHandle));
+ setAX( pNwDosTable->JobHandle );
+ pNwDosTable->CreatedJob = 0; // Only return it once.
+
+ } else {
+
+ NwPrint(("Nw32: AttachHandle failed, no job\n"));
+ setAX(ERROR_FILE_NOT_FOUND);
+ setCF(1);
+
+ }
+}
+
+VOID
+ProcessExit(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Cleanup all cached handles. Unmap all temporary drives.
+
+ Cleanup the server name table so that if another dos app
+ is started we reload all the useful information such as
+ the servers connection number.
+
+ Note: Dos always completes processing after we complete.
+
+Arguments:
+
+ none.
+
+Return Value:
+
+ none.
+
+--*/
+{
+ UCHAR Connection;
+ UCHAR Drive;
+ USHORT Command = pNwDosTable->SavedAx;
+
+ ResetLocks();
+
+ for (Drive = 0; Drive < MD; Drive++) {
+
+ NwPrint(("Nw32: Deallocate directory handle %c\n", 'A' + Drive));
+
+ if (Win32DirectoryHandleTable[Drive] != 0) {
+
+ CloseHandle( Win32DirectoryHandleTable[Drive] );
+ Win32DirectoryHandleTable[Drive] = 0;
+ pNwDosTable->DriveHandleTable[Drive] = 0;
+
+ }
+ }
+
+ for (Connection = 0; Connection < MC ; Connection++ ) {
+ if (pNwDosTable->ConnectionIdTable[Connection].ci_InUse == IN_USE) {
+
+ CloseConnection(Connection);
+
+ pNwDosTable->ConnectionIdTable[Connection].ci_InUse = FREE;
+
+ ZeroMemory( pNwDosTable->ServerNameTable[Connection], SERVERNAME_LENGTH );
+ }
+ }
+
+ pNwDosTable->PreferredServer = 0;
+
+ LockMode = 0;
+ TablesValid = FALSE;
+ DriveHandleTableValid = FALSE;
+
+#if NWDBG
+ if (DebugCtrl & ~3 ) {
+ DebugControl( 2 ); // Close logfile
+ }
+ GotDebugState = FALSE;
+#endif
+
+ //
+ // set AX register so that AH gets preserved
+ //
+
+ setAX( Command );
+}
+
+VOID
+SystemLogout(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This api is called by the NetWare login.
+
+ Remove all NetWare redirected drives and logout connections
+ that don't have open handles on them. Don't detach the connections.
+
+Arguments:
+
+ none.
+
+Return Value:
+
+ none.
+
+--*/
+{
+
+ UCHAR Connection;
+ UCHAR Drive;
+ USHORT Command = pNwDosTable->SavedAx;
+
+ ResetLocks();
+
+ for (Drive = 0; Drive < MD; Drive++) {
+ ResetDrive(Drive);
+ }
+
+ for (Connection = 0; Connection < MC ; Connection++ ) {
+ if (pNwDosTable->ConnectionIdTable[Connection].ci_InUse == IN_USE) {
+
+ if ( ServerHandles[Connection] == NULL ) {
+ OpenConnection( Connection );
+ }
+
+ if (ServerHandles[Connection] != NULL ) {
+
+ NwlibMakeNcp(
+ ServerHandles[Connection],
+ NWR_ANY_F2_NCP(NCP_LOGOUT),
+ 0, // RequestSize
+ 0, // ResponseSize
+ "");
+
+ CloseConnection(Connection);
+ }
+
+ //pNwDosTable->ConnectionIdTable[Connection].ci_InUse = FREE;
+
+ //ZeroMemory( pNwDosTable->ServerNameTable[Connection], SERVERNAME_LENGTH );
+ }
+ }
+
+ pNwDosTable->PreferredServer = 0;
+ pNwDosTable->PrimaryServer = 0;
+
+ // No servers in the table so find the nearest/preferred.
+
+ LoadPreferredServerName();
+
+ //
+ // set AX register so that AH gets preserved
+ // and AL says success.
+ //
+
+ setAX( (USHORT)(Command & 0xff00) );
+}
+
+UCHAR
+AttachmentControl(
+ ULONG Command
+ )
+/*++
+
+Routine Description:
+
+ Implement Funtion F1h
+
+Arguments:
+
+ none.
+
+Return Value:
+
+ Return status.
+
+--*/
+{
+ UCHAR Connection = getDL();
+
+ if ((Connection < 1) ||
+ (Connection > MC)) {
+ return 0xf7;
+ }
+
+ Connection -= 1;
+
+ switch (Command & 0x00ff) {
+
+ case 0: // Attach
+
+ NwPrint(("Nw16AttachmentControl: Attach connection %d\n", Connection));
+
+ pNwDosTable->ConnectionIdTable[Connection].ci_InUse = IN_USE;
+
+ if ( ServerHandles[Connection] == NULL ) {
+
+ NTSTATUS status = OpenConnection( Connection );
+
+ if (!NT_SUCCESS(status)) {
+ pNwDosTable->ConnectionIdTable[Connection].ci_InUse = FREE;
+ ZeroMemory( pNwDosTable->ServerNameTable[Connection], SERVERNAME_LENGTH );
+ return (UCHAR)RtlNtStatusToDosError(status);
+ } else {
+ InitConnection(Connection);
+ }
+ }
+
+ return 0;
+ break;
+
+ case 1: // Detach
+
+ NwPrint(("Nw16AttachmentControl: Detach connection %d\n", Connection));
+
+ if (pNwDosTable->ConnectionIdTable[Connection].ci_InUse != IN_USE) {
+ return 0xff;
+ } else {
+
+ pNwDosTable->ConnectionIdTable[Connection].ci_InUse = FREE;
+
+ if (ServerHandles[Connection] != NULL ) {
+ CloseConnection(Connection);
+ }
+
+ ZeroMemory( pNwDosTable->ServerNameTable[Connection], SERVERNAME_LENGTH );
+
+ if (pNwDosTable->PrimaryServer == (UCHAR)Connection + 1 ) {
+
+ // Need to pick another
+ UCHAR IndexConnection;
+
+ pNwDosTable->PrimaryServer = 0;
+
+ for (IndexConnection = 0; IndexConnection < MC ; IndexConnection++ ) {
+
+ if (pNwDosTable->ConnectionIdTable[IndexConnection].ci_InUse == IN_USE) {
+
+ pNwDosTable->PrimaryServer = IndexConnection + 1;
+
+ }
+ }
+
+ }
+
+ if (pNwDosTable->PreferredServer == (UCHAR)Connection + 1 ) {
+ pNwDosTable->PreferredServer = 0;
+ }
+
+ return 0;
+ }
+
+ case 2: // Logout
+
+ NwPrint(("Nw16AttachmentControl: Logout connection %d\n", Connection));
+
+ if (pNwDosTable->ConnectionIdTable[Connection].ci_InUse != IN_USE) {
+ return 0xff;
+ } else {
+
+ UCHAR Drive;
+
+ if ( ServerHandles[Connection] == NULL ) {
+ OpenConnection( Connection );
+ }
+
+ for (Drive = 0; Drive < MD; Drive++ ) {
+ if (pNwDosTable->DriveIdTable[ Drive ] == (Connection + 1)) {
+ ResetDrive(Drive);
+ }
+ }
+
+ if (ServerHandles[Connection] != NULL ) {
+ NwlibMakeNcp(
+ ServerHandles[Connection],
+ NWR_ANY_F2_NCP(NCP_LOGOUT),
+ 0, // RequestSize
+ 0, // ResponseSize
+ "");
+ CloseConnection(Connection);
+ }
+
+ return 0;
+ }
+
+ }
+ return 0xff;
+}
+
+VOID
+ServerFileCopy(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Build the NCP that tells the server to move a file on the server.
+
+Arguments:
+
+ none.
+
+Return Value:
+
+ none.
+
+--*/
+{
+
+ DWORD BytesReturned;
+ UCHAR SrcHandle[6];
+ UCHAR DestHandle[6];
+ NTSTATUS status;
+ PUCHAR Buffer;
+
+ Buffer = GetVDMPointer (
+ (ULONG)((getES() << 16)|getDI()),
+ 16,
+ CpuInProtectMode
+ );
+
+ if ( DeviceIoControl(
+ GET_NT_SRCHANDLE(),
+ IOCTL_NWR_RAW_HANDLE,
+ NULL,
+ 0,
+ (PUCHAR)&SrcHandle,
+ sizeof(SrcHandle),
+ &BytesReturned,
+ NULL ) == FALSE ) {
+
+ setAL(0xff);
+ return;
+
+ }
+
+ if ( DeviceIoControl(
+ GET_NT_HANDLE(),
+ IOCTL_NWR_RAW_HANDLE,
+ NULL,
+ 0,
+ (PUCHAR)&DestHandle,
+ sizeof(DestHandle),
+ &BytesReturned,
+ NULL ) == FALSE ) {
+
+ setAL(0xff);
+ return;
+
+ }
+
+ status = NwlibMakeNcp(
+ GET_NT_SRCHANDLE(),
+ NWR_ANY_F2_NCP(0x4A),
+ 25, // RequestSize
+ 4, // ResponseSize
+ "brrddd|d",
+ 0,
+ SrcHandle, 6,
+ DestHandle, 6,
+ *(DWORD UNALIGNED*)&Buffer[4],
+ *(DWORD UNALIGNED*)&Buffer[8],
+ *(DWORD UNALIGNED*)&Buffer[12],
+ &BytesReturned
+ );
+
+ setDX((WORD)(BytesReturned >> 16));
+ setCX((WORD)BytesReturned);
+
+ if (!NT_SUCCESS(status)) {
+ SetStatus(status);
+ return;
+ } else {
+ setAL(0);
+ }
+}
+
+VOID
+SetStatus(
+ NTSTATUS Status
+ )
+/*++
+
+Routine Description:
+
+ Convert an NTSTATUS into the appropriate register settings and updates
+ to the dos tables.
+
+Arguments:
+
+ none.
+
+Return Value:
+
+ none.
+
+--*/
+{
+ UCHAR DosStatus = (UCHAR)RtlNtStatusToDosError(Status);
+
+ if ((!DosStatus) &&
+ (Status != 0)) {
+
+ //
+ // We have a connection bit set
+ //
+
+ if ( Status & (NCP_STATUS_BAD_CONNECTION << 8)) {
+ DosStatus = 0xfc;
+ } else {
+ DosStatus = 0xff;
+ }
+ }
+
+ if (DosStatus) {
+ setCF(1);
+ }
+
+ setAL(DosStatus);
+}
diff --git a/private/nw/nw16/dll/nwapi16.rc b/private/nw/nw16/dll/nwapi16.rc
new file mode 100644
index 000000000..18206f077
--- /dev/null
+++ b/private/nw/nw16/dll/nwapi16.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "NW Windows/Dos API DLL"
+#define VER_INTERNALNAME_STR "NwApi16.DLL"
+#define VER_ORIGINALFILENAME_STR "NwApi16.DLL"
+
+#include "common.ver"
+
diff --git a/private/nw/nw16/dll/nwapi16.src b/private/nw/nw16/dll/nwapi16.src
new file mode 100644
index 000000000..6036c090d
--- /dev/null
+++ b/private/nw/nw16/dll/nwapi16.src
@@ -0,0 +1,10 @@
+LIBRARY NWAPI16
+
+DESCRIPTION 'NWAPI16'
+
+EXPORTS
+
+ Nw16Register
+ Nw16Handler
+
+DATA SINGLE SHARED
diff --git a/private/nw/nw16/dll/procs.h b/private/nw/nw16/dll/procs.h
new file mode 100644
index 000000000..cf51577cc
--- /dev/null
+++ b/private/nw/nw16/dll/procs.h
@@ -0,0 +1,159 @@
+
+/*++
+
+Copyright (c) 1993/4 Microsoft Corporation
+
+Module Name:
+
+ procs.c
+
+Abstract:
+
+ Common header file for routines which support 16 bit
+ applications.
+
+Author:
+
+ Colin Watson (colinw) 21-Nov-1993
+
+Environment:
+
+
+Revision History:
+
+
+--*/
+
+#ifndef DBG
+#define DBG 0
+#endif
+
+#if !DBG
+#undef NWDBG
+#endif
+
+#define UNICODE
+
+#include <stdlib.h>
+
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+#include <windows.h>
+
+#include <string.h> // strcmp
+#include <stdio.h>
+#include <stdarg.h>
+#include <debugfmt.h> // FORMAT_LPSTR
+
+#include <nwapi.h>
+#include <nwxchg.h>
+#include <ntddnwfs.h>
+#include <npapi.h>
+#include <nwrnames.h>
+
+#include <vddsvc.h>
+#include <nwdos.h>
+#include <ncp.h>
+
+// Locks.c
+
+VOID
+Locks(
+ USHORT Command
+ );
+
+VOID
+InitLocks(
+ VOID
+ );
+
+VOID
+ResetLocks(
+ VOID
+ );
+
+
+// Ncp.c
+
+extern PNWDOSTABLE pNwDosTable;
+extern HANDLE ServerHandles[MC];
+
+CONN_INDEX
+SelectConnection(
+ VOID
+ );
+
+NTSTATUS
+OpenConnection(
+ CONN_INDEX Connection
+ );
+
+ULONG
+GetDirectoryHandle2(
+ DWORD Drive
+ );
+
+
+#define GET_NT_HANDLE() (HANDLE)(pNwDosTable->NtHandleHi << 16 | pNwDosTable->NtHandleLow)
+#define GET_NT_SRCHANDLE() (HANDLE)(pNwDosTable->NtHandleSrcHi << 16 | pNwDosTable->NtHandleSrcLow)
+
+
+//
+// MSW_PE: Machine Status Word Protect-mode enable bit
+//
+
+#ifndef MSW_PE
+#define MSW_PE 0x0001
+#endif
+
+#undef getMSW // BUGBUG: there's no c_getMSW in the lib!!!
+extern WORD getMSW(VOID);
+
+#define IS_PROTECT_MODE() (UCHAR)((getMSW() & MSW_PE)? TRUE : FALSE)
+
+#if NWDBG
+
+#define NwPrint(String) NwPrintf String;
+
+VOID
+DebugControl(
+ int Command
+ );
+
+VOID
+NwPrintf(
+ char *Format,
+ ...
+ );
+
+VOID
+VrDumpRealMode16BitRegisters(
+ IN BOOL DebugStyle
+ );
+
+VOID
+VrDumpNwData(
+ VOID
+ );
+
+VOID
+DisplayExtendedError(
+ VOID
+ );
+
+VOID
+FormattedDump(
+ PCHAR far_p,
+ LONG len
+ );
+
+#else
+
+#define NwPrint(_x_)
+#define VrDumpRealMode16BitRegisters(_x_)
+#define VrDumpNwData( )
+#define DisplayExtendedError( )
+#define FormattedDump(_x_,_y_)
+
+#endif
diff --git a/private/nw/nw16/dll/sources b/private/nw/nw16/dll/sources
new file mode 100644
index 000000000..fe9eb5d4d
--- /dev/null
+++ b/private/nw/nw16/dll/sources
@@ -0,0 +1,71 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=nw
+MINORCOMP=nwapi16
+
+TARGETNAME=nwapi16
+TARGETPATH=$(BASEDIR)\public\sdk\lib
+TARGETTYPE=DYNLINK
+DLLDEF=obj\*\nwapi16.def
+#DLLENTRY=NwApiInitialize
+DLLBASE=0x6950000
+MSC_WARNING_LEVEL=/W3 /WX
+
+INCLUDES=..\..\inc;$(_NTROOT)\private\inc;$(_NTROOT)\private\mvdm\vdd\h;..\inc
+
+SOURCES= \
+ debug.c \
+ ncp.c \
+ locks.c \
+ nwapi16.rc
+
+TARGETLIBS= \
+ $(BASEDIR)\Public\Sdk\Lib\*\kernel32.lib \
+ $(BASEDIR)\Public\Sdk\Lib\*\advapi32.lib \
+ $(BASEDIR)\Public\Sdk\Lib\*\ntvdm.lib \
+ $(BASEDIR)\Public\Sdk\Lib\*\user32.lib \
+ $(BASEDIR)\Public\Sdk\Lib\*\mpr.lib \
+ $(BASEDIR)\Public\Sdk\Lib\*\nwapi32.lib \
+ $(BASEDIR)\Public\Sdk\Lib\*\nwprovau.lib
+
+UNICODE=1
+
+USE_NTDLL=1
+
+NET_C_DEFINES=-DRPC_NO_WINDOWS_H -DNWDBG=1
+
+UMTYPE=console
+
+UMTEST=
+
+UMLIBS= \
+ $(BASEDIR)\Public\Sdk\Lib\*\nwapi32.lib \
+ $(BASEDIR)\Public\Sdk\Lib\*\mpr.lib
+
+OPTIONAL_UMTEST=
+
+!IFDEF MARS_PCH
+PRECOMPILED_INCLUDE=procs.h
+PRECOMPILED_PCH=procs.pch
+PRECOMPILED_OBJ=procs.obj
+!ENDIF
diff --git a/private/nw/nw16/drv/dllentry.asm b/private/nw/nw16/drv/dllentry.asm
new file mode 100644
index 000000000..fce965935
--- /dev/null
+++ b/private/nw/nw16/drv/dllentry.asm
@@ -0,0 +1,81 @@
+PAGE,132
+;***************************************************************************
+;*
+;* DLLENTRY.ASM
+;*
+;* VER.DLL Entry code
+;*
+;* This module generates a code segment called INIT_TEXT.
+;* It initializes the local heap if one exists and then calls
+;* the C routine LibMain() which should have the form:
+;* BOOL FAR PASCAL LibMain(HANDLE hInstance,
+;* WORD wDataSeg,
+;* WORD cbHeap,
+;* LPSTR lpszCmdLine);
+;*
+;* The result of the call to LibMain is returned to Windows.
+;* The C routine should return TRUE if it completes initialization
+;* successfully, FALSE if some error occurs.
+;*
+;**************************************************************************
+
+ INCLUDE CMACROS.INC
+
+externFP <LIBMAIN> ;The C routine to be called
+
+ifndef SEGNAME
+ SEGNAME equ <_TEXT> ; default seg name
+endif
+
+createSeg %SEGNAME, CodeSeg, word, public, CODE
+
+
+sBegin CodeSeg ; this defines what seg this goes in
+assumes cs,CodeSeg
+
+?PLM=0 ;'C'naming
+externA <_acrtused> ;Ensures that Win DLL startup code is linked
+
+?PLM=1 ;'PASCAL' naming
+externFP <LOCALINIT> ;Windows heap init routine
+
+cProc LibEntry, <PUBLIC,FAR> ;Entry point into DLL
+
+cBegin
+ push di ;Handle of the module instance
+ push ds ;Library data segment
+ push cx ;Heap size
+ push es ;Command line segment
+ push si ;Command line offset
+
+ ;** If we have some heap then initialize it
+ jcxz callc ;Jump if no heap specified
+
+ ;** Call the Windows function LocalInit() to set up the heap
+ ;** LocalInit((LPSTR)start, WORD cbHeap);
+
+ xor ax,ax
+ cCall LOCALINIT <ds, ax, cx>
+ or ax,ax ;Did it do it ok ?
+ jz error ;Quit if it failed
+
+ ;** Invoke the C routine to do any special initialization
+
+callc:
+ call LIBMAIN ;Invoke the 'C' routine (result in AX)
+ jmp short exit ;LibMain is responsible for stack clean up
+
+error:
+ pop si ;Clean up stack on a LocalInit error
+ pop es
+ pop cx
+ pop ds
+ pop di
+exit:
+
+cEnd
+
+sEnd _thisseg
+
+ END LibEntry
+
diff --git a/private/nw/nw16/drv/ints.asm b/private/nw/nw16/drv/ints.asm
new file mode 100644
index 000000000..1dfe878ca
--- /dev/null
+++ b/private/nw/nw16/drv/ints.asm
@@ -0,0 +1,368 @@
+page ,132
+
+if 0
+
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ ints.asm
+
+Abstract:
+
+ Contains handler for Windows protect-mode NetwareRequest function, exported
+ by NETWARE.DRV. Code in this file access real mode memory via an LDT descriptor
+ created especially for this purpose. This selector gives us access to all
+ code and data contained in the Nw16 TSR
+
+Author:
+
+ Richard L Firth 22-Jan-1994
+
+Environment:
+
+ Windows protect mode only
+
+Revision History:
+
+ 22-Jan-1994 rfirth
+ Created
+
+--*/
+
+endif
+
+include nwdos.inc ; NWDOSTABLE_ASM structure
+include isvbop.inc ; DispatchCall
+
+.286
+.model medium,pascal
+
+_DATA segment word public 'DATA'
+
+OldInt21Handler dd ?
+RMSegment dw ?
+RMBase dw ? ; MUST be in this order - loaded
+RMSelector dw ? ; via lds dx,word ptr RMBase
+
+.errnz (RMSelector - (RMBase + 2))
+
+_DATA ends
+
+;
+; code segment ordering
+;
+
+INIT_TEXT segment byte public 'CODE'
+INIT_TEXT ends
+
+_TEXT segment byte public 'CODE'
+_TEXT ends
+
+;
+; macros
+;
+
+LOAD_DS macro
+ push _DATA
+ pop ds
+ assume ds:_DATA
+ endm
+
+SET_DS macro
+ push ds
+ LOAD_DS
+ endm
+
+RESTORE_DS macro
+ pop ds
+ assume ds:nothing
+ endm
+
+LOAD_RM_DS_BX macro
+ LOAD_DS
+ lds bx,dword ptr RMBase
+ assume ds:nothing
+ endm
+
+RESTORE_DS_BX macro
+ RESTORE_DS
+ pop bx
+ endm
+
+INIT_TEXT segment byte public 'CODE'
+
+ assume cs:INIT_TEXT
+
+ public GetLowRedirInfo
+GetLowRedirInfo proc far
+ mov ax,9f00h
+ int 21h ; get the RM data segment in BX
+ jc @f
+ SET_DS
+ mov RMSegment,bx
+ mov RMBase,dx
+ mov ax,2
+ int 31h
+ jc @f ; can't create selector
+ mov RMSelector,ax
+
+;
+; now that we have the selector, we write the selector value into the low
+; memory area. The 32-bit DLL will use this value when setting output DS or ES
+; register values if the call originated in Protect Mode
+;
+
+ lds bx,dword ptr RMBase
+ mov [bx]._PmSelector,ax
+
+;
+; we now hook int 21
+;
+
+ LOAD_DS
+ push es
+ mov ax,3521h
+ int 21h
+ mov word ptr OldInt21Handler,bx
+ mov word ptr OldInt21Handler[2],es
+ mov cx,_TEXT
+ mov dx,offset _TEXT:NewInt21Handler
+ mov ax,205h
+ mov bl,21h
+ int 31h
+ pop es
+ RESTORE_DS
+ xor ax,ax ; success: return TRUE
+ inc ax
+ ret
+@@: xor ax,ax ; failure: return FALSE
+ ret
+GetLowRedirInfo endp
+
+INIT_TEXT ends
+
+_TEXT segment byte public 'CODE'
+
+ assume cs:_TEXT
+
+ public NewInt21Handler
+NewInt21Handler proc far
+ sti
+ cmp ah,0e3h
+ jb @f
+ call far ptr NetwareRequest
+ retf 2
+@@: sub sp,4
+ push bp
+ mov bp,sp
+ push es
+ push bx
+ SET_DS
+ les bx,OldInt21Handler
+ mov [bp+2],bx
+ mov [bp+4],es
+ RESTORE_DS
+ pop bx
+ pop es
+ pop bp
+ retf
+NewInt21Handler endp
+
+ public NetwareRequest
+NetwareRequest proc far
+ push bx
+ push ds
+ LOAD_RM_DS_BX
+ cmp ah,0f0h
+ jne for_dll
+
+;
+; these are the 0xF000, 0xF001, 0xF002, 0xF004, 0xF005 calls that we can handle
+; here without having to BOP. All we need do is access the table in the shared
+; real-mode/protect-mode (low) memory
+;
+
+.errnz (_PrimaryServer - (_PreferredServer + 1))
+
+;
+; point bx at PreferredServer in the low memory area. If the request is a
+; PrimaryServer request (0xF004, 0xF005) then point bx at PrimaryServer
+;
+
+ lea bx,[bx]._PreferredServer; bx = offset of PreferredServer
+ cmp al,3
+ cmc
+ adc bx,0 ; bx = &PrimaryServer if F004 or F005
+ or al,al ; f000 = set preferred server
+ jz set_server
+ cmp al,4 ; f004 = set primary server
+ jnz try_01
+
+;
+; 0xF000 or 0xF004: set Preferred or Primary Server to value contained in DL.
+; If DL > 8, set respective server index to 0
+;
+
+set_server:
+ xor al,al
+ cmp dl,8
+ ja @f
+ mov al,dl
+@@: mov [bx],al
+ jmp short exit_f0
+
+;
+; 0xF001 or 0xF005: get Preferred or Primary Server
+;
+
+try_01: cmp al,1 ; f001 = get preferred server
+ jz get_server
+ cmp al,5
+ jnz try_02
+
+get_server:
+ mov al,[bx]
+ jmp short exit_f0
+
+try_02: cmp al,2 ; f002 = get default server
+ jnz for_dll ; try to handle on 32-bit side
+ mov al,[bx] ; al = PreferredServer
+ or al,al
+ jnz exit_f0
+ mov al,[bx+1] ; al = PrimaryServer
+
+exit_f0:RESTORE_DS_BX
+ ret
+
+;
+; if we're here then the call must go through to the 32-bit DLL. Save any relevant
+; info in the low memory area, load the handle and BOP (DispatchCall)
+;
+
+for_dll:mov [bx]._SavedAx,ax ; save AX value for DLL
+ push word ptr [bx]._hVdd ; put VDD handle on top of stack
+
+ cmp ah,0BCh ; bc, bd, be need handle mapping
+ jb @f
+ cmp ah,0BEh
+ ja @f
+ pop ax ; ax = hVdd
+ RESTORE_DS_BX ; ds, bx = user ds, bx
+ call MapNtHandle
+ jmp dispatchola
+
+@@: push bp
+ cmp ah, 0E3h ; Is it new or old Create Job request?
+ je lookupcode
+ cmp ax, 0F217h
+ jne check_f3
+
+lookupcode:
+ mov bp,sp
+ mov ds,[bp+4]
+ cmp byte ptr [si+2],68h
+ je createjob
+ cmp byte ptr [si+2],79h
+ je createjob
+ jmp short outtahere
+
+createjob:
+ LOAD_RM_DS_BX
+ mov [bx]._SavedAx,9f02h
+ push ax ; Open \\Server\queue for NCP
+ mov ax,[bp+2] ; ax = hVdd
+ mov ds,[bp+4] ; ds = users ds
+ push ds
+ push dx ; users dx
+ DispatchCall ; Set DeNovellBuffer to \\Server\queue
+ ; and registers ready for DOS OpenFile
+ int 21h ; Open \\server\queue
+ LOAD_RM_DS_BX
+ jc openfailed
+ mov [bx]._JobHandle, al
+ mov [bx]._CreatedJob, 1 ; Flag JobHandle is valid
+ push bx
+ mov bx, ax ; JobHandle
+ call MapNtHandle ; take bx and find the Nt handle
+ pop bx
+
+openfailed:
+ pop dx
+ pop ds ; Proceed and send the NCP
+ pop ax
+
+ push ds
+ push bx
+ LOAD_RM_DS_BX
+ mov [bx]._SavedAx, ax
+ pop bx
+ pop ds ; users DS
+ jmp short outtahere
+
+check_f3:
+ cmp ah, 0F3h
+ jne outtahere
+ ; FileServerCopy, change both
+ ; handles in the structure es:di
+ push bx
+
+ mov bx,word ptr es:[di] ; Map Source Handle
+ call MapNtHandle
+
+ pop bx
+ mov ax,[bx]._NtHandleHi
+ mov [bx]._NtHandleSrcHi,ax
+ mov ax,[bx]._NtHandleLow
+ mov [bx]._NtHandleSrcLow,ax
+
+ mov bx,word ptr es:[di+2] ; Map Destination Handle
+ call MapNtHandle
+
+outtahere:
+ pop bp
+ pop ax ; ax = hVdd
+ RESTORE_DS_BX ; ds, bx = user ds, bx
+dispatchola:
+ DispatchCall ; BOP: DLL performs action
+ ret ; return to the application
+
+;
+; if the request was not recognized by the DLL, it modifies IP so that control
+; will resume at the next int 21. We just fill the intervening space with NOPs
+; (space that makes up a retf <n> instruction in the RM TSR)
+;
+
+ nop
+ nop
+ int 21h
+ ret
+NetwareRequest endp
+
+; *** MapNtHandle
+; *
+; * Given a handle in BX, map it to a 32-bit Nt handle in NtHandle[Hi|Low]
+; *
+; * ENTRY bx = handle to map
+; *
+; * EXIT Success - NtHandle set to 32-bit Nt handle from SFT
+; *
+; * USES ax, bx, flags
+; *
+; * ASSUMES nothing
+; *
+; ***
+
+MapNtHandle proc near
+ push ax
+ mov ax,9f01h ; call MapNtHandle on (BX) in RM
+ int 21h ; update NtHandleHi, NtHandleLow
+ pop ax
+@@: ret
+MapNtHandle endp
+
+_TEXT ends
+
+end
diff --git a/private/nw/nw16/drv/makefile b/private/nw/nw16/drv/makefile
new file mode 100644
index 000000000..7b44d0246
--- /dev/null
+++ b/private/nw/nw16/drv/makefile
@@ -0,0 +1,127 @@
+# netware.drv makefile
+#
+# Copyright (c) 1991-1993 Microsoft Corporation
+#
+# History:
+# Created 25-Mar-1993 Chuck Y. Chan (ChuckC)
+#
+
+!IFDEF USEBUILD
+
+# If using BUILD.EXE, edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2.
+
+!INCLUDE $(NTMAKEENV)\makefile.def
+
+!ELSE
+
+.SUFFIXES:
+.SUFFIXES: .c .asm .h .inc .obj .lst .sys .exe .com .map .sym .def .lib .dll
+
+WOW16 =..\..\..\mvdm\wow16
+
+! ifdef INCLUDE
+WBIN =
+INCS =
+! else
+WBIN = $(WOW16)\bin^\
+CINCS = -I. -I$(WOW16)\inc
+ASMINCS = $(CINCS) -I..\inc -I\nt\public\sdk\inc
+! endif
+
+# DEFINES = -DWOW -DDEBUG $(MVDMFLAGS)
+DEFINES = -DWOW $(MVDMFLAGS) -DBUILDDLL
+
+AOBJ = -Ml -t $(DEFINES) $(ASMINCS)
+
+CW16 = -AS -G2sw -Os -W3 -Zp $(DEFINES) $(CINCS)
+CW16B = $(CW16) -B1 c1l.exe -B2 c2l.exe -B3 c3l.exe
+
+LPATH = ..\..\tools.os2
+LINKFLAG= /map
+
+! ifdef LIB
+W16LIBS = sdllcew
+! else
+W16LIBS = $(WOW16)\lib\sdllcew.lib
+! endif
+
+
+! IF "$(QFE_BUILD)" != "1"
+CL16=cl16
+! ELSE
+CL16=cl
+! ENDIF
+
+PATH=..\..\..\mvdm\tools16;$(PATH)
+
+.asm.obj:
+ masm $(AOBJ) $*;
+
+.asm.lst:
+ masm $(AOBJ) -l $*,nul,$*.lst;
+
+
+.c.obj:
+ $(CL16) -c -nologo $(CW16) $*.c
+
+.c.lst:
+ $(CL16) -c -nologo $(CW16) -Fonul -Fc$*.lst $*.c
+
+
+.def.lib:
+ implib $*.lib $*.def
+
+.map.sym:
+ $(WBIN)mapsym $*
+
+
+all: netware.drv netware.sym
+ binplace netware.drv
+ binplace netware.sym
+
+clean:
+ if exist *.lrf del *.lrf
+ if exist *.obj del *.obj
+ if exist *.exe del *.exe
+ if exist *.dll del *.dll
+ if exist *.map del *.map
+ if exist *.sym del *.sym
+ if exist *.drv del *.drv
+
+
+nwinit.obj: nwinit.c .\netware.h .\nwerror.h
+ $(CL16) -c -nologo $(CW16) $*.c
+
+! ifdef NTVDM_BASED_BUILD
+LINK16 = link16
+RC16 = rc16
+! else
+LINK16 = $(LPATH)\link
+RC16 = $(LPATH)\rc
+! endif
+
+! if exist ($(WOW16)\lib\libw.lib) && exist ($(WOW16)\lib\sdllcew.lib)
+
+netware.drv: nwinit.obj dllentry.obj nwasmutl.obj netware.def ints.obj
+ $(LINK16) @<<netware.lrf
+nwinit.obj+
+dllentry.obj+
+nwasmutl.obj+
+ints.obj
+netware.drv
+netware $(LINKFLAG)
+$(WOW16)\lib\libw.lib+
+$(WOW16)\lib\sdllcew.lib /nod
+netware;
+<<KEEP
+ $(RC16) netware.drv
+
+! else
+
+netware.drv: nwinit.obj dllentry.obj nwasmutl.obj netware.def ints.obj
+ @echo Nothing to build yet... No libraries
+! endif
+
+!endif
diff --git a/private/nw/nw16/drv/netware.def b/private/nw/nw16/drv/netware.def
new file mode 100644
index 000000000..fa251cdc5
--- /dev/null
+++ b/private/nw/nw16/drv/netware.def
@@ -0,0 +1,21 @@
+LIBRARY NETWARE
+DESCRIPTION 'NETWARE '
+EXETYPE WINDOWS
+CODE MOVEABLE DISCARDABLE
+DATA PRELOAD MOVEABLE SINGLE
+HEAPSIZE 512
+
+EXPORTS
+ WEP @1 RESIDENTNAME ;Internal
+
+ WNETADDCONNECTION @17
+ WNETGETCONNECTION @12
+ WNETCANCELCONNECTION @18
+
+ NETWAREREQUEST @1000
+ PNETWAREREQUEST @1001
+
+
+SEGMENTS
+ _TEXT PRELOAD MOVEABLE DISCARDABLE
+
diff --git a/private/nw/nw16/drv/netware.h b/private/nw/nw16/drv/netware.h
new file mode 100644
index 000000000..c96086ab8
--- /dev/null
+++ b/private/nw/nw16/drv/netware.h
@@ -0,0 +1,61 @@
+/*****************************************************************/
+/** Microsoft Windows 4.0 **/
+/** Copyright (C) Microsoft Corp., 1991-1993 **/
+/*****************************************************************/
+
+
+/*
+ * History:
+ * 08/08/93 vlads Created
+ * 10/16/93 gregj Removed #pragma pack() because of #include nesting
+ *
+ */
+
+#ifndef _INC_NETWARE
+#define _INC_NETWARE
+
+#include <windows.h>
+
+// #include <npdefs.h>
+
+// #include <base.h>
+
+// #include <npassert.h>
+// #include <buffer.h>
+
+// #include <..\..\dev\ddk\inc16\error.h>
+// #include <bseerr.h>
+#include "nwerror.h"
+// #include "..\nwnp\nwsysdos.h"
+
+#ifdef __cplusplus
+extern "C" { /* Assume C declarations for C++ */
+#endif /* __cplusplus */
+
+// #include <netcons.h>
+// #include <netlib.h>
+
+WINAPI NETWAREREQUEST (LPVOID);
+WINAPI PNETWAREREQUEST(LPVOID);
+WINAPI DOSREQUESTER(LPVOID);
+
+//UINT WINAPI WNetAddConnection(LPSTR, LPSTR, LPSTR);
+//UINT WINAPI WNetGetConnection(LPSTR, LPSTR, UINT FAR*);
+//UINT WINAPI WNetCancelConnection(LPSTR, BOOL);
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#ifdef DEBUG
+#define TRACE(s) OutputDebugString(s)
+#else
+#define TRACE(s)
+#endif
+
+extern HINSTANCE hInstance;
+
+#endif /* !_INC_NETWARE */
+
diff --git a/private/nw/nw16/drv/nwasmutl.asm b/private/nw/nw16/drv/nwasmutl.asm
new file mode 100644
index 000000000..aa03a37b5
--- /dev/null
+++ b/private/nw/nw16/drv/nwasmutl.asm
@@ -0,0 +1,70 @@
+PAGE,132
+;*****************************************************************;
+;** Microsoft Windows for Workgroups **;
+;** Copyright (C) Microsoft Corp., 1991-1993 **;
+;*****************************************************************;
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; ;;
+;; COMPONENT: Windows NetWare DLL. ;;
+;; ;;
+;; FILE: NWASMUTL.ASM ;;
+;; ;;
+;; PURPOSE: General routines used that cannot be done in C. ;;
+;; ;;
+;; REVISION HISTORY: ;;
+;; vlads 09/20/93 First cut ;;
+;; ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ INCLUDE CMACROS.INC
+
+?PLM = 1
+?WIN=0
+
+ifndef SEGNAME
+ SEGNAME equ <_TEXT> ; default seg name
+endif
+
+createSeg %SEGNAME, CodeSeg, word, public, CODE
+
+sBegin CodeSeg ; this defines what seg this goes in
+assumes cs,CodeSeg
+
+;;
+;; Swapping bytes in a word
+;;
+
+cProc WordSwap, <PUBLIC,FAR>
+ parmW inWord
+
+cBegin
+ mov ax, word ptr (inWord)
+ xchg al, ah
+cEnd
+
+
+;;
+;; Swapping words in a long word
+;;
+cProc LongSwap, <FAR,PUBLIC>, <dx>
+ parmD inLong
+
+cBegin
+ mov dx, word ptr (inLong + 2)
+ xchg dl, dh
+ mov ax, word ptr (inLong)
+ xchg al, ah
+cEnd
+
+;public NETWAREREQUEST
+;
+;NETWAREREQUEST proc far
+; int 21h
+; retf
+;NETWAREREQUEST endp
+
+sEnd _thisseg
+
+ END
+
diff --git a/private/nw/nw16/drv/nwerror.h b/private/nw/nw16/drv/nwerror.h
new file mode 100644
index 000000000..f369855ce
--- /dev/null
+++ b/private/nw/nw16/drv/nwerror.h
@@ -0,0 +1,46 @@
+/*****************************************************************/
+/** Microsoft Windows for Workgroups **/
+/** Copyright (C) Microsoft Corp., 1991-1992 **/
+/*****************************************************************/
+
+/* NWERROR.H -- Novell defined error return codes from Netware API
+ *
+ * History:
+ * 03/16/93 vlads Created
+ *
+ */
+
+#ifndef _nwerror_h_
+#define _nwerror_h_
+
+
+#define NWSC_SUCCESS 0x00
+#define NWSC_SERVEROUTOFMEMORY 0x96
+#define NWSC_NOSUCHVOLUME 0x98 // Volume does not exist
+#define NWSC_BADDIRECTORYHANDLE 0x9b
+#define NWSC_NOSUCHPATH 0x9c
+#define NWSC_NOJOBRIGHTS 0xd6
+#define NWSC_EXPIREDPASSWORD 0xdf
+#define NWSC_NOSUCHSEGMENT 0xec // Segment does not exist
+#define NWSC_INVALIDNAME 0xef
+#define NWSC_NOWILDCARD 0xf0 // Wildcard not allowed
+#define NWSC_NOPERMBIND 0xf1 // Invalid bindery security
+
+#define NWSC_ALREADYATTACHED 0xf8 // Already attached to file server
+#define NWSC_NOPERMREADPROP 0xf9 // No property read privelege
+#define NWSC_NOFREESLOTS 0xf9 // No free connection slots at server
+#define NWSC_NOMORESLOTS 0xfa // No more server slots
+#define NWSC_NOSUCHPROPERTY 0xfb // Property does not exist
+#define NWSC_UNKNOWN_REQUEST 0xfb // Invalid NCP number
+#define NWSC_NOSUCHOBJECT 0xfc // End of Scan Bindery Object service
+ // No such object
+#define NWSC_UNKNOWNSERVER 0xfc // Unknown file server
+#define NWSC_SERVERBINDERYLOCKED 0xfe // Server bindery locked
+#define NWSC_BINDERYFAILURE 0xff // Bindery failure
+#define NWSC_ILLEGALSERVERADDRESS 0xff // No response from server (illegal server address)
+#define NWSC_NOSUCHCONNECTION 0xff // Connection ID does not exist
+
+
+typedef WORD NW_STATUS;
+
+#endif
diff --git a/private/nw/nw16/drv/nwinit.c b/private/nw/nw16/drv/nwinit.c
new file mode 100644
index 000000000..c61a4fb40
--- /dev/null
+++ b/private/nw/nw16/drv/nwinit.c
@@ -0,0 +1,81 @@
+/*****************************************************************/
+/** Microsoft Windows 4.0 **/
+/** Copyright (C) Microsoft Corp., 1992-1993 **/
+/*****************************************************************/
+
+/* INIT.C -- General code for MS/Netware network driver emulator.
+ *
+ * History:
+ * 09/22/93 vlads Created
+ *
+ */
+
+#include "netware.h"
+
+#define Reference(x) ((void)(x))
+
+extern BOOL far pascal GetLowRedirInfo(void);
+
+int FAR PASCAL LibMain(
+ HANDLE hInst,
+ WORD wDataSeg,
+ WORD wcbHeapSize,
+ LPSTR lpstrCmdLine)
+{
+
+ //
+ // get shared data segment address. Fail initialization if an error is
+ // returned
+ //
+
+ if (!GetLowRedirInfo()) {
+ return 0;
+ }
+
+ //
+ // return success
+ //
+
+ return 1;
+}
+
+/* WEP
+ * Windows Exit Procedure
+ */
+
+int FAR PASCAL _loadds WEP(int nParameter)
+{
+ Reference(nParameter);
+ return 1;
+}
+
+
+WINAPI PNETWAREREQUEST(LPVOID x)
+{
+ return(1);
+}
+
+//
+// removed because nwcalls makes use of this function; removing it causes
+// NWCALLS to use real INT 21
+//
+
+//WINAPI DOSREQUESTER(LPVOID x)
+//{
+// return(1);
+//}
+
+UINT WINAPI WNetAddConnection(LPSTR p1, LPSTR p2, LPSTR p3)
+{
+ return(1);
+}
+
+UINT WINAPI WNetGetConnection(LPSTR p1, LPSTR p2, UINT FAR *p3)
+{
+ return(1);
+}
+
+UINT WINAPI WNetCancelConnection(LPSTR p1, BOOL p2)
+{
+ return(1);
+}
diff --git a/private/nw/nw16/inc/makefile b/private/nw/nw16/inc/makefile
new file mode 100644
index 000000000..ad117a137
--- /dev/null
+++ b/private/nw/nw16/inc/makefile
@@ -0,0 +1,34 @@
+!IF 0
+
+Copyright (c) 1991 & 1993 Microsoft Corporation
+
+Module Name:
+
+ makefile
+
+Abstract:
+
+ makefile for Vdm NetWare Redir program
+
+Author:
+
+ Richard L Firth (rfirth) 13-Sep-1991
+
+Revision History:
+
+ 13-Sep-1991 rfirth
+ Created
+
+!ENDIF
+
+.SUFFIXES:
+.SUFFIXES: .asm .h
+
+.h.inc:
+ h2inc $< -o $*.inc
+
+nwdos.inc: nwdos.h
+
+clean:
+ del *.inc
+ $(MAKE)
diff --git a/private/nw/nw16/inc/nwdos.h b/private/nw/nw16/inc/nwdos.h
new file mode 100644
index 000000000..c1a03891e
--- /dev/null
+++ b/private/nw/nw16/inc/nwdos.h
@@ -0,0 +1,220 @@
+/*--
+
+ Copyright (c) 1993 Microsoft Corporation
+
+ Module Name:
+
+ NWDOS.h
+
+ Abstract:
+
+ This is the include file that defines all constants and types for
+ 16 bit applications accessing the redirector.
+
+ Author:
+
+ Colin Watson (ColinW) 08-Jul-1993
+
+ Revision History:
+
+--*/
+
+#define NWDOS_INCLUDED
+
+#define MC 8 // maximum number of connections
+
+#define NC 8 // number of novell connections
+#define MP 3 // maximum number of printers
+#define MD 32 // maximum number of drives
+#define PZ 64 // print buffer size
+
+#define SERVERNAME_LENGTH 48
+#define USERNAME_LENGTH 16
+#define PASSWORD_LENGTH 16
+#define IPXADDRESS_LENGTH 12
+#define NODEADDRESS_LENGTH 6
+
+typedef UCHAR byte;
+typedef USHORT word;
+
+typedef byte CONN_INDEX; // index into ConnectionIdTable, range 0..MC-1
+typedef byte DRIVE; // index into DriveXxxTable, range 0..MD-1
+
+/* OpenFile() Flags */
+
+#define OF_READ_WRITE_MASK 0x0003
+/*
+#define OF_READ 0x0000
+#define OF_WRITE 0x0001
+#define OF_READWRITE 0x0002
+*/
+#define OF_SHARE_MASK 0x0070
+/*
+#define OF_SHARE_COMPAT 0x0000
+#define OF_SHARE_EXCLUSIVE 0x0010
+#define OF_SHARE_DENY_WRITE 0x0020
+#define OF_SHARE_DENY_READ 0x0030
+#define OF_SHARE_DENY_NONE 0x0040
+#define OF_PARSE 0x0100
+#define OF_DELETE 0x0200
+#define OF_VERIFY 0x0400 */ /* Used with OF_REOPEN */
+/*
+#define OF_SEARCH 0x0400 */ /* Used without OF_REOPEN */
+/*
+#define OF_CANCEL 0x0800
+#define OF_CREATE 0x1000
+#define OF_PROMPT 0x2000
+#define OF_EXIST 0x4000
+#define OF_REOPEN 0x8000
+*/
+
+//
+// Force misalignment of the following structures
+//
+
+/* XLATOFF */
+#include <packon.h>
+/* XLATON */
+
+typedef struct CID { /* */
+ byte ci_InUse;
+ byte ci_OrderNo;
+ byte ci_ServerAddress[IPXADDRESS_LENGTH];
+ word ci_TimeOut;
+ byte ci_LocalNode[NODEADDRESS_LENGTH];
+ byte ci_SequenceNo;
+ byte ci_ConnectionNo;
+ byte ci_ConnectionStatus;
+ word ci_MaxTimeOut;
+ byte ci_ConnectionLo;
+ byte ci_ConnectionHi;
+ byte ci_MajorVersion;
+ byte ci_1;
+ byte ci_MinorVersion;
+} CONNECTIONID;
+typedef CONNECTIONID UNALIGNED *PCONNECTIONID;
+
+#if 0 /* Already declared in nw\inc\ntddnwfs.h */
+typedef char SERVERNAME[SERVERNAME_LENGTH];
+#endif
+
+typedef char USERNAME[USERNAME_LENGTH];
+typedef char PASSWORD[PASSWORD_LENGTH];
+typedef char IPXADDRESS[IPXADDRESS_LENGTH];
+typedef char NODEADDRESS[NODEADDRESS_LENGTH];
+
+//
+// The following type collects all the structures used between the TSR
+// and the 32 bit dll into one packed structure.
+//
+// *** ANY CHANGES TO THIS STRUCTURE MUST ALSO BE MADE TO THE ASM NWDOSTABLE_ASM
+// *** STRUCTURE (below)
+//
+
+/* XLATOFF */
+typedef struct {
+ CONNECTIONID ConnectionIdTable[MC];
+ SERVERNAME ServerNameTable[MC];
+ CONN_INDEX DriveIdTable[MD]; // Corresponding ConnectionId
+ UCHAR DriveFlagTable[MD];
+ UCHAR DriveHandleTable[MD];
+ UCHAR PreferredServer;
+ UCHAR PrimaryServer;
+ UCHAR TaskModeByte;
+ UCHAR CurrentDrive;
+ USHORT SavedAx;
+ USHORT NtHandleHi;
+ USHORT NtHandleLow;
+ USHORT NtHandleSrcHi;
+ USHORT NtHandleSrcLow;
+ USHORT hVdd;
+ USHORT PmSelector;
+ UCHAR CreatedJob;
+ UCHAR JobHandle;
+ UCHAR DeNovellBuffer[256];
+ UCHAR DeNovellBuffer2[256];
+} NWDOSTABLE;
+typedef NWDOSTABLE *PNWDOSTABLE;
+/* XLATON */
+
+//
+// Turn structure packing back off
+//
+
+/* XLATOFF */
+#include <packoff.h>
+/* XLATON */
+
+//
+// CONNECTIONID Constants
+//
+
+#define FREE 0
+#define IN_USE 0xff
+
+//
+// Values for DriveFlags
+//
+
+#define NOT_MAPPED 0
+#define PERMANENT_NETWORK_DRIVE 1
+#define TEMPORARY_NETWORK_DRIVE 2
+#define LOCAL_DRIVE 0x80
+
+
+///// Client state tables:
+
+extern CONNECTIONID* ConnectionIdTable; // MC entries
+extern SERVERNAME* ServerNameTable; // MC entries
+
+extern byte* DriveFlagTable; // MD entries
+extern byte* DriveIdTable; // MD entries
+
+//
+// this next egregious grossness is extant because MASM cannot handle anything
+// other than a basic type inside a structure declaration
+//
+// *** ANY CHANGES TO THIS STRUCTURE MUST ALSO BE MADE TO THE C NWDOSTABLE
+// *** STRUCTURE (above)
+//
+// NB. The leading underscores are there because we already have globals with
+// the same names
+//
+
+/* ASM
+
+NWDOSTABLE_ASM struc
+
+_ConnectionIdTable db ((size CID) * MC) dup (?)
+_ServerNameTable db (MC * SERVERNAME_LENGTH) dup (?)
+_DriveIdTable db MD dup (?)
+_DriveFlagTable db MD dup (?)
+_DriveHandleTable db MD dup (?)
+_PreferredServer db ?
+_PrimaryServer db ?
+_TaskModeByte db ?
+_CurrentDrive db ?
+_SavedAx dw ?
+_NtHandleHi dw ?
+_NtHandleLow dw ?
+_NtHandleSrcHi dw ?
+_NtHandleSrcLow dw ?
+_hVdd dw ?
+_PmSelector dw ?
+_CreatedJob db ?
+_JobHandle db ?
+_DeNovellBuffer db 256 dup (?)
+_DeNovellBuffer2 db 256 dup (?)
+
+NWDOSTABLE_ASM ends
+
+*/
+
+/* XLATOFF */
+//
+// IS_ASCII_PATH_SEPARATOR - returns TRUE if ch is / or \. ch is a single
+// byte (ASCII) character
+//
+#define IS_ASCII_PATH_SEPARATOR(ch) (((ch) == '/') || ((ch) == '\\'))
+/* XLATON */
+
diff --git a/private/nw/nw16/tsr/asmmacro.inc b/private/nw/nw16/tsr/asmmacro.inc
new file mode 100644
index 000000000..0b7b2db16
--- /dev/null
+++ b/private/nw/nw16/tsr/asmmacro.inc
@@ -0,0 +1,343 @@
+;++
+;
+;Copyright (c) 1991 Microsoft Corporation
+;
+;Module Name:
+;
+; asmmacro.inc
+;
+;Abstract:
+;
+; Contains macros to extend masm functionality:
+;
+; jmpc
+; jmpnc
+; jmpne
+; jmps
+; _mkjmp
+;
+;
+;Author:
+;
+; Richard L Firth (rfirth) 24-Sep-1991
+;
+;Environment:
+;
+; DOS application mode only
+;
+;Revision History:
+;
+; 24-Sep-1991 rfirth
+; Created
+;
+;--
+
+
+
+DEFINED_BIT=020h
+;ISDEFINED equ %(.type <thing> and DEFINED_BIT)
+LABEL_DEFINED equ <(.type &label and DEFINED_BIT)>
+
+DEBUG_MACROS = 0
+;DEBUG_MACROS = 1
+
+
+;*** jmpa
+;*
+;* jump to label if above. Label can be short (+129, -126 from
+;* the first byte of the current jump instruction, if it is a short - ie
+;* byte - jump) or near
+;*
+;* ENTRY label - to jump to
+;*
+;* EXIT nothing
+;*
+;* USES nothing
+;*
+;* ASSUMES 286+
+;*
+;***
+
+jmpa macro label
+ _mkjmp ja,jna,&label
+endm
+
+;*** jmpc
+;*
+;* jump to label if below. Label can be short (+129, -126 from
+;* the first byte of the current jump instruction, if it is a short - ie
+;* byte - jump) or near
+;*
+;* ENTRY label - to jump to
+;*
+;* EXIT nothing
+;*
+;* USES nothing
+;*
+;* ASSUMES 286+
+;*
+;***
+
+jmpb macro label
+ _mkjmp jb,jnb,&label
+endm
+
+;*** jmpc
+;*
+;* jump to label if carry flag set. Label can be short (+129, -126 from
+;* the first byte of the current jump instruction, if it is a short - ie
+;* byte - jump) or near
+;*
+;* ENTRY label - to jump to
+;*
+;* EXIT nothing
+;*
+;* USES nothing
+;*
+;* ASSUMES 286+
+;*
+;***
+
+jmpc macro label
+ _mkjmp jc,jnc,&label
+endm
+
+
+
+;*** jmpnc
+;*
+;* jump to label if carry flag NOT set. Label can be short (+129, -126 from
+;* the first byte of the current jump instruction, if it is a short - ie
+;* byte - jump) or near
+;*
+;* ENTRY label - to jump to
+;*
+;* EXIT nothing
+;*
+;* USES nothing
+;*
+;* ASSUMES 286+
+;*
+;***
+
+jmpnc macro label
+ _mkjmp jnc,jc,&label
+endm
+
+
+
+;*** jmpne
+;*
+;* jump to label if zero flag NOT set. Label can be short (+129, -126 from
+;* the first byte of the current jump instruction, if it is a short - ie
+;* byte - jump) or near
+;*
+;* ENTRY label - to jump to
+;*
+;* EXIT nothing
+;*
+;* USES nothing
+;*
+;* ASSUMES 286+
+;*
+;***
+
+jmpne macro label
+ _mkjmp jne,je,&label
+endm
+
+
+
+;*** jmpe
+;*
+;* jump to label if zero flag set. Label can be short (+129, -126 from
+;* the first byte of the current jump instruction, if it is a short - ie
+;* byte - jump) or near
+;*
+;* ENTRY label - to jump to
+;*
+;* EXIT nothing
+;*
+;* USES nothing
+;*
+;* ASSUMES 286+
+;*
+;***
+
+jmpe macro label
+ _mkjmp je,jne,&label
+endm
+
+
+
+;*** jmps
+;*
+;* jump to label. Label can be short (+129, -126 from
+;* the first byte of the current jump instruction, if it is a short - ie
+;* byte - jump) or near
+;*
+;* ENTRY label - to jump to
+;*
+;* EXIT nothing
+;*
+;* USES nothing
+;*
+;* ASSUMES 286+
+;*
+;***
+
+jmps macro label
+ local l,dist
+dist=&label-$
+if1
+if (.type label and DEFINED_BIT)
+if ((dist gt 129) or (dist lt -126))
+if DEBUG_MACROS
+ %out pass1: &label defined and near
+endif
+ jmp &label
+else
+if DEBUG_MACROS
+ %out pass1: &label defined and short
+endif
+ jmp short &label
+endif
+else
+if DEBUG_MACROS
+ %out pass1: &label not defined
+endif
+ org $+3
+endif
+else
+if ((dist gt 129) or (dist lt -126))
+if DEBUG_MACROS
+ %out pass2: &label defined and near
+endif
+ jmp &label
+else
+if DEBUG_MACROS
+ %out pass2: &label defined and short
+endif
+ jmp short &label
+ org $+1
+endif
+endif
+l:
+endm
+
+
+
+;*** _mkjmp
+;*
+;* Make a jmp<?> macro. Generate instruction sequence for jump with or
+;* without conditional test. Jump may be short (+127/-128 bytes) or near
+;* (+32767/-32768 bytes)
+;*
+;* ENTRY is - short jump instruction
+;* in - near jump instruction
+;* label - to jump to
+;*
+;* EXIT nothing
+;*
+;* USES nothing
+;*
+;* ASSUMES 286+
+;*
+;***
+
+_put macro s,v
+if2
+if DEBUG_MACROS
+%out s = v
+endif
+endif
+endm
+
+_mkjmp macro is, in, label
+ local l
+
+;;
+;; if pass 1 and label is already known, generate correct instruction
+;;
+
+if1
+if (.type &label and DEFINED_BIT)
+
+;;
+;; if label is too far away for short jump instruction, make jump <condition>
+;; into jump <NOT condition> round jump to label followed by a near jump to
+;; label
+;;
+
+if (((&label - $) gt 129) or ((&label - $) lt -126))
+ &in l ;; short jump, NOT condition
+ jmp &label ;; jump to where we want to go
+else
+ &is &label ;; short jump
+endif
+
+;;
+;; if pass 1 and we don't know about the label yet, adjust the program
+;; counter by the max. number of bytes taken up by this macro (5 - 2 for
+;; short jump, 3 for near jump)
+;;
+
+else
+ nop
+ nop
+ nop
+ nop
+ nop
+endif
+
+;;
+;; pass 2 - do same stuff as for pass 1
+;;
+
+else
+if (((&label - $) gt 129) or ((&label - $) lt -126))
+ if ((&label-$) gt 129)
+ _put <label distance>, %(&label-$)
+ else
+ _put <label distance>, %($-&label)
+ endif
+ &in l
+ jmp &label
+else
+
+;;
+;; label is within +127/-128 bytes of current instruction - generate short
+;; jump instruction and put the program counter forward past the space
+;; reserved during pass 1
+;;
+
+ _put <label distance>, %(&label-$)
+ &is &label
+ nop
+ nop
+ nop
+endif
+endif
+l:
+endm
+
+
+
+oldjmps macro label
+if2
+if (((&label - $) gt 127) or (($ - &label) lt -128))
+ jmp short l
+ jmp &label
+else
+ jmp short &label
+ org $+3
+endif
+else
+;;
+;; if this is pass 1 just take up max amount of space so phases don't get
+;; screwed
+;;
+ org $+5
+endif
+l:
+endm
diff --git a/private/nw/nw16/tsr/debugmac.inc b/private/nw/nw16/tsr/debugmac.inc
new file mode 100644
index 000000000..45fe236e5
--- /dev/null
+++ b/private/nw/nw16/tsr/debugmac.inc
@@ -0,0 +1,356 @@
+;++
+;
+;Copyright (c) 1991 Microsoft Corporation
+;
+;Module Name:
+;
+; debugmac.inc
+;
+;Abstract:
+;
+; Contains debugging macros:
+;
+; DbgBreakPoint
+; DbgUnsupported
+; DbgDEBUG
+; DbgPrint
+; DbgPrintTty
+; DbgPrintString
+; DbgPrintHexDword
+; DbgPrintHexWord
+; DbgPrintHexByte
+; DbgPrintNearPointer
+; DbgPrintFarPointer
+;
+;Author:
+;
+; Richard L Firth (rfirth) 13-Sep-1991
+;
+;Environment:
+;
+; DOS application mode only
+;
+;[Notes:]
+;
+; optional-notes
+;
+;Revision History:
+;
+; 13-Sep-1991 rfirth
+; Created
+;
+;--
+
+
+;*** DbgBreakPoint
+;*
+;* Same as NT routine of same name. No-op in non-DEBUG version
+;*
+;* ENTRY
+;*
+;* EXIT
+;*
+;* RETURNS
+;*
+;* ASSUMES
+;*
+;***
+
+DbgBreakPoint macro
+if DEBUG
+ int 3
+endif
+endm
+
+;*** DbgUnsupported
+;*
+;* Causes the 32-bit support code to display a message about an unsupported
+;* service code, and dumps the 16-bit registers. Used to discover when an
+;* unsupported int 2f/11 call or int 21/5f call is being made
+;*
+;* ENTRY
+;*
+;* EXIT
+;*
+;* RETURNS
+;*
+;* ASSUMES
+;*
+;***
+
+DbgUnsupported macro
+if DEBUG
+ SVC -1
+endif
+endm
+
+;*** DbgDEBUG
+;*
+;* Prints the string "DEBUG: " to console using Bios Int 10h/ah=0eh
+;*
+;* ENTRY nothing
+;*
+;* EXIT nothing
+;*
+;* USES ax
+;*
+;* ASSUMES 286+
+;*
+;***
+
+DbgDEBUG macro
+ mov ax,(14 shl 8) + 'D'
+ int 10h
+ mov al,'E'
+ int 10h
+ mov al,'B'
+ int 10h
+ mov al,'U'
+ int 10h
+ mov al,'G'
+ int 10h
+ mov al,':'
+ int 10h
+ mov al,' '
+ int 10h
+endm
+
+
+
+;*** DbgCrLf
+;*
+;* Prints CR,LF to console using Bios Int 10h/ah=0eh
+;*
+;* ENTRY nothing
+;*
+;* EXIT nothing
+;*
+;* USES nothing
+;*
+;* ASSUMES 286+
+;*
+;***
+
+DbgCrLf macro
+ push ax
+ mov ax,(14 shl 8) + 13
+ int 10h
+ mov al,10
+ int 10h
+ pop ax
+endm
+
+
+
+;*** DbgPrint
+;*
+;* Prints an ASCIZ string to console using Bios Int 10h
+;*
+;* ENTRY string - address of ASCIZ string to print
+;*
+;* EXIT nothing
+;*
+;* USES nothing
+;*
+;* ASSUMES 286+
+;*
+;***
+
+DbgPrint macro string
+if DEBUG ;; no macro if not debug version
+ pushf ;; save regs used by DbgPrintTty
+ push ax
+ push bx
+ push si
+ push ds
+ mov ax,seg string
+ mov ds,ax
+ mov si,offset string;; ds:si = address of string
+ DbgPrintTty ;; display it on console
+ pop ds
+ pop si
+ pop bx
+ pop ax
+ popf
+endif
+endm
+
+
+
+;*** DbgPrintTty
+;*
+;* Prints an ASCIZ string in ds:si to console using Bios Int 10h
+;*
+;* ENTRY page - if present defines which Bios video page to use
+;* Defaults to 0
+;* ds:si - address of ASCIZ string to print
+;*
+;* EXIT nothing
+;*
+;* USES al, bh, si, flags
+;*
+;* ASSUMES 286+
+;*
+;***
+
+DbgPrintTty macro page
+ local l1,l2
+
+if DEBUG ;; no macro if not debug version
+ mov ah,14 ;; Bios Int write character as TTY function
+ifb <page>
+ sub bh,bh
+else
+ mov bh,page
+endif
+ cld ;; autoincrement lodsb
+l1: lodsb ;; al := next character; si := next character addr
+ or al,al ;; eof string?
+ jz l2 ;; yes
+ int 10h ;; display it to console
+ jmp short l1 ;; go round again
+l2:
+endif
+endm
+
+
+
+;*** DbgPrintString
+;*
+;* Prints a string to console using Bios Int 10h. Note that this macro
+;* does not do printf style substitutions. The string "DEBUG: " will be
+;* displayed if the banner parm is not blank
+;*
+;* ENTRY string - character string. Needn't be zero-terminated
+;* banner - the "DEBUG: " banner will be printed if not blank
+;*
+;* EXIT nothing
+;*
+;* USES nothing
+;*
+;* ASSUMES 286+
+;*
+;***
+
+DbgPrintString macro string, banner
+ local s1
+ local l1
+
+if DEBUG ;; no macro if not debug version
+ jmp short l1
+s1 db &string,0
+l1: pushf ;; don't destroy direction flag
+ pusha ;; save gp regs
+ifb <banner>
+ DbgDEBUG ;; Display "DEBUG: "
+endif
+ push ds ;; save user's data seg
+ push cs
+ pop ds ;; ds == cs
+ mov si,offset cs:s1 ;; si := string offset
+ DbgPrintTty ;; display ds:si to console
+ pop ds ;; restore user's data seg
+ popa ;; restore gp regs
+ popf ;; restore direction flag+
+endif
+endm
+
+
+
+;*** DbgPrintHexDword
+;*
+;* Prints a dword to console in hex notation using Bios Int 10h
+;*
+;* ENTRY dword - dword to print
+;*
+;* EXIT nothing
+;*
+;* USES nothing
+;*
+;* ASSUMES 286+
+;*
+;***
+
+DbgPrintHexDword macro dword
+if DEBUG ;; no macro if not debug version
+ DbgPrint <"DbgPrintHexDword not implemented yet",13,10>
+endif
+endm
+
+
+
+;*** DbgPrintHexWord
+;*
+;* Prints a word to console in hex notation using Bios Int 10h
+;*
+;* ENTRY word - to print. Can be memory or register
+;*
+;* EXIT nothing
+;*
+;* USES nothing
+;*
+;* ASSUMES 286+
+;*
+;***
+
+DbgPrintHexWord macro word
+ local l1, l2
+if DEBUG ;; no macro if not debug version
+ pushf ;; don't use any registers
+ push ax
+ push cx
+ push dx
+ifdifi <word>,<ax>
+ mov ax,word
+endif
+ mov cx,4
+l1: rol ax,4
+ mov dx,ax
+ and al,0fh
+ cmp al,9
+ jle l2
+ add al,'a'-('9'+1)
+l2: add al,'0'
+ mov ah,14
+ int 10h
+ mov ax,dx
+ loop l1
+ pop dx
+ pop cx
+ pop ax
+ popf
+endif
+endm
+
+
+
+;*** DbgPrintHexByte
+;*
+;* Prints a string to console using Bios Int 10h. Note that this macro
+;* does not do printf style substitutions
+;*
+;* ENTRY string - character string. Needn't be zero-terminated
+;*
+;* EXIT
+;*
+;* USES nothing
+;*
+;* ASSUMES 286+
+;*
+;***
+
+DbgPrintHexByte macro byte
+if DEBUG ;; no macro if not debug version
+ DbgPrint <"DbgPrintHexByte not implemented yet",13,10>
+endif
+endm
+
+
+
+DbgPrintNearPointer macro nearptr
+endm
+
+
+
+DbgPrintFarPointer macro farptr
+endm
diff --git a/private/nw/nw16/tsr/makefile b/private/nw/nw16/tsr/makefile
new file mode 100644
index 000000000..61ae19b12
--- /dev/null
+++ b/private/nw/nw16/tsr/makefile
@@ -0,0 +1,192 @@
+!IF 0
+
+Copyright (c) 1991 & 1993 Microsoft Corporation
+
+Module Name:
+
+ makefile
+
+Abstract:
+
+ makefile for Vdm NetWare Redir program
+
+Author:
+
+ Richard L Firth (rfirth) 13-Sep-1991
+
+Revision History:
+
+ 13-Sep-1991 rfirth
+ Created
+
+!ENDIF
+
+
+
+.SUFFIXES:
+.SUFFIXES: .asm .h
+
+#
+# nmake doesn't work properly if we try to stick the objects in obj, so put
+# them in current dir for now. WHEN CHANGE OBJPATH TO BE OBJ, CHANGE clean TOO
+#
+
+#OBJPATH = .
+OBJPATH = obj
+
+ASM = masm
+!IFDEF NTVDM_BASED_BUILD
+LINK = link16
+!ELSE
+LINK = link
+!ENDIF
+
+#
+# set the country info
+#
+
+!if "$(LANGUAGE)" == "JPN"
+COUNTRY=jpn
+!elseif "$(LANGUAGE)" == "CHT"
+COUNTRY=cht
+!elseif "$(LANGUAGE)" == "CHS"
+COUNTRY=chs
+!elseif "$(LANGUAGE)" == "KOR"
+COUNTRY=kor
+!ENDIF
+
+!IFNDEF COUNTRY
+COUNTRY=usa
+!ENDIF
+
+#
+# convert NTDEBUG into DEBUG flag. NTDEBUG can be not present or retail, either
+# of which mean no debugging; or ntsd, cvp or sym, which means debugging support
+# required
+#
+
+!IFDEF NTDEBUG
+!IF "$(NTDEBUG)" == "retail"
+DEBUGGING=0
+!ELSE
+DEBUGGING=1
+!ENDIF
+!ELSE
+DEBUGGING=0
+!ENDIF
+
+#
+# assembler and linker debugging options
+#
+
+!IF $(DEBUGGING)
+ASMDEBUG = /DDEBUG=1 /Zi
+LINKDEBUG = /CO
+!ELSE
+ASMDEBUG = /DDEBUG=0
+LINKDEBUG =
+!ENDIF
+ASMINC = /I$(_NTROOT)\public\sdk\inc /I$(_NTROOT)\private\mvdm\dos\v86\inc /I..\..\inc /I..\inc
+ASMFLAGS = /Mx
+LINKFLAGS = /MAP /CP:1
+
+#
+# any other non-debug related options (for assembler) go in USERDEFS
+#
+
+#USERDEFS = /DCALL_DOS /DVERBOSE
+#USERDEFS = /DCALL_DOS
+
+
+
+#
+# Inference rules - asm to obj, h to inc
+#
+
+.asm{$(OBJPATH)\}.obj:
+ $(ASM) $(ASMINC) $(ASMDEBUG) $(USERDEFS) $<,$@;
+
+.asm.lst:
+ $(ASM) $(ASMINC) $(ASMDEBUG) $(USERDEFS) /L $<;
+
+
+
+#
+# what it is we're building
+#
+
+TARGET = $(OBJPATH)\nw16.exe
+MAPFILE = $(TARGET:.exe=.map)
+DEFFILE = ;
+
+OBJS = $(OBJPATH)\nw16.obj \
+ $(OBJPATH)\resident.obj
+
+LIBS =
+
+
+
+#
+# how to build it
+#
+
+all: makedir $(TARGET)
+
+$(TARGET): $(OBJS)
+ $(LINK) @<<
+$(OBJS)
+$(TARGET) $(LINKFLAGS) $(LINKDEBUG)
+$(MAPFILE)
+$(LIBS)
+$(DEFFILE)
+<<
+
+
+#
+# where to put it
+#
+
+ binplace $(TARGET)
+
+
+#
+# clean build - delete all objs
+#
+
+#clean: makedir clean2
+clean: clean2
+
+clean2:
+ if exist $(OBJPATH)\*.obj del $(OBJPATH)\*.obj
+ $(MAKE)
+
+#
+# makedir - ensure the subdirectory for the object files exists
+#
+
+makedir:
+ @-if not exist $(OBJPATH) md $(OBJPATH)
+
+
+
+#
+# file dependencies
+#
+
+$(OBJPATH)\nw16.obj: \
+ nw16.asm \
+ debugmac.inc \
+ asmmacro.inc \
+ segorder.inc \
+ messages.inc \
+ ..\inc\nwdos.inc
+
+$(OBJPATH)\resident.obj: \
+ resident.asm \
+ segorder.inc \
+ debugmac.inc \
+ asmmacro.inc \
+ ..\inc\nwdos.inc
+
+messages.inc: ..\..\inc\$(COUNTRY)\messages.inc
+ copy ..\..\inc\$(COUNTRY)\messages.inc .
diff --git a/private/nw/nw16/tsr/nw16.asm b/private/nw/nw16/tsr/nw16.asm
new file mode 100644
index 000000000..ac19beed8
--- /dev/null
+++ b/private/nw/nw16/tsr/nw16.asm
@@ -0,0 +1,517 @@
+page ,132
+
+if 0
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ nw16.asm
+
+Abstract:
+
+ This module contains the stub redir TSR code for NT VDM net support
+
+Author:
+
+ Richard L Firth (rfirth) 05-Sep-1991
+ Colin Watson (colinw) 30-Jun-1993
+
+Environment:
+
+ Dos mode only
+
+Revision History:
+
+ 05-Sep-1991 rfirth
+ Created
+
+ 30-Jun-1993 colinw
+ ported to NetWare
+
+--*/
+endif
+
+
+
+;
+; DOS include files
+;
+
+.xlist
+.xcref
+include isvbop.inc ; NTVDM BOP mechanism
+include dossym.inc ; includes MS-DOS version etc
+include pdb.inc ; PSP defines
+include syscall.inc ; AssignOper
+include segorder.inc ; load order of 'redir' segments
+include debugmac.inc ; debug display macros
+include asmmacro.inc ; jumps which may be short or near
+include messages.inc
+include nwdos.inc ; NetWare structures and nwapi32 interface
+.cref
+.list
+
+;
+; Define externals in resident code and data
+;
+
+ResidentCodeStart
+
+ extrn Old21Handler:dword
+ extrn NwInt21:near
+ extrn hVDD:dword
+ extrn quick_jump_to_dos:byte
+ extrn for_dos_proper:byte
+ extrn chain_previous_int21:byte
+ extrn ConnectionIdTable:byte
+ extrn not_exclusive:byte
+
+ResidentCodeEnd
+
+
+InitStack segment stack para 'stack'
+
+ dw 256 dup (?)
+
+InitStack ends
+
+InitDataStart
+
+
+bad_ver_msg db NLS_MSG_001,c_CR,c_LF
+BAD_VER_MSG_LEN equ $-bad_ver_msg
+ db '$' ; for INT 21/09 display string
+
+already_loaded_msg db NLS_MSG_004,c_CR,c_LF
+ALREADY_LOADED_MSG_LEN equ $-already_loaded_msg
+
+cannot_load_msg db NLS_MSG_005,c_CR, c_LF
+CANNOT_LOAD_MSG_LEN equ $-cannot_load_msg
+
+InitDataEnd
+
+
+InitCodeStart
+
+ assume cs:InitCode
+ assume ds:nothing
+ assume es:nothing
+ assume ss:nothing
+
+ public DllName
+DllName db "NWAPI16.DLL",0
+
+ public InitFunc
+InitFunc db "Nw16Register",0
+
+ public DispFunc
+DispFunc db "Nw16Handler",0
+
+ public start
+start proc near
+
+;
+; when we start up we could be on any old PC - even an original, so don't
+; assume anything other than a model-T processor
+;
+
+ .8086
+
+;
+; Set the data segment while we're at it - all paths set it sooner
+; or later. NOTE: es will point to the PSP until we change it!
+;
+
+ mov dx,InitData
+ mov ds,dx
+ assume ds:InitData
+
+;
+; first off, get the DOS version. If we're not running on NT (VDM) then this
+; TSR's not going to do much, so exit. Exit using various methods, depending
+; on the DOS version (don't you hate compatibility?)
+;
+
+ mov ah,30h
+ int 21h
+ jc ancient_version ; version not even supported
+
+;
+; version is 2.0 or higher. Check it out. al = major#, ah = minor#
+;
+
+ cmp al,major_version
+ jne invalid_version
+
+;
+; what do you know? We're actually running on NT (unless some evil programmer
+; has pinched int 21h/30h and broken it!). Enable minimum instruction set
+; for NTVDM (286 on RISC).
+;
+
+ .286c
+
+;
+; perform an installation check by calling one of our entry points
+; (GetFileServerNameTable). If this returns a table pointer in ES:DI then we
+; know this TSR is already active, in which case we bail out now
+;
+
+ push es
+ push di
+ xor di,di
+ mov es,di
+ mov ax,0ef03h
+ int 21h
+ mov ax,es
+ or ax,di
+ pop di
+ pop es
+ jnz already_here
+
+;
+; OK, the NetWare redir is not already loaded - we're in business.
+; Find entrypoints to nwapi16.dll Get and set the various interrupt
+; vectors, Calculate the amount of space we want to keep,
+; free up any unused space (like the environment segment), display a message
+; in the DEBUG version, then terminate and stay resident. Remember: at this
+; point we expect ES to point at the PSP
+;
+
+ call PullInDll
+ jc already_here ; failed to load
+
+ call InstallInterruptHandlers
+
+ assume es:nothing
+
+ push es
+ pop ds
+ call is_c_on_command_line
+ jz @f
+
+ mov dx,ResidentCode
+ mov ds,dx
+
+ assume ds:ResidentCode
+ mov not_exclusive, 1
+
+ assume ds:nothing
+@@:
+
+;
+; free the environment segment
+;
+
+ mov es,es:[PDB_environ]
+ mov ah,49h
+ int 21h ; free environment segment
+
+;if DEBUG
+;ifdef VERBOSE
+; DbgPrintString <"NetWare Redir successfully loaded",13,10>
+;endif
+;endif
+
+;
+; finally terminate and stay resident
+;
+
+ mov dx,ResidentEnd
+ sub dx,ResidentStart ; number of paragraphs in resident code
+ add dx,10h ; additional for PSP (PDB)
+
+
+;if DEBUG
+;ifdef VERBOSE
+; DbgPrintString "Staying resident with "
+; DbgPrintHexWord dx
+; DbgPrintString " paragraphs. Load seg is ",NOBANNER
+; mov ah,62h
+; int 21h
+; DbgPrintHexWord bx
+; DbgPrintString " current seg is ",NOBANNER
+; DbgPrintHexWord cs
+; DbgCrLf
+;endif
+;endif
+
+ mov ax,3100h
+ int 21h ; terminate and stay resident
+
+;
+; here if the MS-DOS version check (Ah=30h) call is not supported
+;
+
+ancient_version:
+ mov dx,InitData
+ mov ds,dx
+
+ assume ds:InitData
+
+ mov dx,offset bad_ver_msg
+ mov ah,9 ; cp/m-style write to output
+ int 21h
+
+;
+; safe exit: what we really want to do here is INT 20H, but when you do this,
+; CS must be the segment of the PSP of this program. Knowing that CD 20 is
+; embedded at the start of the PSP, the most foolproof way of doing this is
+; to jump (using far return) to the start of the PSP
+;
+
+ push es
+ xor ax,ax
+ push ax
+ retf ; terminate
+
+;
+; we are running on a version of DOS >= 2.00, but its not NT, so we still can't
+; help. Display the familiar message and exit, but using a less programmer-
+; hostile mechanism
+;
+
+invalid_version:
+ mov dx,offset bad_ver_msg
+ mov cx,BAD_VER_MSG_LEN
+ jmps print_error_message_and_exit
+
+;
+; if we cannot initialize 32-bit support (because we can't find/load the DLL)
+; then put back the hooked interrupt vectors as they were when this TSR started,
+; display a message and fail to load the redir TSR
+;
+
+initialization_error:
+ call RestoreInterruptHandlers
+ mov dx,offset cannot_load_msg
+ mov cx,CANNOT_LOAD_MSG_LEN
+ jmps print_error_message_and_exit
+
+;
+; The DOS version's OK, but this TSR is already loaded
+;
+
+already_here:
+ mov dx,offset already_loaded_msg
+ mov cx,ALREADY_LOADED_MSG_LEN
+
+print_error_message_and_exit:
+ mov bx,1 ; bx = stdout handle
+ mov ah,40h ; write to handle
+ int 21h ; write (cx) bytes @ (ds:dx) to stdout
+ mov ax,4c01h ; terminate program
+ int 21h ; au revoir, cruel environment
+
+start endp
+
+;*******************************************************************************
+;*
+;* InstallInterruptHandlers
+;*
+;* Sets the interrupt handlers for all the ints we use - 21
+;*
+;* ENTRY es = PSP segment
+;* ds =
+;*
+;* EXIT Old21Handler contains the original interrupt 21 vector
+;*
+;* RETURNS nothing
+;*
+;* ASSUMES
+;*
+;*******************************************************************************
+
+InstallInterruptHandlers proc
+ push es ; PSP segment - destroyed by INT 21/35h
+ push ds
+
+;
+; note: if we use ResidentCode here, explicitly, instead of seg OldMultHandler,
+; then we can leave out an extraneous load of ds for the ISR address
+;
+
+ mov dx,ResidentCode
+ mov ds,dx
+
+ assume ds:ResidentCode
+
+;
+; Add ourselves to the int 21 chain
+;
+
+ mov ax,3521h
+ int 21h
+ mov word ptr Old21Handler,bx
+ mov word ptr Old21Handler+2,es
+ mov word ptr quick_jump_to_dos+1,bx
+ mov word ptr quick_jump_to_dos+3,es
+ mov word ptr for_dos_proper+1,bx
+ mov word ptr for_dos_proper+3,es
+ mov word ptr chain_previous_int21+1,bx
+ mov word ptr chain_previous_int21+3,es
+ mov dx,offset ResidentCode:NwInt21
+ mov ax,2521h
+ int 21h
+
+ pop ds ; restore segment registers
+ pop es
+ ret
+InstallInterruptHandlers endp
+
+;*******************************************************************************
+;*
+;* RestoreInterruptHandlers
+;*
+;* Resets the interrupt handlers for all the ints we use - 21
+;*
+;* ENTRY Old21Handler
+;* contain the interrupt vectors from before nw16.sys was loaded
+;*
+;* EXIT Original interrupt vectors are restored
+;*
+;* RETURNS nothing
+;*
+;* ASSUMES
+;*
+;*******************************************************************************
+
+RestoreInterruptHandlers proc
+ push ds
+
+ assume ds:nothing
+
+ push es
+ mov dx,ResidentCode
+ mov es,dx
+
+ assume es:ResidentCode
+
+ lds dx,Old21Handler
+ mov ax,2521h
+ int 21h
+
+ pop es
+ pop ds
+ ret
+RestoreInterruptHandlers endp
+
+;*******************************************************************************
+;*
+;* PullInDll
+;*
+;* Does a RegisterModule to load NWAPI32.DLL into our NTVDM.EXE
+;*
+;* ENTRY nothing
+;*
+;* EXIT nothing
+;*
+;* RETURNS cf if fails.
+;*
+;* ASSUMES Earth moves round Sun
+;*
+;******************************************************************************/
+
+PullInDll proc near
+
+ pusha ; dispatch code
+ push dx ; save callers dx,ds,es,ax
+ push ds
+ push es
+ push ax
+
+ mov dx,InitCode
+ mov ds,dx
+
+ assume ds:InitCode
+
+ push ds
+ pop es
+
+ assume es:InitCode
+
+ mov si,offset DllName ; ds:si = nwapi32.dll
+ mov di,offset InitFunc ; es:di = init routine
+ mov bx,offset DispFunc ; ds:bx = dispatch routine
+ mov ax,ResidentCode
+ mov dx,offset ConnectionIdTable
+ ; ax:dx = shared datastructure
+
+ RegisterModule
+
+ jc @f
+
+ mov dx,ResidentCode
+ mov ds,dx
+ assume ds:ResidentCode
+ mov word ptr hVDD,ax
+
+@@: pop ax ; callers ax
+ pop es ; callers es
+ pop ds ; callers ds
+ pop dx ; callers dx
+
+ assume ds:nothing
+ assume es:nothing
+
+ popa ; dispatch code
+ ret
+PullInDll endp
+
+;*******************************************************************************
+;*
+;* is_c_on_command_line
+;*
+;* -C or /C means we should open compatiblity mode createfiles as shared
+;* instead of exclusive
+;*
+;* ENTRY ds points to PDB
+;*
+;* EXIT nothing
+;*
+;* RETURNS zero if not found.
+;*
+;* ASSUMES ds points at PSP
+;*
+;******************************************************************************/
+
+is_c_on_command_line proc near
+ mov si,80h
+ lodsb
+ cbw
+ mov cx,ax
+next: jcxz quit
+ dec cx
+ lodsb
+check_next:
+ cmp al,'-'
+ je check_c
+ cmp al,'/'
+ je check_c
+ cmp al,' '
+ je next
+ cmp al,9
+ je next
+find_ws:jcxz quit
+ dec cx
+ lodsb
+ cmp al,' '
+ je next
+ cmp al,9
+ je next
+ jmp short find_ws
+check_c:jcxz quit
+ dec cx
+ lodsb
+ or al,20h
+ cmp al,'c'
+ jne find_ws
+ or cx,ax
+quit: or cx,cx
+ ret
+is_c_on_command_line endp
+
+InitCodeEnd
+end start
diff --git a/private/nw/nw16/tsr/resident.asm b/private/nw/nw16/tsr/resident.asm
new file mode 100644
index 000000000..5c95168da
--- /dev/null
+++ b/private/nw/nw16/tsr/resident.asm
@@ -0,0 +1,1039 @@
+page ,132
+if 0
+
+/*++
+
+Copyright (c) 1993-4 Microsoft Corporation
+
+Module Name:
+
+ resident.asm
+
+Abstract:
+
+ This module contains the resident code part of the stub redir TSR for NT
+ VDM NetWare support.
+
+Author:
+
+ Colin Watson (colinw) 08-Jul-1993
+
+Environment:
+
+ Dos mode only
+
+Revision History:
+
+ 08-Jul-1993 colinw
+ Created
+
+--*/
+
+endif
+
+
+
+.xlist ; don't list these include files
+.xcref ; turn off cross-reference listing
+include isvbop.inc ; NTVDM BOP mechanism
+include dosmac.inc ; Break macro etc (for following include files only)
+include dossym.inc ; User_<Reg> defines
+include segorder.inc ; segments
+include mult.inc ; MultNET
+include sf.inc ; SFT definitions/structure
+include pdb.inc ; program header/process data block structure
+
+include debugmac.inc ; DbgPrint macro
+include asmmacro.inc ; language extensions
+
+include nwdos.inc ; NetWare structures and nwapi32 interface
+
+.cref ; switch cross-reference back on
+.list ; switch listing back on
+subttl ; kill subtitling started in include file
+
+
+.286 ; all code in this module 286 compatible
+
+far_segment segment
+far_label label far
+far_segment ends
+
+ResidentCodeStart
+
+ assume cs:ResidentCode
+ assume ds:nothing
+ assume es:nothing
+ assume ss:nothing
+
+ public Old21Handler
+Old21Handler dd ?
+
+;
+; IMPORTANT: the following up to the comment <END NWDOSTABLE> must
+; be kept in the same order as for the NWDOSTABLE structure in NWDOS.H/.INC.
+; Align on 32 bits to make it convenient for nwapi32.dll
+;
+ align 4
+
+ public ConnectionIdTable
+ConnectionIdTable CID MC dup (<>)
+
+ public ServerNameTable
+ServerNameTable db MC * SERVERNAME_LENGTH dup (0)
+
+ public DriveIdTable
+DriveIdTable db MD dup (0)
+
+ public DriveFlagTable
+DriveFlagTable db MD dup (0)
+
+ public DriveHandleTable
+DriveHandleTable db MD dup (0)
+
+ public PreferredServer
+PreferredServer db 0
+
+ public PrimaryServer
+PrimaryServer db 0
+
+ public TaskModeByte
+TaskModeByte db 0
+
+CurrentDrive db 0
+
+ public SavedAx;
+SavedAx dw 0
+
+ public NtHandleHi;
+NtHandleHi dw 0
+ public NtHandleLow;
+NtHandleLow dw 0
+
+ public NtHandleSrcHi; // Used in FileServerCopy
+NtHandleSrcHi dw 0
+ public NtHandleSrcLow;
+NtHandleSrcLow dw 0
+
+ public hVDD
+hVDD dw -1
+
+ public PmSelector
+PmSelector dw 0
+
+ public CreatedJob
+CreatedJob db 0
+ public JobHandle
+JobHandle db 0
+
+NOV_BUFFER_LENGTH equ 256
+
+ public DenovellBuffer
+DenovellBuffer db NOV_BUFFER_LENGTH dup (?)
+
+ public DenovellBuffer2
+DenovellBuffer2 db NOV_BUFFER_LENGTH dup (?)
+
+
+.errnz (size DeNovellBuffer2 - size DenovellBuffer)
+
+Comspec db "COMSPEC="
+COMSPEC_LENGTH equ ($ - Comspec)
+
+;
+; this is the <END NWDOSTABLE> structure.
+;
+
+;
+; data passed from nw16.asm
+;
+ public not_exclusive
+not_exclusive db 0
+
+ page
+
+ public NwInt21
+NwInt21 proc far
+ assume cs:ResidentCode
+ assume ds:nothing
+ assume es:nothing
+ assume ss:nothing
+
+ sti ; make sure ints are still enabled
+
+;
+; check whether we filter this vector; if not, pass it through to previous INT 21
+; handler (DOS or some other TSR)
+;
+; If this is a name based operation, and the caller is passing through a novell
+; format name - SYS:FOO or SERVER\SYS:FOO - then munge the name to be a UNC name
+;
+
+ cmp ah,0eh
+ jne @f
+ jmp select_default_drive
+@@: cmp ah,39h ; create directory
+ je check_name
+ ja @f
+
+;
+; ah less than 39h (mkdir) is definitely for DOS
+;
+
+ public quick_jump_to_dos
+quick_jump_to_dos:
+ jmp far_label
+
+;
+; run any of the following name-based calls through the name check:
+;
+; 3ah remove directory
+; 3bh change directory
+; 3ch create file
+; 3dh open file
+; 41h delete file
+; 43h get/set attributes
+; 4bh exec program
+; 4eh find first file
+; 56h rename
+;
+
+@@: cmp ah,3dh
+ jbe check_name
+ cmp ah,41h ; delete file
+ je check_name
+ cmp ah,43h ; get/set attributes
+ je check_name
+ cmp ah,4bh ; exec program
+ je check_name
+ cmp ah,4eh ; find first file
+ je check_name
+ cmp ah,56h ; rename
+ je rename
+ jmp dispatch_check
+
+
+;
+; Rename function. This has 2 path names: source in ds:dx and
+; destination in es:di. Check the destination first then fall through
+; and check the source.
+;
+rename:
+ push ds
+ push dx
+ push es
+ push di ; user registers saved for after Int21
+
+ push ds ; save ds:dx 'cause we will corrupt them
+ push dx
+
+ mov dx,es
+ mov ds,dx
+ mov dx,di ; ds:dx = destination buffer
+ call IsDosPath
+ je @f ; DOS path, no modification
+ cld
+ push di
+ call DenovellizeName
+ pop di
+ cmp dx,offset DenovellBuffer
+ je swap_buffers
+
+@@:
+ pop dx ; ds:dx points at source again
+ pop ds
+
+ pop di
+ pop es
+ pop dx
+ pop ds
+ jmp check_name
+
+;
+; Destination name was normalized and stored in DeNovellBuffer. put the data
+; in Denovellbuffer2 in-case we need to put the Source name in Denovellbuffer
+;
+
+swap_buffers:
+ push cx
+ push si
+ push ds ; will become es during Dos call
+
+ mov si,dx
+ mov di,cs
+ mov es,di
+ mov di,offset DenovellBuffer2
+ mov cx,NOV_BUFFER_LENGTH / 2
+.errnz (NOV_BUFFER_LENGTH and 1)
+
+ rep movsw
+
+ mov di,offset DenovellBuffer2
+ pop es ; es:di is now Denovellbuffer2
+ pop si
+ pop cx
+
+ pop dx ; make ds:dx source again
+ pop ds
+
+ ; stack has users di,es,dx,ds pushed
+ ; parameters are same as callers except for es:di
+ jmp check_src
+
+check_name: ; ds:dx points at name to examine
+ push ds
+ push dx
+ push es
+ push di
+ ; fall through
+
+check_src: ; only jumped to in rename
+
+ cld
+ call IsDosPath
+ je for_dos_properR ; x: or UNC filename. No more processing
+
+ cmp ah,3dh
+ jne notNETQ ; special NETQ open only applies for create
+ cmp CreatedJob,0
+ jz notNETQ ; don't look at name if no job handle available
+
+ push ax
+ push si
+ mov si,dx
+ cld
+ lodsw
+ cmp ax,"EN"
+ jne @f
+ lodsw
+ cmp ax,"QT"
+ jne @f
+ lodsb
+ or al,al
+ jnz @f
+
+ pop si ; Opening NETQ. Return Dos handle from CreateJob and File
+ pop ax
+ mov CreatedJob,0 ; Only return handle once
+ mov al, JobHandle
+ xor ah, ah
+ pop di
+ pop es
+ pop dx
+ pop ds
+ clc
+ retf 2
+
+@@: pop si
+ pop ax
+ jmp for_dos_properR
+
+notNETQ:push di
+ call DenovellizeName ; munge the name if required
+ pop di ; restore caller DI
+
+;
+; Look for compatibility mode opens that need to change to exlusive mode
+; opens so that they get properly cached. Criteria for opening exclusive
+; is that the application did not specify any sharing modes and the drive
+; being opened is on a netware drive.
+;
+
+ cmp ah, 3ch
+ je @f
+ cmp ah, 3dh
+ jne not_compat
+@@: test al,OF_SHARE_MASK
+ jne not_compat
+
+ cmp not_exclusive, 1 ; open shared mode anyway
+ je not_compat
+
+ mov SavedAx,ax
+ mov ax,hVdd
+ DispatchCall ; 32 bit code decides if compat mode
+
+not_compat:
+ pushf
+ call Old21Handler ; fake int 21 to get to DOS
+
+ pop di
+ pop es
+ pop dx
+ pop ds
+ retf 2 ; return to app (with flags from DOS)
+
+for_dos_properR: ; restore regs and call dos
+ pop di
+ pop es
+ pop dx
+ pop ds
+ cmp ah, 3ch
+ je @f
+ cmp ah, 3dh
+ jne for_dos_proper
+@@: test al,OF_SHARE_MASK
+ jne for_dos_proper
+ cmp not_exclusive, 1 ; open shared mode anyway
+ je for_dos_proper
+ mov SavedAx,ax
+ mov ax,hVdd
+@@: DispatchCall ; 32 bit code decides if compat mode
+ public for_dos_proper
+for_dos_proper:
+ jmp far_label
+
+dispatch_check:
+ cmp ah,04ch
+ jne check_9f
+ jmp process_exit
+
+;
+; 'special' entry point to return the data segment info to the protect-mode code
+; so it can generate an LDT descriptor which refers to this memory.
+;
+
+check_9f:
+ cmp ah,9fh
+ jne check_nw_ep ; is it a Netware call?
+ or al,al
+ jnz check_handle_mapper
+ mov bx,seg ConnectionIdTable; 9f00: return segment info
+ mov dx,offset ConnectionIdTable
+ clc ; if we loaded then it can't fail
+ retf 2
+
+;
+; if the call is 9f01 then we call MapNtHandle for the value in BX. This will
+; update NtHandleHi and NtHandleLow, which we assume will be accessed from the
+; code segment register
+;
+
+check_handle_mapper:
+ cmp al,1
+ jne check_nw_ep ; still not one of ours?
+ call MapNtHandle ; 9f01: call MapNtHandle
+ retf 2
+
+check_nw_ep:
+ cmp ah,0b4h
+ jb for_dos_proper
+ cmp ah,0f3h
+ ja for_dos_proper
+ jne @f
+ jmp file_server_copy
+@@: cmp ah,0BAh
+ jne check_f0
+
+ push bx ; get environment. used by map.exe
+ push ax
+ mov ah,051h ; load current apps PDB into ax
+ int 021h
+
+@@: mov es, bx
+ cmp bx, es:PDB_Parent_PID
+ je @f
+ mov bx, es:PDB_Parent_PID
+ jmp @b
+@@:
+ mov dx, es:PDB_environ ; set DX to environment segment
+ mov es, dx ; set es:di to value of COMSPEC
+
+ push si
+ push ds
+ mov ds, dx
+ xor si, si
+
+; future code to save space
+; es <- env seg
+; di <- env off
+; ds <- cs
+; si <- offset Comspec
+; cx <- .size Comspec / 2
+; cld
+; repz cmpsw
+; jnz no match
+
+; al <- 0
+; cx <- remaining size of env seg
+; rep scasb
+
+ cld
+next_var:
+ lodsb
+ cmp al, "C"
+ jne @f
+ lodsb
+ cmp al, "O"
+ jne @f
+ lodsb
+ cmp al, "M"
+ jne @f
+ lodsb
+ cmp al, "S"
+ lodsb
+ jne @f
+ cmp al, "P"
+ jne @f
+ lodsb
+ cmp al, "E"
+ jne @f
+ lodsb
+ cmp al, "C"
+ jne @f
+ lodsb
+ cmp al, "="
+ je got_comspec
+
+@@: ; Search for null terminating environment
+ or al,al
+ je next_var
+ lodsb
+ jmp @b
+
+got_comspec:
+ pop ds
+ mov di,si
+ pop si
+
+ pop ax
+ pop bx
+ iret
+
+check_f0:
+ cmp ah,0f0h
+ jne for_me
+
+;
+; if we're here then we're doing simple stuff that we don't need to bop fer
+; currently stuff here is ah=f0, al = 00, 01, 04, 05
+;
+; caveat emptor dept #312: However, it came to pass that we needed to bop when
+; the f00x calls were made without any preceding calls that would cause nwapi32
+; to be loaded
+;
+
+dispatch_f0:
+
+.errnz ((offset PrimaryServer - offset PreferredServer) - 1)
+
+ or al,al ; f000 = set preferred server
+ jnz try_01
+ cmp dl,8
+ ja zap_preferred
+ mov PreferredServer,dl
+ iret
+
+zap_preferred:
+ mov PreferredServer,al ; al contains 0 remember
+ iret
+
+try_01: cmp al,1 ; f001 = get preferred server
+ jnz try_02
+ mov al,PreferredServer
+ iret
+
+try_02: cmp al,2 ; f002 = get default server
+ jnz try_04
+ mov al,PreferredServer
+ or al,al
+ jnz @f
+ mov al,PrimaryServer
+@@: iret
+
+try_04: cmp al,4 ; f004 = set primary server
+ jne try_05
+ cmp dl,8
+ ja zap_primary
+ mov PrimaryServer,dl
+ iret
+
+zap_primary:
+ mov PrimaryServer,0
+ iret
+
+try_05: cmp al,5 ; f005 = get primary server
+ jne for_me
+ mov al,PrimaryServer
+ iret
+
+file_server_copy:
+ call FileServerCopy ; f3 - Used by ncopy.exe
+ ;jmp for_me
+
+;
+; if the process exits and the dll is loaded then call the 32 bit code to
+; close any cached handles.
+;
+
+process_exit:
+ ;jmp for_me
+
+;
+; if we're here then the dispatch code is for a NetWare client API. First we
+; check if we have already loaded the 32-bit code. If not, then load it. If we
+; get an error, we will fall through to DOS
+;
+
+for_me:
+ cmp ah,0BCh ; bc,bd,be need handle mapping
+ jb no_mapping
+ cmp ah,0BEh
+ ja no_mapping
+
+;do_mapping_call:
+ call MapNtHandle ; take bx and find the Nt handle
+
+no_mapping:
+ mov SavedAx,ax
+
+ cmp ah,0e3h ; Look for CreateJob NCP
+ jne @f ; try f2 alternative
+
+ mov al,[si+2] ; si is NCP subfunction
+ jmp lookupcode
+
+@@: cmp ax,0f217h
+ jne do_dispatch ; Not CreateJob
+ mov al,[si+2] ; si is NCP subfunction
+
+lookupcode:
+ cmp al,68h
+ je createjob
+ cmp al,79h
+ jne do_dispatch
+
+
+createjob: ; It is a CreateJob and File
+
+ ; Always return the errorcode from the NCP exchange
+ ; regardless of any earlier failures in the NT plumbing.
+ mov ax, SavedAx
+ push ax ; Open \\Server\queue for NCP
+ push ds
+ push dx
+ mov ax, 9f02h
+ mov SavedAx,ax
+
+ mov ax,hVdd
+ DispatchCall ; Set DeNovellBuffer to \\Server\queue
+ ; and registers ready for DOS OpenFile
+
+ pushf
+ call Old21Handler ; Open \\server\queue
+ jc @f
+ mov JobHandle, al
+ mov CreatedJob, 1 ; Flag JobHandle is valid
+ push bx
+ xor ah, ah
+ mov bx, ax ; JobHandle
+ call MapNtHandle ; take bx and find the Nt handle
+ pop bx
+
+@@:
+ pop dx
+ pop ds ; Proceed and send the NCP
+ pop ax
+ mov SavedAx, ax
+
+do_dispatch:
+ mov ax,hVdd
+ DispatchCall
+ retf 2 ; return to the application
+
+ public chain_previous_int21
+chain_previous_int21:
+ jmp far_label
+
+
+;
+; Save new drive so we can conveniently handle compatibility mode opens.
+; also need to return 32 as the number of available drives.
+;
+
+select_default_drive:
+ pushf
+ call Old21Handler ; fake int 21 to get to DOS
+
+ mov ah,19h ; get current drive
+ pushf
+ call Old21Handler ; fake int 21 to get to DOS
+ mov CurrentDrive,al ; current drive
+
+ mov al,32 ; # of drives supported by NetWare
+ retf 2 ; return to app (with flags from DOS)
+
+
+NwInt21 endp
+
+;*******************************************************************************
+;*
+;* FileServerCopy
+;*
+;* Implement preperation for calling
+;* \\...)
+;*
+;* ENTRY applications registers
+;*
+;* EXIT nothing
+;*
+;* RETURNS nothing
+;*
+;* ASSUMES no registers (except flags) can be destroyed
+;*
+;******************************************************************************/
+
+FileServerCopy proc near
+
+ push ax
+ push bx
+
+ mov bx,word ptr es:[di] ; Map Source Handle
+ call MapNtHandle
+
+ mov bx,NtHandleHi
+ mov NtHandleSrcHi,bx
+ mov bx,NtHandleLow
+ mov NtHandleSrcLow,bx
+
+ mov bx,word ptr es:[di+2] ; Map Destination Handle
+ call MapNtHandle
+
+@@: pop bx
+ pop ax
+
+ ret
+FileServerCopy endp
+
+;*******************************************************************************
+;*
+;* IsDosPath
+;*
+;* Checks to see if a path name looks like a Microsoft path (<drive>:... or
+;* \\...)
+;*
+;* ENTRY ds:dx = path name
+;*
+;* EXIT nothing
+;*
+;* RETURNS ZF = 1: path is for MS-DOS
+;*
+;* ASSUMES no registers (except flags) can be destroyed
+;*
+;******************************************************************************/
+
+IsDosPath proc near
+ push ax
+ xchg si,dx ; si = offset of filename; dx = ????
+ mov al,[si+1] ; al = second character of filename
+ cmp al,':'
+ je @f ; looks like a DOS filename
+ cmp al,'\' ; (X\... or \\...)
+ jne tryFirstbyte
+ cmp al,'/' ; (X/... or //...)
+ jne @f ; second char is not "\" or "/"
+
+tryFirstbyte:
+ mov al,[si] ; al = first character of filename
+ cmp al,'\' ; (\\... or \/...)
+ je @f
+ cmp al,'/' ; (\/... or //...)
+
+@@: xchg si,dx ; dx = offset of filename; si = ????
+ pop ax
+ ret
+IsDosPath endp
+
+;*******************************************************************************
+;*
+;* DenovellizeName
+;*
+;* Converts a name from Novell format (SERVER\SHARE:filename or
+;* SHARE:filename) to DOS UNC name. Server name is found by:
+;*
+;* if PreferredServer != 0 then Index = PreferredServer
+;* else if PrimaryServer != 0 then Index = PrimaryServer
+;* else Index = 0
+;* servername = ServerNameTable[Index * sizeof(SERVER_NAME)]
+;*
+;* ENTRY ds:dx = name
+;*
+;* EXIT ds:dx = offset of DenovellBuffer
+;*
+;* RETURNS if success, DI points to last byte+1 in DenovellBuffer, else
+;* DI is garbage
+;*
+;* ASSUMES 1. filename does not wrap in buffer segment
+;* 2. DI register can be trashed
+;* 3. DF = 0
+;*
+;******************************************************************************/
+
+DenovellizeName proc near
+ assume ds:nothing
+ assume es:nothing
+
+ push ax
+ push bx
+ push cx
+ push bp
+ push si
+ push es
+ mov bp,ds
+
+;
+; get the length of the input filename
+;
+
+ mov cx,ds
+ mov es,cx
+ mov di,dx ; es:di = filename
+ xor cx,cx
+ dec cx ; cx = ffff
+ xor al,al
+ repnz scasb
+ not cx
+ dec cx ; cx = strlen(filename)
+ cmp cx,length DenovellBuffer
+ jb @f
+ jmp dnn_ret ; filename too long: give it to DOS
+
+;
+; find the offset of ':' in the filename
+;
+
+@@: mov bx,cx ; remember length
+ mov di,dx ; es:di = filename
+ mov al,':'
+ repnz scasb ; di = strchr(filename, ':')+1
+ jz @f
+go_home:jmp dnn_ret ; no ':' - not novell format name?
+@@: cmp byte ptr [di],0
+ je go_home ; device name? (eg "LPT1:") - to DOS
+ mov si,di ; si = offset of ':' in name, +1
+
+;
+; find the offset of the first '/' or '\'
+;
+
+ mov cx,bx ; cx = length of filename
+ mov di,dx ; di = offset of filename
+ mov al,'\'
+ repnz scasb
+ sub bx,cx
+ mov cx,bx
+ mov bx,di
+ mov di,dx
+ mov al,'/'
+ repnz scasb
+ jnz @f
+ mov bx,di
+
+;
+; if ':' before '\' or '/' then name is SYS:FOO... else SERVER\SYS:FOO...
+;
+
+@@: mov di,cs
+ mov es,di
+ mov di,offset DenovellBuffer
+ mov ax,('\' shl 8) + '\'
+ stosw
+ cmp bx,si
+ jb copy_share_name
+ xor bx,bx
+ mov cl,PreferredServer
+ or cl,cl
+ jnz got_index
+ mov cl,PrimaryServer
+ jcxz get_server_name
+
+got_index:
+ dec cl
+ jz get_server_name
+ mov bx,cx
+
+.errnz SERVERNAME_LENGTH - 48
+
+ shl cx,5
+ shl bx,4
+
+get_server_name:
+ add bx,cx
+ mov cx,ds
+ mov si,es
+ mov ds,si
+ lea si,ServerNameTable[bx]
+ cmp byte ptr [si],0
+ je dnn_ret
+ mov ah,SERVERNAME_LENGTH
+
+copy_server_name:
+ lodsb
+ or al,al
+ jz done_server_name
+ stosb
+ dec ah
+ jnz copy_server_name
+
+done_server_name:
+ mov al,'\'
+ stosb
+ mov ds,cx
+
+copy_share_name:
+ mov si,dx
+
+next_char:
+ lodsb
+ cmp al,':'
+ je @f
+ stosb
+ jmp short next_char
+@@: mov al,'\'
+ stosb
+
+copy_rest:
+ lodsb
+ stosb
+ or al,al
+ jnz copy_rest
+ cmp byte ptr [si-2],':'
+ jne @f
+ mov byte ptr [si-2],0
+@@: mov dx,offset DenovellBuffer
+ mov bp,es
+
+dnn_ret:mov ds,bp
+ pop es
+ pop si
+ pop bp
+ pop cx
+ pop bx
+ pop ax
+ ret
+DenovellizeName endp
+
+
+
+;*** DosCallBack
+;*
+;* Call back into DOS via the int 2f/ah=12 back door. If CALL_DOS defined,
+;* use a call, else s/w interrupt. Using a call means no other TSRs etc.
+;* which load AFTER the redir can hook it, but we DON'T HAVE TO MAKE A
+;* PRIVILEGE TRANSITION ON x86 which speeds things up. This should be safe,
+;* because no other s/w should really be hooking INT 2F/AH=12
+;*
+;* ENTRY FunctionNumber - dispatch code goes in al
+;* DosAddr - if present, variable containing address of
+;* DOS int 2f entry point
+;* OldMultHandler - this variable contains the address of DOSs
+;* int 2f back door. Specific to redir code
+;*
+;* EXIT nothing
+;*
+;* USES ax, OldMultHandler
+;*
+;* ASSUMES nothing
+;*
+;***
+
+DosCallBack macro FunctionNumber, DosAddr
+ mov ax,(MultDOS shl 8) + FunctionNumber
+ifdef CALL_DOS
+ pushf
+ifb <DosAddr>
+if (((.type OldMultHandler) and 32) eq 0) ;; OldMultHandler not defined
+ extrn OldMultHandler:dword
+endif
+ call OldMultHandler
+else
+ call DosAddr
+endif
+else
+ int 2fh
+endif
+endm
+
+;
+; defines for DosCallBack FunctionNumbers
+;
+
+SF_FROM_SFN = 22
+PJFN_FROM_HANDLE= 32
+
+; *** MapNtHandle
+; *
+; * Given a handle in BX, map it to a 32-bit Nt handle store result
+; * in NtHandle[Hi|Low]
+; *
+; *
+; * ENTRY bx = handle to map
+; *
+; * EXIT Success - NtHandle set to 32-bit Nt handle from SFT
+; *
+; * RETURNS Success - CF = 0
+; * Failure - CF = 1, ax = ERROR_INVALID_HANDLE
+; *
+; * USES ax, bx, flags
+; *
+; * ASSUMES nothing
+; *
+; ***
+
+MapNtHandle proc near
+ pusha ; save regs used by Dos call back
+ push ds
+ push es
+
+;
+; call back to Dos to get the pointer to the JFN in our caller's JFT. Remember
+; the handle (BX) is an index into the JFT. The byte at this offset in the JFT
+; contains the index of the SFT structure we want in the system file table
+;
+
+ DosCallBack PJFN_FROM_HANDLE ; pJfnFromHamdle
+ jc @f ; bad handle
+
+;
+; we retrieved a pointer to the required byte in the JFT. The byte at this
+; pointer is the SFT index which describes our 'file' (file to (un)lock in
+; this case). We use this as an argument to the next call back function -
+; get Sft from System File Number.
+;
+
+ mov bl,es:[di]
+ xor bh,bh
+ DosCallBack SF_FROM_SFN ; SfFromSfn
+ jc @f ; oops - bad handle
+
+;
+; Ok. We have a pointer to the SFT which describes this named pipe. Get the
+; 32-bit Nt handle and store it in the shared datastructure.
+;
+
+ mov bx,word ptr es:[di].sf_NtHandle[2]
+ mov NtHandleHi,bx
+ mov bx,word ptr es:[di].sf_NtHandle
+ mov NtHandleLow,bx
+
+;
+; restore all registers used by Dos call back.
+; Carry flag is set appropriately
+;
+
+@@: pop es
+ pop ds
+ popa
+ jnc @f
+
+;
+; finally, if there was an error then return a bad handle indication in ax
+;
+
+ mov ax,ERROR_INVALID_HANDLE
+@@: ret
+MapNtHandle endp
+
+ResidentCodeEnd
+
+end
diff --git a/private/nw/nw16/tsr/segorder.inc b/private/nw/nw16/tsr/segorder.inc
new file mode 100644
index 000000000..689c62fa2
--- /dev/null
+++ b/private/nw/nw16/tsr/segorder.inc
@@ -0,0 +1,113 @@
+;/*++
+;
+;Copyright (c) 1991 Microsoft Corporation
+;
+;Module Name:
+;
+; segorder.inc
+;
+;Abstract:
+;
+; This module contains the segment order and segment macros
+;
+;Author:
+;
+; Richard Firth (rfirth) 05-Sep-1991
+;
+;Environment:
+;
+; Dos mode only
+;
+;Notes:
+;
+; When initially loaded, the NT VDM redir has the following order:
+;
+; +----------------------+
+; | |
+; | Resident Code |
+; | |
+; +----------------------+
+; | |
+; | Resident Data |
+; | |
+; +----------------------+ ----------------+
+; | | |
+; | Initialisation Code | <- entry point v
+; | |
+; +----------------------+
+; | | all the stuff between these
+; | Initialisation Data | arrows is discarded if we stay
+; | | resident. Note that the redir
+; +----------------------+ does not uninstall
+; | |
+; | Initialisation Stack | ^
+; | | |
+; +----------------------+ ----------------+
+;
+;Revision History:
+;
+; 05-Sep-1991 rfirth
+; Created
+;
+;--*/
+
+
+
+ResidentStart segment public para 'code'
+ResidentStart ends
+
+ResidentCode segment public word 'code'
+ResidentCode ends
+
+ResidentData segment public word 'data'
+ResidentData ends
+
+ResidentEnd segment public para 'data'
+ResidentEnd ends
+
+ResidentGroup group ResidentStart, ResidentCode, ResidentData, ResidentEnd
+
+InitCode segment public para 'init'
+InitCode ends
+
+InitData segment public word 'init'
+InitData ends
+
+InitStack segment stack para 'stack'
+InitStack ends
+
+;
+; macros to avoid having to type in/possibly alter segment header guff
+;
+
+ResidentCodeStart macro
+ResidentCode segment public word 'code'
+endm
+
+ResidentCodeEnd macro
+ResidentCode ends
+endm
+
+ResidentDataStart macro
+ResidentData segment public word 'data'
+endm
+
+ResidentDataEnd macro
+ResidentData ends
+endm
+
+InitCodeStart macro
+InitCode segment public para 'init'
+endm
+
+InitCodeEnd macro
+InitCode ends
+endm
+
+InitDataStart macro
+InitData segment public word 'init'
+endm
+
+InitDataEnd macro
+InitData ends
+endm