From e611b132f9b8abe35b362e5870b74bce94a1e58e Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 16 May 2020 20:51:50 -0700 Subject: initial commit --- private/nw/nw16/dll/debug.c | 584 +++++++ private/nw/nw16/dll/locks.c | 677 ++++++++ private/nw/nw16/dll/makefile | 6 + private/nw/nw16/dll/ncp.c | 3383 +++++++++++++++++++++++++++++++++++++++ private/nw/nw16/dll/nwapi16.rc | 12 + private/nw/nw16/dll/nwapi16.src | 10 + private/nw/nw16/dll/procs.h | 159 ++ private/nw/nw16/dll/sources | 71 + 8 files changed, 4902 insertions(+) create mode 100644 private/nw/nw16/dll/debug.c create mode 100644 private/nw/nw16/dll/locks.c create mode 100644 private/nw/nw16/dll/makefile create mode 100644 private/nw/nw16/dll/ncp.c create mode 100644 private/nw/nw16/dll/nwapi16.rc create mode 100644 private/nw/nw16/dll/nwapi16.src create mode 100644 private/nw/nw16/dll/procs.h create mode 100644 private/nw/nw16/dll/sources (limited to 'private/nw/nw16/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 + +--*/ + +{ + 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 +typedef struct _TTSOUTPACKET { + UCHAR SubFunction; + USHORT cx; + USHORT dx; +} TTSOUTPACKET, *PTTSOUTPACKET ; + +typedef struct _TTSINPACKET{ + USHORT cx; + USHORT dx; +} TTSINPACKET, *PTTSINPACKET; + +#include + +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; ilpRemoteName ); + + 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 + +typedef struct _TTSOUTPACKETTYPE { + UCHAR SubFunction; + USHORT cx; + USHORT dx; +} TTSOUTPACKETTYPE; + +typedef struct _TTSINPACKETTYPE { + USHORT cx; + USHORT dx; +} TTSINPACKETTYPE; + +#include + +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 + +#include + +#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 + +#include +#include +#include +#include + +#include // strcmp +#include +#include +#include // FORMAT_LPSTR + +#include +#include +#include +#include +#include + +#include +#include +#include + +// 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 -- cgit v1.2.3