diff options
Diffstat (limited to 'private/nw/nw16')
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 |