summaryrefslogtreecommitdiffstats
path: root/private/mvdm/dos/command
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/mvdm/dos/command
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/mvdm/dos/command')
-rw-r--r--private/mvdm/dos/command/cmd.c34
-rw-r--r--private/mvdm/dos/command/cmd.h292
-rw-r--r--private/mvdm/dos/command/cmdconf.c636
-rw-r--r--private/mvdm/dos/command/cmddata.c51
-rw-r--r--private/mvdm/dos/command/cmddisp.c56
-rw-r--r--private/mvdm/dos/command/cmdenv.c696
-rw-r--r--private/mvdm/dos/command/cmdexec.c650
-rw-r--r--private/mvdm/dos/command/cmdexit.c31
-rw-r--r--private/mvdm/dos/command/cmdkeyb.c251
-rw-r--r--private/mvdm/dos/command/cmdkeyb.h18
-rw-r--r--private/mvdm/dos/command/cmdmisc.c897
-rw-r--r--private/mvdm/dos/command/cmdpif.c289
-rw-r--r--private/mvdm/dos/command/cmdpif.h46
-rw-r--r--private/mvdm/dos/command/cmdredir.c664
-rw-r--r--private/mvdm/dos/command/makefile9
-rw-r--r--private/mvdm/dos/command/sources60
16 files changed, 4680 insertions, 0 deletions
diff --git a/private/mvdm/dos/command/cmd.c b/private/mvdm/dos/command/cmd.c
new file mode 100644
index 000000000..c701f8a86
--- /dev/null
+++ b/private/mvdm/dos/command/cmd.c
@@ -0,0 +1,34 @@
+/*
+ * cmd.c - Main Module of Command.lib
+ *
+ * Sudeepb 09-Apr-1991 Craeted
+ */
+
+#include "cmd.h"
+#include "cmdsvc.h"
+
+
+/* CmdInit - COmmand Initialiazation routine.
+ *
+ * Entry
+ * argc,argv - from softpc as it is.
+ * Full path name of the dos binary is preceded with
+ * -a or /a. i.e. -a c:\nt\bin86\kernel.exe reversi.exe
+ *
+ *
+ * Exit
+ *
+ */
+
+BOOL CMDInit (argc,argv)
+INT argc;
+PSZ *argv;
+{
+CHAR RootDir [MAX_PATH];
+UINT Len;
+
+ Len = GetSystemDirectory (RootDir,MAX_PATH);
+ if (Len <= MAX_PATH && Len > 0)
+ cmdHomeDirectory[0] = RootDir[0];
+ return TRUE;
+}
diff --git a/private/mvdm/dos/command/cmd.h b/private/mvdm/dos/command/cmd.h
new file mode 100644
index 000000000..8ace02a73
--- /dev/null
+++ b/private/mvdm/dos/command/cmd.h
@@ -0,0 +1,292 @@
+/* cmd.h - main include file for command.lib
+ *
+ * Modification History
+ *
+ * Sudeepb 17-Sep-1991 Created
+ */
+
+/*
+#define WIN
+#define FLAT_32
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+
+#define _WINDOWS
+#include <windows.h>
+
+*/
+
+#ifdef DOS
+#define SIGNALS
+#endif
+
+#ifdef OS2_16
+#define OS2
+#define SIGNALS
+#endif
+
+#ifdef OS2_32
+#define OS2
+#define FLAT_32
+#endif
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <malloc.h>
+#include <process.h>
+
+#ifdef WIN_16
+#define WIN
+#define API16
+#endif
+
+#ifdef WIN_32
+#define WIN
+#define FLAT_32
+#define TRUE_IF_WIN32 1
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+#else
+#define TRUE_IF_WIN32 0
+#endif
+
+#ifdef FLAT_32
+#ifndef i386
+#define ALIGN_32
+#else
+#define NOALIGN_32
+#endif
+#endif
+
+#ifdef WIN
+#define _WINDOWS
+#include <windows.h>
+#endif
+
+#ifdef SIGNALS
+#include <conio.h>
+#include <signal.h>
+#endif
+
+#ifdef OS2_32
+#include <excpt.h>
+#define XCPT_SIGNAL 0xC0010003
+#endif
+
+#include <vdmapi.h>
+
+#define COPY_STD_OUT 1
+#define COPY_STD_ERR 2
+
+#define CLOSE_ALL_HANDLES 1
+#define CLOSE_STD_OUT 2
+#define CLOSE_STD_ERR 4
+
+#define DEFAULT_REDIRECTION_SIZE 1024
+#define MAX_SHORTCUT_SIZE 128
+#define STDIN_BUF_SIZE 512
+
+/** Command Macros **/
+
+/** Command Basic Typedefs **/
+
+typedef VOID (*PFNSVC)(VOID);
+
+#pragma pack(1)
+
+typedef struct _PARAMBLOCK {
+ USHORT SegEnv;
+ USHORT OffCmdTail;
+ USHORT SegCmdTail;
+ ULONG pFCB1;
+ ULONG pFCB2;
+} PARAMBLOCK,*PPARAMBLOCK;
+
+typedef struct _SCSINFO {
+ CHAR SCS_ComSpec [64];
+ CHAR SCS_CmdTail [128];
+ PARAMBLOCK SCS_ParamBlock;
+ CHAR SCS_ToSync;
+} SCSINFO, *PSCSINFO;
+
+typedef struct _STD_HANDLES {
+ ULONG hStdErr;
+ ULONG hStdOut;
+ ULONG hStdIn;
+} STD_HANDLES, *PSTD_HANDLES;
+
+#define PIPE_INPUT_BUFFER_SIZE 512
+#define PIPE_OUTPUT_BUFFER_SIZE PIPE_INPUT_BUFFER_SIZE
+#define PIPE_INPUT_TIMEOUT 55
+#define PIPE_OUTPUT_TIMEOUT PIPE_INPUT_TIMEOUT
+
+typedef struct _PIPE_INPUT{
+ struct _PIPE_INPUT *Next;
+ HANDLE hFileRead;
+ HANDLE hFileWrite;
+ HANDLE hPipe;
+ HANDLE hDataEvent;
+ HANDLE hThread;
+ CHAR *pFileName;
+ DWORD BufferSize;
+ BOOL fEOF;
+ BOOL WaitData;
+ BYTE *Buffer;
+ CRITICAL_SECTION CriticalSection;
+} PIPE_INPUT, *PPIPE_INPUT;
+
+typedef struct _PIPE_OUTPUT {
+ HANDLE hFile;
+ HANDLE hPipe;
+ HANDLE hExitEvent;
+ CHAR *pFileName;
+ DWORD BufferSize;
+ BYTE *Buffer;
+} PIPE_OUTPUT, *PPIPE_OUTPUT;
+
+typedef struct _RedirComplete_Info {
+ HANDLE ri_hStdErr;
+ HANDLE ri_hStdOut;
+ HANDLE ri_hStdIn;
+ HANDLE ri_hStdErrFile;
+ HANDLE ri_hStdOutFile;
+ HANDLE ri_hStdInFile;
+ HANDLE ri_hStdOutThread;
+ HANDLE ri_hStdErrThread;
+ PPIPE_INPUT ri_pPipeStdIn;
+ PPIPE_OUTPUT ri_pPipeStdOut;
+ PPIPE_OUTPUT ri_pPipeStdErr;
+
+} REDIRCOMPLETE_INFO, *PREDIRCOMPLETE_INFO;
+
+typedef struct _VDMENVBLK {
+ DWORD cchEnv;
+ DWORD cchRemain;
+ CHAR *lpszzEnv;
+} VDMENVBLK, *PVDMENVBLK;
+
+#pragma pack()
+
+/** Command Function Prototypes */
+
+
+VOID cmdComSpec (VOID);
+VOID cmdGetEnv (VOID);
+VOID cmdGetNextCmd (VOID);
+VOID cmdGetNextCmdForSeparateWow (VOID);
+VOID cmdGetStdHandle (VOID);
+VOID cmdExec (VOID);
+VOID cmdExecComspec32 (VOID);
+VOID cmdExitVDM (VOID);
+VOID cmdReturnExitCode (VOID);
+VOID cmdSaveWorld (VOID);
+VOID cmdSetInfo (VOID);
+VOID cmdGetCurrentDir (VOID);
+VOID cmdSetDirectories (PCHAR,VDMINFO *);
+VOID CheckDotExeForWOW (LPSTR);
+BOOL cmdCheckCopyForRedirection (PREDIRCOMPLETE_INFO);
+BOOL cmdCreateTempFile (PHANDLE,PCHAR *);
+VOID cmdCheckBinary (VOID);
+VOID cmdInitConsole (VOID);
+VOID nt_init_event_thread (VOID);
+VOID cmdExec32 (PCHAR,PCHAR);
+VOID cmdCreateProcess (VOID);
+USHORT cmdMapCodePage (ULONG);
+VOID cmdCheckForPIF (PVDMINFO);
+VOID cmdGetConfigSys (VOID);
+VOID cmdGetAutoexecBat (VOID);
+VOID DeleteConfigFiles (VOID);
+VOID cmdGetKbdLayout (VOID);
+BOOL cmdXformEnvironment (PCHAR, PANSI_STRING);
+VOID cmdGetInitEnvironment (VOID);
+VOID cmdUpdateCurrentDirectories (BYTE);
+BOOL cmdCreateVDMEnvironment (PVDMENVBLK);
+DWORD cmdGetEnvironmentVariable (PVDMENVBLK, PCHAR, PCHAR, DWORD);
+BOOL cmdSetEnvironmentVariable (PVDMENVBLK, PCHAR, PCHAR);
+DWORD cmdExpandEnvironmentStrings (PVDMENVBLK, PCHAR, PCHAR, DWORD);
+PREDIRCOMPLETE_INFO cmdCheckStandardHandles (PVDMINFO,USHORT UNALIGNED *);
+VOID cmdGetStartInfo (VOID);
+BOOL cmdHandleStdinWithPipe (PREDIRCOMPLETE_INFO);
+BOOL cmdHandleStdOutErrWithPipe (PREDIRCOMPLETE_INFO, USHORT);
+LPSTR cmdSkipOverPathName (LPSTR);
+BOOL cmdPipeFileDataEOF (HANDLE, BOOL *);
+BOOL cmdPipeFileEOF (HANDLE);
+VOID cmdPipeInThread (LPVOID);
+VOID cmdPipeOutThread (LPVOID);
+
+/** Command Externs **/
+
+extern USHORT nDrives;
+extern BOOL IsFirstVDMInSystem;
+extern BOOL VDMForWOW;
+extern CHAR lpszComSpec[];
+extern USHORT cbComSpec;
+extern BOOL IsFirstCall;
+extern BOOL IsRepeatCall;
+extern BOOL IsFirstWOWCheckBinary;
+extern BOOL IsFirstVDMInSystem;
+extern BOOL SaveWorldCreated;
+extern PCHAR pSCS_ToSync;
+extern BOOL fBlock;
+extern PCHAR pCommand32;
+extern PCHAR pEnv32;
+extern DWORD dwExitCode32;
+extern PSCSINFO pSCSInfo;
+extern HANDLE hFileStdOut;
+extern HANDLE hFileStdOutDup;
+extern HANDLE hFileStdErr;
+extern HANDLE hFileStdErrDup;
+extern VDMINFO VDMInfo;
+extern PSZ pszFileStdOut;
+extern PSZ pszFileStdErr;
+extern CHAR cmdHomeDirectory[];
+extern HANDLE SCS_hStdIn;
+extern HANDLE SCS_hStdOut;
+extern HANDLE SCS_hStdErr;
+extern CHAR chDefaultDrive;
+extern BOOL DontCheckDosBinaryType;
+extern WORD Exe32ActiveCount;
+extern BOOL fSoftpcRedirection;
+extern BOOL fSoftpcRedirectionOnShellOut;
+extern VOID nt_std_handle_notification (BOOL);
+extern VOID cmdPushExitInConsoleBuffer (VOID);
+
+
+// control handler state, defined in nt_event.h, nt_event.c
+extern ULONG CntrlHandlerState;
+#define CNTRL_SHELLCOUNT 0x0FFFF // The LOWORD is used for shell count
+#define CNTRL_PIFALLOWCLOSE 0x10000
+#define CNTRL_VDMBLOCKED 0x20000
+#define CNTRL_SYSTEMROOTCONSOLE 0x40000
+#define CNTRL_PUSHEXIT 0x80000
+
+
+// Temporary variable till we standardized on wowexec
+extern ULONG iWOWTaskId;
+extern CHAR comspec[];
+extern CHAR ShortCutInfo[];
+
+extern VOID nt_pif_callout (LPVOID);
+extern CHAR *lpszzInitEnvironment;
+extern WORD cchInitEnvironment;
+extern CHAR *lpszzCurrentDirectories;
+extern DWORD cchCurrentDirectories;
+extern BYTE * pIsDosBinary;
+extern WORD * pFDAccess;
+extern CHAR *lpszzcmdEnv16;
+extern BOOL DosEnvCreated;
+extern BOOL IsFirstVDM;
+extern VDMENVBLK cmdVDMEnvBlk;
+extern CHAR *lpszzVDMEnv32;
+extern DWORD cchVDMEnv32;
+extern UINT VdmExitCode;
+
+// application path name extention type.
+#define EXTENTION_STRING_LEN 4
+#define BAT_EXTENTION_STRING ".BAT"
+#define EXE_EXTENTION_STRING ".EXE"
+#define COM_EXTENTION_STRING ".COM"
diff --git a/private/mvdm/dos/command/cmdconf.c b/private/mvdm/dos/command/cmdconf.c
new file mode 100644
index 000000000..0b57d2bf6
--- /dev/null
+++ b/private/mvdm/dos/command/cmdconf.c
@@ -0,0 +1,636 @@
+/* cmdconf.c - handles pre-processing of config.sys\autoexec.bat
+ *
+ * Modification History:
+ *
+ * 21-Nov-1992 Jonle , Created
+ */
+
+#include "cmd.h"
+#include <cmdsvc.h>
+#include <demexp.h>
+#include <softpc.h>
+#include <mvdm.h>
+#include <ctype.h>
+#include <oemuni.h>
+
+//
+// local stuff
+//
+CHAR *pchTmpConfigFile;
+CHAR *pchTmpAutoexecFile;
+CHAR achSYSROOT[] = "%SystemRoot%";
+CHAR achCOMMAND[] = "\\System32\\command.com";
+CHAR achSHELL[] = "shell";
+CHAR achCOUNTRY[] = "country";
+CHAR achREM[] = "rem";
+CHAR achENV[] = "/e:";
+CHAR achEOL[] = "\r\n";
+CHAR achSET[] = "SET";
+CHAR achPROMPT[] = "PROMPT";
+CHAR achPATH[] = "PATH";
+
+DWORD dwLenSysRoot;
+CHAR achSysRoot[64];
+
+
+
+void ExpandConfigFiles(BOOLEAN bConfig);
+DWORD WriteExpanded(HANDLE hFile, CHAR *pch, DWORD dwBytes);
+void WriteFileAssert(HANDLE hFile, CHAR *pBuff, DWORD dwBytes);
+#define ISEOL(ch) ( !(ch) || ((ch) == '\n') || ((ch) == '\r'))
+
+
+
+/** There are still many items we don't supprot for long path name
+ (1). device, install in config.sys
+ (2). Third-party shell
+ (3). lh, loadhigh and any other commands in autoexec.bat
+
+**/
+
+/* cmdGetConfigSys - Creates a temp file to replace c:\config.sys
+ *
+ * Entry - Client (DS:DX) pointer to receive file name
+ *
+ * EXIT - This routine will Terminate the vdm if it fails
+ * And will not return
+ *
+ * The buffer to receive the file name must be at least 64 bytes
+ */
+VOID cmdGetConfigSys (VOID)
+{
+ UNICODE_STRING Unicode;
+ OEM_STRING OemString;
+ ANSI_STRING AnsiString;
+
+ ExpandConfigFiles(TRUE);
+
+ RtlInitAnsiString(&AnsiString, pchTmpConfigFile);
+ if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&Unicode, &AnsiString, TRUE)) )
+ goto ErrExit;
+
+ OemString.Buffer = (char *)GetVDMAddr(getDS(),getDX());
+ OemString.MaximumLength = 64;
+ if ( !NT_SUCCESS(RtlUnicodeStringToOemString(&OemString,&Unicode,FALSE)) )
+ goto ErrExit;
+
+ RtlFreeUnicodeString(&Unicode);
+ return;
+
+ErrExit:
+ RcErrorDialogBox(ED_INITMEMERR, pchTmpConfigFile, NULL);
+ TerminateVDM();
+}
+
+
+
+/* cmdGetAutoexecBat - Creates a temp file to replace c:\autoexec.bat
+ *
+ * Entry - Client (DS:DX) pointer to receive file name
+ *
+ * EXIT - This routine will Terminate the vdm if it fails
+ * And will not return
+ *
+ *
+ * The buffer to receive the file name must be at least 64 bytes
+ */
+VOID cmdGetAutoexecBat (VOID)
+{
+ UNICODE_STRING Unicode;
+ OEM_STRING OemString;
+ ANSI_STRING AnsiString;
+
+ ExpandConfigFiles(FALSE);
+
+ RtlInitAnsiString(&AnsiString, pchTmpAutoexecFile);
+ if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&Unicode,&AnsiString,TRUE)) )
+ goto ErrExit;
+
+ OemString.Buffer = (char *)GetVDMAddr(getDS(),getDX());
+ OemString.MaximumLength = 64;
+ if (!NT_SUCCESS(RtlUnicodeStringToOemString(&OemString,&Unicode,FALSE)) )
+ goto ErrExit;
+
+ RtlFreeUnicodeString(&Unicode);
+
+ return;
+
+ErrExit:
+ RcErrorDialogBox(ED_INITMEMERR, pchTmpConfigFile, NULL);
+ TerminateVDM(); // skip cleanup since I insist that we exit!
+}
+
+
+
+/*
+ * DeleteConfigFiles - Deletes the temporray config files created
+ * by cmdGetAutoexecBat and cmdGetConfigSys
+ */
+VOID DeleteConfigFiles(VOID)
+{
+ if (pchTmpConfigFile) {
+#if DBG
+ if (!(fShowSVCMsg & KEEPBOOTFILES))
+#endif
+ DeleteFile(pchTmpConfigFile);
+
+ free(pchTmpConfigFile);
+ pchTmpConfigFile = NULL;
+ }
+
+ if (pchTmpAutoexecFile) {
+#if DBG
+ if (!(fShowSVCMsg & KEEPBOOTFILES))
+#endif
+ DeleteFile(pchTmpAutoexecFile);
+
+ free(pchTmpAutoexecFile);
+ pchTmpAutoexecFile = NULL;
+ }
+
+ return;
+}
+
+
+
+// if it is a config command
+// returns pointer to character immediatly following the equal sign
+// else
+// returns NULL
+
+PCHAR IsConfigCommand(PCHAR pConfigCommand, int CmdLen, PCHAR pLine)
+{
+ PCHAR pch;
+
+ if (!_strnicmp(pLine, pConfigCommand, CmdLen)) {
+ pch = pLine + CmdLen;
+ while (!isgraph(*pch) && !ISEOL(*pch)) // skip to "="
+ pch++;
+
+ if (*pch++ == '=') {
+ return pch;
+ }
+ }
+
+ return NULL;
+}
+
+
+
+
+
+
+/*
+ * Preprocesses the specfied config file (config.sys\autoexec.bat)
+ * into a temporary file.
+ *
+ * - expands %SystemRoot%
+ * - adds SHELL line for config.sys
+ *
+ * entry: BOOLEAN bConfig : TRUE - config.sys
+ * FALSE - autoexec.bat
+ */
+void ExpandConfigFiles(BOOLEAN bConfig)
+{
+ DWORD dw, dwRawFileSize;
+
+ HANDLE hRawFile;
+ HANDLE hTmpFile;
+ CHAR **ppTmpFile;
+ CHAR *pRawBuffer;
+ CHAR *pLine;
+ CHAR *pTmp;
+ CHAR *pEnvParam= NULL;
+ CHAR *pPartyShell=NULL;
+ CHAR achRawFile[MAX_PATH+12];
+ CHAR *lpszzEnv, *lpszName;
+ CHAR cchEnv;
+
+ dw = GetWindowsDirectory(achRawFile, sizeof(achRawFile));
+ dwLenSysRoot = GetShortPathNameA(achRawFile, achSysRoot, sizeof(achSysRoot));
+ if (dwLenSysRoot >= sizeof(achSysRoot)) {
+ dwLenSysRoot = 0;
+ achSysRoot[0] = '\0';
+ }
+ GetPIFConfigFiles(bConfig, achRawFile);
+ ppTmpFile = bConfig ? &pchTmpConfigFile : &pchTmpAutoexecFile;
+
+ hRawFile = CreateFile(achRawFile,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL );
+
+ if (hRawFile == (HANDLE)0xFFFFFFFF
+ || !dwLenSysRoot
+ || dwLenSysRoot >= sizeof(achSysRoot)
+ || !(dwRawFileSize = GetFileSize(hRawFile, NULL))
+ || dwRawFileSize == 0xFFFFFFFF )
+ {
+ RcErrorDialogBox(ED_BADSYSFILE, achRawFile, NULL);
+ TerminateVDM(); // skip cleanup since I insist that we exit!
+ }
+
+ pRawBuffer = malloc(dwRawFileSize+1);
+ // allocate buffer to save environment settings in autoexec.nt
+ // I know this is bad to allocate this amount of memory at this
+ // moment as we dont know if there are anything we want to keep
+ // at all. This allocation simply provides the following error
+ // handling easily.
+ if(!bConfig) {
+ lpszzEnv = lpszzcmdEnv16 = (PCHAR)malloc(dwRawFileSize);
+ cchEnv = 0;
+ }
+ if (!pRawBuffer || (!bConfig && lpszzcmdEnv16 == NULL)) {
+ RcErrorDialogBox(ED_INITMEMERR, achRawFile, NULL);
+ TerminateVDM(); // skip cleanup since I insist that we exit!
+ }
+
+ if (!cmdCreateTempFile(&hTmpFile,ppTmpFile)
+ || !ReadFile(hRawFile, pRawBuffer, dwRawFileSize, &dw, NULL)
+ || dw != dwRawFileSize )
+ {
+ GetTempPath(MAX_PATH, achRawFile);
+ achRawFile[63] = '\0';
+ RcErrorDialogBox(ED_INITTMPFILE, achRawFile, NULL);
+ TerminateVDM(); // skip cleanup since I insist that we exit!
+ }
+ // CHANGE HERE WHEN YOU CHANGE cmdCreateTempFile !!!!!!!!!!
+ // we depend on the buffer size allocated for the file name
+ dw = GetShortPathNameA(*ppTmpFile, *ppTmpFile, MAX_PATH +13);
+ if (dw == 0 || dw > 63)
+ {
+ GetTempPath(MAX_PATH, achRawFile);
+ achRawFile[63] = '\0';
+ RcErrorDialogBox(ED_INITTMPFILE, achRawFile, NULL);
+ TerminateVDM(); // skip cleanup since I insist that we exit!
+ }
+
+
+ // null terminate the buffer so we can use CRT string functions
+ *(pRawBuffer+dwRawFileSize) = '\0';
+
+ // ensure no trailing backslash in System Directory
+ if (*(achSysRoot+dwLenSysRoot-1) == '\\') {
+ *(achSysRoot + --dwLenSysRoot) = '\0';
+ }
+
+ pLine = pRawBuffer;
+ while (dwRawFileSize) {
+ // skip leading white space
+ while (dwRawFileSize && !isgraph(*pLine)) {
+ pLine++;
+ dwRawFileSize -= sizeof(CHAR);
+ }
+ if (!dwRawFileSize) // anything left to do ?
+ break;
+
+
+ if (bConfig) {
+ //
+ // filter out country= setting we will create our own based
+ // on current country ID and codepage.
+ //
+ pTmp = IsConfigCommand(achCOUNTRY, sizeof(achCOUNTRY) - sizeof(CHAR), pLine);
+ if (pTmp) {
+ while (dwRawFileSize && !ISEOL(*pLine)) {
+ pLine++;
+ dwRawFileSize -= sizeof(CHAR);
+ }
+ continue;
+ }
+
+ // filter out shell= command, saving /E:nn parameter
+ pTmp = IsConfigCommand(achSHELL, sizeof(achSHELL) - sizeof(CHAR),pLine);
+ if (pTmp) {
+ // skip leading white space
+ while (!isgraph(*pTmp) && !ISEOL(*pTmp)) {
+ dwRawFileSize -= sizeof(CHAR);
+ pTmp++;
+ }
+
+ /* if for a third party shell (not SCS command.com)
+ * append the whole thing thru /c parameter
+ * else
+ * append user specifed /e: parameter
+ */
+ if (!_strnicmp(achSYSROOT,pTmp,sizeof(achSYSROOT)-sizeof(CHAR)))
+ {
+ dw = sizeof(achSYSROOT) - sizeof(CHAR);
+ }
+ else if (!_strnicmp(achSysRoot,pTmp, strlen(achSysRoot)))
+ {
+ dw = strlen(achSysRoot);
+ }
+ else {
+ dw = 0;
+ }
+
+ if (!dw ||
+ _strnicmp(achCOMMAND,pTmp+dw,sizeof(achCOMMAND)-sizeof(CHAR)) )
+ {
+ pPartyShell = pTmp;
+ }
+ else {
+ do {
+ while (*pTmp != '/' && !ISEOL(*pTmp)) // save "/e:"
+ pTmp++;
+
+ if(ISEOL(*pTmp))
+ break;
+
+ if (!_strnicmp(pTmp,achENV,sizeof(achENV)-sizeof(CHAR)))
+ pEnvParam = pTmp;
+
+ pTmp++;
+
+ } while(1); // was: while (!ISEOL(*pTmp));
+ // we have break form this loop now,
+ // and don't need in additional macro..
+
+ }
+
+ // skip the "shell=" line
+ while (dwRawFileSize && !ISEOL(*pLine)) {
+ pLine++;
+ dwRawFileSize -= sizeof(CHAR);
+ }
+ continue;
+
+ } // END, really is "shell=" line!
+ }
+
+
+ /** Filter out PROMPT, SET and PATH from autoexec.nt
+ for environment merging. The output we prepare here is
+ a multiple strings buffer which has the format as :
+ "EnvName_1 NULL EnvValue_1 NULL[EnvName_n NULL EnvValue_n NULL] NULL
+ We don't take them out from the file because command.com needs
+ them.
+ **/
+ if (!bConfig)
+ if (!_strnicmp(pLine, achPROMPT, sizeof(achPROMPT) - 1)){
+ // prompt command found.
+ // the syntax of prompt can be eithe
+ // prompt xxyyzz or
+ // prompt=xxyyzz
+ //
+ strcpy(lpszzEnv, achPROMPT); // get the name
+ lpszzEnv += sizeof(achPROMPT);
+ cchEnv += sizeof(achPROMPT);
+ pTmp = pLine + sizeof(achPROMPT) - 1;
+ // skip possible white chars
+ while (!isgraph(*pTmp) && !ISEOL(*pTmp))
+ pTmp++;
+ if (*pTmp == '=') {
+ pTmp++;
+ while(!isgraph(*pTmp) && !ISEOL(*pTmp))
+ pTmp++;
+ }
+ while(!ISEOL(*pTmp)){
+ *lpszzEnv++ = *pTmp++;
+ cchEnv++;
+ }
+ // null terminate this
+ // it may be "prompt NULL NULL" for delete
+ // or "prompt NULL something NULL"
+ *lpszzEnv++ = '\0';
+ cchEnv++;
+ }
+ else if (!_strnicmp(pLine, achPATH, sizeof(achPATH) - 1)) {
+ // PATH was found, it has the same syntax as
+ // PROMPT
+ strcpy(lpszzEnv, achPATH);
+ lpszzEnv += sizeof(achPATH);
+ cchEnv += sizeof(achPATH);
+ pTmp = pLine + sizeof(achPATH) - 1;
+ while (!isgraph(*pTmp) && !ISEOL(*pTmp))
+ pTmp++;
+ if (*pTmp == '=') {
+ pTmp++;
+ while(!isgraph(*pTmp) && !ISEOL(*pTmp))
+ pTmp++;
+ }
+ while(!ISEOL(*pTmp)) {
+ *lpszzEnv++ = *pTmp++;
+ cchEnv++;
+ }
+ *lpszzEnv++ = '\0';
+ cchEnv++;
+ }
+ else if(!_strnicmp(pLine, achSET, sizeof(achSET) -1 )) {
+ // SET was found, first search for name
+ pTmp = pLine + sizeof(achSET) - 1;
+ while(!isgraph(*pTmp) && !ISEOL(*pTmp))
+ *pTmp ++;
+ // get the name
+ lpszName = pTmp;
+ // looking for the '='
+ // note that the name can have white characters
+ while (!ISEOL(*lpszName) && *lpszName != '=')
+ lpszName++;
+ if (!ISEOL(*lpszName)) {
+ // copy the name
+ while (pTmp < lpszName) {
+ *lpszzEnv++ = *pTmp++;
+ cchEnv++;
+ }
+ *lpszzEnv++ = '\0';
+ cchEnv++;
+ // discard the '='
+ pTmp++;
+ // grab the value(may be nothing
+ while (!ISEOL(*pTmp)) {
+ *lpszzEnv++ = *pTmp++;
+ cchEnv++;
+ }
+ *lpszzEnv++ = '\0';
+ cchEnv++;
+ }
+ }
+
+
+ dw = WriteExpanded(hTmpFile, pLine, dwRawFileSize);
+ pLine += dw;
+ dwRawFileSize -=dw;
+
+ WriteFileAssert(hTmpFile,achEOL,sizeof(achEOL) - sizeof(CHAR));
+
+ } // END, while (dwRawFileSize)
+
+
+
+ if (bConfig) {
+ UINT OemCP;
+ UINT CtryId;
+ CHAR szCtryId[64]; // expect "nnn" only
+
+ /* Ensure that the country settings are in sync with NT This is
+ * especially important for DosKrnl file UPCASE tables. The
+ * doskrnl default is "CTRY_UNITED_STATES, 437". But we add the
+ * country= line to config.sys, even if is US,437, so that the DOS
+ * will know where the default country.sys is.
+ */
+ if (GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCOUNTRY,
+ szCtryId, sizeof(szCtryId) - 1) )
+ {
+ CtryId = strtoul(szCtryId,NULL,10);
+ }
+ else {
+ CtryId = CTRY_UNITED_STATES;
+ }
+
+ OemCP = GetOEMCP();
+
+ sprintf(achRawFile,
+ "%s=%3.3u,%3.3u,%s\\system32\\%s.sys%s",
+ achCOUNTRY, CtryId, OemCP, achSysRoot, achCOUNTRY, achEOL);
+ WriteFileAssert(hTmpFile,achRawFile,strlen(achRawFile));
+
+
+
+ /* We cannot allow the user to set an incorrect shell= command
+ * so we will contruct the correct shell= command appending
+ * either (in order of precedence):
+ * 1. /c ThirdPartyShell
+ * 2. /e:NNNN
+ * 3. nothing
+ *
+ * If there is a third party shell then we must turn the console
+ * on now since we no longer have control once system32\command.com
+ * spawns the third party shell.
+ */
+
+ // write shell=....
+ sprintf(achRawFile,
+ "%s=%s%s /p %s\\system32",
+ achSHELL,achSysRoot, achCOMMAND, achSysRoot);
+ WriteFileAssert(hTmpFile,achRawFile,strlen(achRawFile));
+
+ // write extra string (/c ... or /e:nnn)
+ if (pPartyShell && isgraph(*pPartyShell)) {
+ pTmp = pPartyShell;
+ while (!ISEOL(*pTmp))
+ pTmp++;
+ }
+ else if (pEnvParam && isgraph(*pEnvParam)) {
+ pTmp = pEnvParam;
+ while (isgraph(*pTmp))
+ pTmp++;
+ }
+ else {
+ pTmp = NULL;
+ }
+
+ if (pTmp) {
+ *pTmp = '\0';
+ if (pPartyShell) {
+ cmdInitConsole();
+ strcpy(achRawFile, " /c ");
+ strcat(achRawFile, pPartyShell);
+ }
+ else if (pEnvParam) {
+ strcpy(achRawFile, " ");
+ strcat(achRawFile, pEnvParam);
+ }
+
+ WriteExpanded(hTmpFile, achRawFile, strlen(achRawFile));
+ }
+
+ WriteFileAssert(hTmpFile,achEOL,sizeof(achEOL) - sizeof(CHAR));
+ }
+
+ SetEndOfFile(hTmpFile);
+ CloseHandle(hTmpFile);
+ CloseHandle(hRawFile);
+ free(pRawBuffer);
+ if (!bConfig) {
+ // shrink(or free) the memory
+ if (cchEnv && lpszzcmdEnv16) {
+ // doubld null terminate it
+ lpszzcmdEnv16[cchEnv++] = '\0';
+ // shrink the memory. If it fails, simple keep
+ // it as is
+ lpszzEnv = realloc(lpszzcmdEnv16, cchEnv);
+ if (lpszzEnv != NULL)
+ lpszzcmdEnv16 = lpszzEnv;
+ }
+ else {
+ free(lpszzcmdEnv16);
+ lpszzcmdEnv16 = NULL;
+ }
+ }
+
+}
+
+
+
+
+/*
+ * WriteExpanded - writes up to dwChars or EOL, expanding %SystemRoot%
+ * returns number of CHARs processed in buffer
+ * (not number of bytes actually written)
+ */
+DWORD WriteExpanded(HANDLE hFile, CHAR *pch, DWORD dwChars)
+{
+ DWORD dw;
+ DWORD dwSave = dwChars;
+ CHAR *pSave = pch;
+
+
+ while (dwChars && !ISEOL(*pch)) {
+ if (*pch == '%' &&
+ !_strnicmp(pch, achSYSROOT, sizeof(achSYSROOT)-sizeof(CHAR)) )
+ {
+ dw = pch - pSave;
+ if (dw) {
+ WriteFileAssert(hFile, pSave, dw);
+ }
+
+ WriteFileAssert(hFile, achSysRoot, dwLenSysRoot);
+
+ pch += sizeof(achSYSROOT)-sizeof(CHAR);
+ pSave = pch;
+ dwChars -= sizeof(achSYSROOT)-sizeof(CHAR);
+ }
+ else {
+ pch++;
+ dwChars -= sizeof(CHAR);
+ }
+ }
+
+ dw = pch - pSave;
+ if (dw) {
+ WriteFileAssert(hFile, pSave, dw);
+ }
+
+ return (dwSave - dwChars);
+}
+
+
+
+
+/*
+ * WriteFileAssert
+ *
+ * Cecks for error in wrtiting the temp boot file,
+ * If one occurs displays warning popup and terminates the vdm.
+ *
+ */
+void WriteFileAssert(HANDLE hFile, CHAR *pBuff, DWORD dwBytes)
+{
+ DWORD dw;
+ CHAR ach[MAX_PATH];
+
+ if (!WriteFile(hFile, pBuff, dwBytes, &dw, NULL) ||
+ dw != dwBytes)
+ {
+
+ GetTempPath(MAX_PATH, ach);
+ ach[63] = '\0';
+ RcErrorDialogBox(ED_INITTMPFILE, ach, NULL);
+ TerminateVDM(); // skip cleanup since I insist that we exit!
+ }
+}
diff --git a/private/mvdm/dos/command/cmddata.c b/private/mvdm/dos/command/cmddata.c
new file mode 100644
index 000000000..05d35ad44
--- /dev/null
+++ b/private/mvdm/dos/command/cmddata.c
@@ -0,0 +1,51 @@
+/* cmddata.c - Misc. SCS global data
+ *
+ *
+ * Modification History:
+ *
+ * Sudeepb 22-Apr-1992 Created
+ */
+
+#include "cmd.h"
+#include <mvdm.h>
+
+CHAR lpszComSpec[64+8];
+USHORT cbComSpec=0;
+BOOL IsFirstCall = TRUE;
+BOOL IsRepeatCall = FALSE;
+BOOL IsFirstWOWCheckBinary = TRUE;
+BOOL IsFirstVDMInSystem = FALSE;
+BOOL SaveWorldCreated;
+PCHAR pSCS_ToSync;
+PSCSINFO pSCSInfo;
+BOOL fBlock = FALSE;
+PCHAR pCommand32;
+PCHAR pEnv32;
+DWORD dwExitCode32;
+CHAR cmdHomeDirectory [] = "C:\\";
+CHAR chDefaultDrive;
+CHAR comspec[]="COMSPEC=";
+BOOL fSoftpcRedirection;
+BOOL fSoftpcRedirectionOnShellOut;
+CHAR ShortCutInfo[MAX_SHORTCUT_SIZE];
+BOOL DosEnvCreated = FALSE;
+
+BOOL IsFirstVDM = TRUE;
+// FORCEDOS.EXE supported
+BOOL DontCheckDosBinaryType = FALSE;
+WORD Exe32ActiveCount = 0;
+
+
+
+// Redirection Support variables
+
+VDMINFO VDMInfo;
+CHAR *lpszzInitEnvironment = NULL;
+WORD cchInitEnvironment = 0;
+CHAR *lpszzCurrentDirectories = NULL;
+DWORD cchCurrentDirectories = 0;
+BYTE * pIsDosBinary;
+CHAR *lpszzcmdEnv16 = NULL;
+CHAR *lpszzVDMEnv32 = NULL;
+DWORD cchVDMEnv32;
+VDMENVBLK cmdVDMEnvBlk;
diff --git a/private/mvdm/dos/command/cmddisp.c b/private/mvdm/dos/command/cmddisp.c
new file mode 100644
index 000000000..e1b93683f
--- /dev/null
+++ b/private/mvdm/dos/command/cmddisp.c
@@ -0,0 +1,56 @@
+/*
+ * cmddisp.c - SVC dispatch module of command
+ *
+ * Modification History:
+ *
+ * Sudeepb 17-Sep-1991 Created
+ */
+
+#include "cmd.h"
+
+#include <cmdsvc.h>
+#include <softpc.h>
+
+
+PFNSVC apfnSVCCmd [] = {
+ cmdExitVDM, //SVC_CMDEXITVDM
+ cmdGetNextCmd, //SVC_CMDGETNEXTCMD
+ cmdComSpec, //SVC_CMDCOMSPEC
+ cmdSaveWorld, //SVC_CMDSAVEWORLD
+ cmdGetCurrentDir, //SVC_CMDGETCURDIR
+ cmdSetInfo, //SVC_CMDSETINFO
+ cmdGetStdHandle, //SVC_GETSTDHANDLE
+ cmdCheckBinary, //SVC_CMDCHECKBINARY
+ cmdExec, //SVC_CMDEXEC
+ cmdInitConsole, //SVC_CMDINITCONSOLE
+ cmdExecComspec32, //SVC_EXECCOMSPEC32
+ cmdReturnExitCode, //SVC_RETURNEXITCODE
+ cmdGetConfigSys, //SVC_GETCONFIGSYS
+ cmdGetAutoexecBat, //SVC_GETAUTOEXECBAT
+ cmdGetKbdLayout, //SVC_GETKBDLAYOUT
+ cmdGetInitEnvironment, //SVC_GETINITENVIRONMENT
+ cmdGetStartInfo //SVC_GETSTARTINFO
+};
+
+
+/* cmdDispatch - Dispatch SVC call to right command handler.
+ *
+ * Entry - iSvc (SVC byte following SVCop)
+ *
+ * Exit - None
+ *
+ */
+
+BOOL CmdDispatch (ULONG iSvc)
+{
+#if DBG
+ if (iSvc >= SVC_CMDLASTSVC){
+ DbgPrint("Unimplemented SVC index for COMMAND %x\n",iSvc);
+ setCF(1);
+ return FALSE;
+ }
+#endif
+ (apfnSVCCmd [iSvc])();
+
+ return TRUE;
+}
diff --git a/private/mvdm/dos/command/cmdenv.c b/private/mvdm/dos/command/cmdenv.c
new file mode 100644
index 000000000..6bbf509e2
--- /dev/null
+++ b/private/mvdm/dos/command/cmdenv.c
@@ -0,0 +1,696 @@
+
+/* cmdenv.c - Environment supporting functions for command.lib
+ *
+ *
+ * Modification History:
+ *
+ * williamh 13-May-1993 Created
+ */
+
+#include "cmd.h"
+
+#include <cmdsvc.h>
+#include <demexp.h>
+#include <softpc.h>
+#include <mvdm.h>
+#include <ctype.h>
+#include <memory.h>
+#include <oemuni.h>
+
+#define VDM_ENV_INC_SIZE 512
+
+CHAR windir[] = "windir";
+extern BOOL fSeparateWow;
+
+// Transform the given DOS environment to 32bits environment.
+// WARNING!! The environment block we passed to 32bits must be in sort order.
+// Therefore, we call RtlSetEnvironmentVariable to do the work
+// The result string must be in ANSI character set.
+BOOL cmdXformEnvironment(PCHAR pEnv16, PANSI_STRING Env_A)
+{
+ UNICODE_STRING Name_U, Value_U, Temp_U;
+ STRING String;
+ PWCHAR pwch, NewEnv, CurEnv, CurEnvCopy, pTmp;
+ NTSTATUS Status;
+ BOOL fFoundComSpec;
+ USHORT NewEnvLen;
+
+ if (pEnv16 == NULL)
+ return FALSE;
+
+ // flag true if we alread found comspec envirnment
+ // !!!! Do we allow two or more comspec in environment????????
+ fFoundComSpec = FALSE;
+
+ CurEnv = GetEnvironmentStringsW();
+ pwch = CurEnv;
+ // figure how long the environment strings is
+ while (*pwch != UNICODE_NULL || *(pwch + 1) != UNICODE_NULL)
+ pwch++;
+
+ // plus 2 to include the last two NULL chars
+ CurEnvCopy = malloc((pwch - CurEnv + 2) * sizeof(WCHAR));
+ if (!CurEnvCopy)
+ return FALSE;
+
+ // make a copy of current process environment so we can walk through
+ // it. The environment can be changed by any threads in the process
+ // thus is not safe to walk through without a local copy
+ RtlMoveMemory(CurEnvCopy, CurEnv, (pwch - CurEnv + 2) * sizeof(WCHAR));
+
+ // create a new environment block. We don't want to change
+ // any currnt process environment variables, instead, we are
+ // preparing a new one for the new process.
+ Status = RtlCreateEnvironment(FALSE, (PVOID *)&NewEnv);
+ if (!NT_SUCCESS(Status)) {
+ free(CurEnvCopy);
+ return FALSE;
+ }
+ NewEnvLen = 0;
+ // now pick up environment we want from the current environment
+ // and set it to the new environment block
+ // the variables we want:
+ // (1). comspec
+ // (2). current directories settings
+
+ pwch = CurEnvCopy;
+
+ while (*pwch != UNICODE_NULL) {
+ if (*pwch == L'=') {
+ // variable names started with L'=' are current directroy settings
+ pTmp = wcschr(pwch + 1, L'=');
+ if (pTmp) {
+ Name_U.Buffer = pwch;
+ Name_U.Length = (pTmp - pwch) * sizeof(WCHAR);
+ RtlInitUnicodeString(&Value_U, pTmp + 1);
+ Status = RtlSetEnvironmentVariable(&NewEnv, &Name_U, &Value_U);
+ if (!NT_SUCCESS(Status)) {
+ RtlDestroyEnvironment(NewEnv);
+ free(CurEnvCopy);
+ return FALSE;
+ }
+ // <name> + <'='> + <value> + <'\0'>
+ NewEnvLen += Name_U.Length + Value_U.Length + 2 * sizeof(WCHAR);
+ }
+ }
+ else if (!fFoundComSpec) {
+ fFoundComSpec = !_wcsnicmp(pwch, L"COMSPEC=", 8);
+ if (fFoundComSpec) {
+ Name_U.Buffer = pwch;
+ Name_U.Length = 7 * sizeof(WCHAR);
+ RtlInitUnicodeString(&Value_U, pwch + 8);
+ Status = RtlSetEnvironmentVariable(&NewEnv,
+ &Name_U,
+ &Value_U
+ );
+ if (!NT_SUCCESS(Status)) {
+ RtlDestroyEnvironment(NewEnv);
+ free(CurEnvCopy);
+ return FALSE;
+ }
+ NewEnvLen += Name_U.Length + Value_U.Length + 2 * sizeof(WCHAR);
+ }
+ }
+ pwch += wcslen(pwch) + 1;
+ }
+ // we are done with current process environment.
+ free(CurEnvCopy);
+
+ // now deal with 16bits settings passed from dos.
+ // characters in 16bits environment are in OEM character set
+
+ // 16bit comspec environment variable
+ fFoundComSpec = FALSE;
+ while (*pEnv16 != '\0') {
+ RtlInitString(&String, pEnv16);
+ // discard 16bits comspec
+ if (!fFoundComSpec) {
+ fFoundComSpec = !_strnicmp(pEnv16, comspec, 8);
+ if (fFoundComSpec) {
+ // ignore 16bits comspec environment
+ pEnv16 += String.Length + 1;
+ continue;
+ }
+ }
+ Status = RtlOemStringToUnicodeString(&Temp_U, &String, TRUE);
+ if (!NT_SUCCESS(Status)) {
+ RtlDestroyEnvironment(NewEnv);
+ return FALSE;
+ }
+ pwch = wcschr(Temp_U.Buffer, L'=');
+ if (pwch) {
+ Name_U.Buffer = Temp_U.Buffer;
+ Name_U.Length = (pwch - Temp_U.Buffer) * sizeof(WCHAR);
+ RtlInitUnicodeString(&Value_U, pwch + 1);
+ Status = RtlSetEnvironmentVariable( &NewEnv, &Name_U, &Value_U);
+ RtlFreeUnicodeString(&Temp_U);
+ if (!NT_SUCCESS(Status)) {
+ RtlDestroyEnvironment(NewEnv);
+ return FALSE;
+ }
+ NewEnvLen += Name_U.Length + Value_U.Length + 2 * sizeof(WCHAR);
+ }
+ pEnv16 += String.Length + 1;
+ }
+ // count the last terminated null char
+ Temp_U.Length = NewEnvLen + sizeof(WCHAR);
+ Temp_U.Buffer = NewEnv;
+ Status = RtlUnicodeStringToAnsiString(Env_A, &Temp_U, TRUE);
+ RtlDestroyEnvironment(NewEnv); /* don't need it anymore */
+ return(NT_SUCCESS(Status));
+}
+
+
+
+
+/* get ntvdm initial environment. This initial environment is necessary
+ * for the first instance of command.com before it processing autoexec.bat
+ * this function strips off an environment headed with "=" and
+ * replace the comspec with 16bits comspec and upper case all environment vars.
+ *
+ * Entry: Client (ES:0) = buffer to receive the environment
+ * Client (BX) = size in paragraphs of the given buffer
+ *
+ * Exit: (BX) = 0 if nothing to copy
+ * (BX) <= the given size, function okay
+ * (BX) > given size, (BX) has the required size
+ */
+
+VOID cmdGetInitEnvironment(VOID)
+{
+ CHAR *lpszzEnvBuffer, *lpszEnv;
+ WORD cchEnvBuffer;
+ CHAR *lpszzEnvStrings, * lpszz;
+ WORD cchString;
+ WORD cchRemain;
+ WORD cchIncrement = MAX_PATH;
+ BOOL fFoundComSpec = FALSE;
+ BOOL fFoundWindir = FALSE;
+ BOOL fVarIsWindir = FALSE;
+
+ // if not during the initialization return nothing
+ if (!IsFirstCall) {
+ setBX(0);
+ return;
+ }
+ if (cchInitEnvironment == 0) {
+ //
+ // If the PROMPT variable is not set, add it as $P$G. This is to
+ // keep the command.com shell consistent with SCS cmd.exe(which
+ // always does this) when we don't have a top level cmd shell.
+ //
+ {
+ CHAR *pPromptStr = "PROMPT";
+ char ach[2];
+
+ if (!GetEnvironmentVariable(pPromptStr,ach,1)) {
+ SetEnvironmentVariable(pPromptStr, "$P$G");
+ }
+ }
+
+ cchRemain = 0;
+ fFoundComSpec = FALSE;
+ lpszEnv =
+ lpszzEnvStrings = GetEnvironmentStrings();
+ while (*lpszEnv) {
+ cchString = strlen(lpszEnv) + 1;
+ cchVDMEnv32 += cchString;
+ lpszEnv += cchString;
+ }
+ lpszz = lpszzEnvStrings;
+
+ if (lpszzVDMEnv32 != NULL)
+ free(lpszzVDMEnv32);
+ lpszzVDMEnv32 = malloc(++cchVDMEnv32);
+ if (lpszzVDMEnv32 == NULL) {
+ RcMessageBox(EG_MALLOC_FAILURE, NULL, NULL,
+ RMB_ICON_BANG | RMB_ABORT);
+ TerminateVDM();
+ }
+
+ RtlMoveMemory(lpszzVDMEnv32, lpszzEnvStrings, cchVDMEnv32);
+
+ while (*lpszz != '\0') {
+ cchString = strlen(lpszz) + 1;
+ if (*lpszz != '=') {
+
+ if (!fFoundComSpec && !_strnicmp(lpszz, comspec, 8)){
+ fFoundComSpec = TRUE;
+ lpszz += cchString;
+ continue;
+ }
+
+ if (!fFoundWindir && !_strnicmp(lpszz, windir, 6)) {
+ fFoundWindir = TRUE;
+ if (fSeparateWow) {
+ // starting a separate WOW box - flag this one so its
+ // name won't be converted to uppercase later.
+ fVarIsWindir = TRUE;
+ } else {
+ // starting a DOS app, so remove "windir" to make sure
+ // they don't think they are running under Windows.
+ lpszz += cchString;
+ continue;
+ }
+ }
+
+ if (cchRemain < cchString) {
+ if (cchIncrement < cchString)
+ cchIncrement = cchString;
+ lpszzEnvBuffer =
+ (CHAR *)realloc(lpszzInitEnvironment,
+ cchInitEnvironment + cchRemain + cchIncrement
+ );
+ if (lpszzEnvBuffer == NULL) {
+ if (lpszzInitEnvironment != NULL) {
+ free(lpszzInitEnvironment);
+ lpszzInitEnvironment = NULL;
+ }
+ cchInitEnvironment = 0;
+ break;
+ }
+ lpszzInitEnvironment = lpszzEnvBuffer;
+ lpszzEnvBuffer += cchInitEnvironment;
+ cchRemain += cchIncrement;
+ }
+ // the environment strings from base is in ANSI and dos needs OEM
+ AnsiToOemBuff(lpszz, lpszzEnvBuffer, cchString);
+ // convert the name to upper case -- ONLY THE NAME, NOT VALUE.
+ if (!fVarIsWindir && (lpszEnv = strchr(lpszzEnvBuffer, '=')) != NULL){
+ *lpszEnv = '\0';
+ _strupr(lpszzEnvBuffer);
+ *lpszEnv = '=';
+ } else {
+ fVarIsWindir = FALSE;
+ }
+ cchRemain -= cchString;
+ cchInitEnvironment += cchString ;
+ lpszzEnvBuffer += cchString;
+ }
+ lpszz += cchString;
+ }
+ FreeEnvironmentStrings(lpszzEnvStrings);
+
+ lpszzEnvBuffer = (CHAR *) realloc(lpszzInitEnvironment,
+ cchInitEnvironment + 1
+ );
+ if (lpszzInitEnvironment != NULL ) {
+ lpszzInitEnvironment = lpszzEnvBuffer;
+ lpszzInitEnvironment[cchInitEnvironment++] = '\0';
+ }
+ else {
+ if (lpszzInitEnvironment != NULL) {
+ free(lpszzInitEnvironment);
+ lpszzInitEnvironment = NULL;
+ }
+ cchInitEnvironment = 0;
+ }
+ }
+ lpszzEnvBuffer = (CHAR *) GetVDMAddr(getES(), 0);
+ cchEnvBuffer = (WORD)getBX() << 4;
+ if (cchEnvBuffer < cchInitEnvironment + cbComSpec) {
+ setBX((USHORT)((cchInitEnvironment + cbComSpec + 15) >> 4));
+ return;
+ }
+ else {
+ strncpy(lpszzEnvBuffer, lpszComSpec, cbComSpec);
+ lpszzEnvBuffer += cbComSpec;
+ }
+ if (lpszzInitEnvironment != NULL) {
+ setBX((USHORT)((cchInitEnvironment + cbComSpec + 15) >> 4));
+ memcpy(lpszzEnvBuffer, lpszzInitEnvironment, cchInitEnvironment);
+ free(lpszzInitEnvironment);
+ lpszzInitEnvironment = NULL;
+ cchInitEnvironment = 0;
+
+ }
+ else
+ setBX(0);
+
+ return;
+}
+
+
+
+/** create a DOS environment for DOS.
+ This is to get 32bits environment(comes with the dos executanle)
+ and merge it with the environment settings in autoexec.nt so that
+ COMMAND.COM gets the expected environment. We already created a
+ double-null terminated string during autoexec.nt parsing. The string
+ has mutltiple substring:
+ "EnvName_1 NULL EnvValue_1 NULL[EnvName_n NULL EnvValue_n NULL] NULL"
+ When name conflicts happened(a environment name was found in both
+ 16 bits and 32 bits), we do the merging based on the rules:
+ get 16bits value, expands any environment variables in the string
+ by using the current environment.
+
+WARINING !!! The changes made by applications through directly manipulation
+ in command.com environment segment will be lost.
+
+**/
+BOOL cmdCreateVDMEnvironment(
+PVDMENVBLK pVDMEnvBlk
+)
+{
+PCHAR p1, p2;
+BOOL fFoundComSpec;
+BOOL fFoundWindir;
+BOOL fVarIsWindir;
+DWORD Length;
+PCHAR lpszzVDMEnv, lpszzEnv;
+CHAR achBuffer[MAX_PATH + 1];
+
+ pVDMEnvBlk->lpszzEnv = malloc(cchVDMEnv32 + cbComSpec + 1);
+ if ((lpszzVDMEnv = pVDMEnvBlk->lpszzEnv) == NULL)
+ return FALSE;
+
+ pVDMEnvBlk->cchRemain = cchVDMEnv32 + cbComSpec + 1;
+ pVDMEnvBlk->cchEnv = 0;
+
+ // grab the 16bits comspec first
+ if (cbComSpec && lpszComSpec && *lpszComSpec) {
+ RtlCopyMemory(lpszzVDMEnv, lpszComSpec, cbComSpec);
+ pVDMEnvBlk->cchEnv += cbComSpec;
+ pVDMEnvBlk->cchRemain -= cbComSpec;
+ lpszzVDMEnv += cbComSpec;
+ }
+ if (lpszzVDMEnv32) {
+
+ // go through the given 32bits environmnet and take what we want:
+ // everything except:
+ // (1). variable name begin with '='
+ // (2). compsec
+ // (3). string without a '=' -- malformatted environment variable
+ // (4). windir, so DOS apps don't think they're running under Windows
+ // Note that strings pointed by lpszzVDMEnv32 are in ANSI character set
+
+
+ fFoundComSpec = FALSE;
+ fFoundWindir = FALSE;
+ fVarIsWindir = FALSE;
+ lpszzEnv = lpszzVDMEnv32;
+
+ while (*lpszzEnv) {
+ Length = strlen(lpszzEnv) + 1;
+ if (*lpszzEnv != '=' &&
+ (p1 = strchr(lpszzEnv, '=')) != NULL &&
+ (fFoundComSpec || !(fFoundComSpec = _strnicmp(lpszzEnv,
+ comspec,
+ 8
+ ) == 0)) ){
+ if (!fFoundWindir) {
+ fFoundWindir = (_strnicmp(lpszzEnv,
+ windir,
+ 6) == 0);
+ fVarIsWindir = fFoundWindir;
+ }
+ if (!fVarIsWindir || fSeparateWow) {
+ if (Length >= pVDMEnvBlk->cchRemain) {
+ lpszzVDMEnv = realloc(pVDMEnvBlk->lpszzEnv,
+ pVDMEnvBlk->cchEnv +
+ pVDMEnvBlk->cchRemain +
+ VDM_ENV_INC_SIZE
+ );
+ if (lpszzVDMEnv == NULL){
+ free(pVDMEnvBlk->lpszzEnv);
+ return FALSE;
+ }
+ pVDMEnvBlk->cchRemain += VDM_ENV_INC_SIZE;
+ pVDMEnvBlk->lpszzEnv = lpszzVDMEnv;
+ lpszzVDMEnv += pVDMEnvBlk->cchEnv;
+ }
+ AnsiToOemBuff(lpszzEnv, lpszzVDMEnv, Length);
+ if (!fVarIsWindir) {
+ *(lpszzVDMEnv + (DWORD)(p1 - lpszzEnv)) = '\0';
+ _strupr(lpszzVDMEnv);
+ *(lpszzVDMEnv + (DWORD)(p1 - lpszzEnv)) = '=';
+ } else {
+ fVarIsWindir = FALSE;
+ }
+ pVDMEnvBlk->cchEnv += Length;
+ pVDMEnvBlk->cchRemain -= Length;
+ lpszzVDMEnv += Length;
+ }
+ else
+ fVarIsWindir = FALSE;
+ }
+ lpszzEnv += Length;
+ }
+ }
+ *lpszzVDMEnv = '\0';
+ pVDMEnvBlk->cchEnv++;
+ pVDMEnvBlk->cchRemain--;
+
+ if (lpszzcmdEnv16 != NULL) {
+ lpszzEnv = lpszzcmdEnv16;
+
+ while (*lpszzEnv) {
+ p1 = lpszzEnv + strlen(lpszzEnv) + 1;
+ p2 = NULL;
+ if (*p1) {
+ p2 = achBuffer;
+ // expand the strings pointed by p1
+ Length = cmdExpandEnvironmentStrings(pVDMEnvBlk,
+ p1,
+ p2,
+ MAX_PATH + 1
+ );
+ if (Length && Length > MAX_PATH) {
+ p2 = (PCHAR) malloc(Length);
+ if (p2 == NULL) {
+ free(pVDMEnvBlk->lpszzEnv);
+ return FALSE;
+ }
+ cmdExpandEnvironmentStrings(pVDMEnvBlk,
+ p1,
+ p2,
+ Length
+ );
+ }
+ }
+ if (!cmdSetEnvironmentVariable(pVDMEnvBlk,
+ lpszzEnv,
+ p2
+ )){
+ if (p2 && p2 != achBuffer)
+ free(p2);
+ free(pVDMEnvBlk->lpszzEnv);
+ return FALSE;
+ }
+ lpszzEnv = p1 + strlen(p1) + 1;
+ }
+ }
+ lpszzVDMEnv = realloc(pVDMEnvBlk->lpszzEnv, pVDMEnvBlk->cchEnv);
+ if (lpszzVDMEnv != NULL) {
+ pVDMEnvBlk->lpszzEnv = lpszzVDMEnv;
+ pVDMEnvBlk->cchRemain = 0;
+ }
+ return TRUE;
+}
+
+
+BOOL cmdSetEnvironmentVariable(
+PVDMENVBLK pVDMEnvBlk,
+PCHAR lpszName,
+PCHAR lpszValue
+)
+{
+ PCHAR p, p1, pEnd;
+ DWORD ExtraLength, Length, cchValue, cchOldValue;
+
+ pVDMEnvBlk = (pVDMEnvBlk) ? pVDMEnvBlk : &cmdVDMEnvBlk;
+
+ if (pVDMEnvBlk == NULL || lpszName == NULL)
+ return FALSE;
+ if (!(p = pVDMEnvBlk->lpszzEnv))
+ return FALSE;
+ pEnd = p + pVDMEnvBlk->cchEnv - 1;
+
+ cchValue = (lpszValue) ? strlen(lpszValue) : 0;
+
+ Length = strlen(lpszName);
+ while (*p && ((p1 = strchr(p, '=')) == NULL ||
+ (DWORD)(p1 - p) != Length ||
+ _strnicmp(p, lpszName, Length)))
+ p += strlen(p) + 1;
+
+ if (*p) {
+ // name was found in the base environment, replace it
+ p1++;
+ cchOldValue = strlen(p1);
+ if (cchValue <= cchOldValue) {
+ if (!cchValue) {
+ RtlMoveMemory(p,
+ p1 + cchOldValue + 1,
+ (DWORD)(pEnd - p) - cchOldValue
+ );
+ pVDMEnvBlk->cchRemain += Length + cchOldValue + 2;
+ pVDMEnvBlk->cchEnv -= Length + cchOldValue + 2;
+ }
+ else {
+ RtlCopyMemory(p1,
+ lpszValue,
+ cchValue
+ );
+ if (cchValue != cchOldValue) {
+ RtlMoveMemory(p1 + cchValue,
+ p1 + cchOldValue,
+ (DWORD)(pEnd - p1) - cchOldValue + 1
+ );
+ pVDMEnvBlk->cchEnv -= cchOldValue - cchValue;
+ pVDMEnvBlk->cchRemain += cchOldValue - cchValue;
+ }
+ }
+ return TRUE;
+ }
+ else {
+ // need more space for the new value
+ // we delete it from here and fall through
+ RtlMoveMemory(p,
+ p1 + cchOldValue + 1,
+ (DWORD)(pEnd - p1) - cchOldValue
+ );
+ pVDMEnvBlk->cchRemain += Length + 1 + cchOldValue + 1;
+ pVDMEnvBlk->cchEnv -= Length + 1 + cchOldValue + 1;
+ }
+ }
+ if (cchValue) {
+ ExtraLength = Length + 1 + cchValue + 1;
+ if (pVDMEnvBlk->cchRemain < ExtraLength) {
+ p = realloc(pVDMEnvBlk->lpszzEnv,
+ pVDMEnvBlk->cchEnv + pVDMEnvBlk->cchRemain + ExtraLength
+ );
+ if (p == NULL)
+ return FALSE;
+ pVDMEnvBlk->lpszzEnv = p;
+ pVDMEnvBlk->cchRemain += ExtraLength;
+ }
+ p = pVDMEnvBlk->lpszzEnv + pVDMEnvBlk->cchEnv - 1;
+ RtlCopyMemory(p, lpszName, Length + 1);
+ _strupr(p);
+ p += Length;
+ *p++ = '=';
+ RtlCopyMemory(p, lpszValue, cchValue + 1);
+ *(p + cchValue + 1) = '\0';
+ pVDMEnvBlk->cchEnv += ExtraLength;
+ pVDMEnvBlk->cchRemain -= ExtraLength;
+ return TRUE;
+ }
+ return FALSE;
+
+}
+
+
+DWORD cmdExpandEnvironmentStrings(
+PVDMENVBLK pVDMEnvBlk,
+PCHAR lpszSrc,
+PCHAR lpszDst,
+DWORD cchDst
+)
+{
+
+
+ DWORD RequiredLength, RemainLength, Length;
+ PCHAR p1;
+
+ RequiredLength = 0;
+ RemainLength = (lpszDst) ? cchDst : 0;
+ pVDMEnvBlk = (pVDMEnvBlk) ? pVDMEnvBlk : &cmdVDMEnvBlk;
+ if (pVDMEnvBlk == NULL || lpszSrc == NULL)
+ return 0;
+
+ while(*lpszSrc) {
+ if (*lpszSrc == '%') {
+ p1 = strchr(lpszSrc + 1, '%');
+ if (p1 != NULL) {
+ if (p1 == lpszSrc + 1) { // a "%%"
+ lpszSrc += 2;
+ continue;
+ }
+ *p1 = '\0';
+ Length = cmdGetEnvironmentVariable(pVDMEnvBlk,
+ lpszSrc + 1,
+ lpszDst,
+ RemainLength
+ );
+ *p1 = '%';
+ lpszSrc = p1 + 1;
+ if (Length) {
+ if (Length < RemainLength) {
+ RemainLength -= Length;
+ lpszDst += Length;
+ }
+ else {
+ RemainLength = 0;
+ Length --;
+ }
+ RequiredLength += Length;
+ }
+ continue;
+ }
+ else {
+ RequiredLength++;
+ if (RemainLength) {
+ *lpszDst++ = *lpszSrc;
+ RemainLength--;
+ }
+ lpszSrc++;
+ continue;
+ }
+ }
+ else {
+ RequiredLength++;
+ if (RemainLength) {
+ *lpszDst++ = *lpszSrc;
+ RemainLength--;
+ }
+ lpszSrc++;
+ }
+ } // while(*lpszSrc)
+ RequiredLength++;
+ if (RemainLength)
+ *lpszDst = '\0';
+ return RequiredLength;
+}
+
+
+DWORD cmdGetEnvironmentVariable(
+PVDMENVBLK pVDMEnvBlk,
+PCHAR lpszName,
+PCHAR lpszValue,
+DWORD cchValue
+)
+{
+
+ DWORD RequiredLength, Length;
+ PCHAR p, p1;
+
+ pVDMEnvBlk = (pVDMEnvBlk) ? pVDMEnvBlk : &cmdVDMEnvBlk;
+ if (pVDMEnvBlk == NULL || lpszName == NULL)
+ return 0;
+
+ RequiredLength = 0;
+ Length = strlen(lpszName);
+
+ // if the name is "windir", get its value from ntvdm process's environment
+ // for DOS because we took it out of the environment block the application
+ // will see.
+ if (Length == 6 && !fSeparateWow && !_strnicmp(lpszName, windir, 6)) {
+ return(GetEnvironmentVariableOem(lpszName, lpszValue, cchValue));
+ }
+
+ if (p = pVDMEnvBlk->lpszzEnv) {
+ while (*p && ((p1 = strchr(p, '=')) == NULL ||
+ (DWORD)(p1 - p) != Length ||
+ _strnicmp(lpszName, p, Length)))
+ p += strlen(p) + 1;
+ if (*p) {
+ RequiredLength = strlen(p1 + 1);
+ if (cchValue > RequiredLength && lpszValue)
+ RtlCopyMemory(lpszValue, p1 + 1, RequiredLength + 1);
+ else
+ RequiredLength++;
+ }
+ }
+ return RequiredLength;
+}
diff --git a/private/mvdm/dos/command/cmdexec.c b/private/mvdm/dos/command/cmdexec.c
new file mode 100644
index 000000000..61af4c591
--- /dev/null
+++ b/private/mvdm/dos/command/cmdexec.c
@@ -0,0 +1,650 @@
+/* cmdexec.c - Misc SCS routines for non-dos exec and re-entering
+ * the DOS.
+ *
+ *
+ * Modification History:
+ *
+ * Sudeepb 22-Apr-1992 Created
+ */
+
+#include "cmd.h"
+
+#include <cmdsvc.h>
+#include <softpc.h>
+#include <mvdm.h>
+#include <ctype.h>
+#include <oemuni.h>
+#include <wowcmpat.h>
+
+//*****************************************************************************
+// IsWowAppRunnable
+//
+// Returns FALSE if the WOW-specific compatibility flags for the specified
+// task include the bit WOWCF_NOTDOSSPAWNABLE. This is done mostly for
+// "dual mode" executables, e.g., Windows apps that have a real program
+// as a DOS stub. Certain apps that are started via a DOS command shell,
+// for example PWB, really do expect to be started as a DOS app, not a WOW
+// app. For these apps, the compatibility bit should be set in the
+// registry.
+//
+//*****************************************************************************
+
+BOOL IsWowAppRunnable(LPSTR lpAppName)
+{
+ BOOL Result = TRUE;
+ LONG lError;
+ HKEY hKey = 0;
+ char szModName[9];
+ char szHexAsciiFlags[12];
+ DWORD dwType = REG_SZ;
+ DWORD cbData = sizeof(szHexAsciiFlags);
+ ULONG ul = 0;
+ LPSTR pStrt, pEnd;
+ SHORT len;
+
+ lError = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
+ "Software\\Microsoft\\Windows NT\\CurrentVersion\\WOW\\Compatibility",
+ 0,
+ KEY_QUERY_VALUE,
+ &hKey
+ );
+
+ if (ERROR_SUCCESS != lError) {
+ goto Cleanup;
+ }
+
+ //
+ // The following code strips the file name (<9 chars) out of a dos
+ // path name.
+ //
+
+ pStrt = strrchr (lpAppName, '\\');
+
+ if (pStrt==NULL)
+ pStrt = lpAppName;
+ else
+ pStrt++;
+
+ if ( (pEnd = strchr (pStrt, '.')) == NULL)
+ strncpy (szModName, pStrt, 9);
+
+ else {
+ len = (SHORT) (pEnd - pStrt);
+ if (len>8) goto Cleanup;
+ strncpy (szModName, pStrt, len);
+ szModName[len] = '\0';
+ }
+
+
+ //
+ // Look for the file name in the registry
+ //
+
+ lError = RegQueryValueEx( hKey,
+ szModName,
+ 0,
+ &dwType,
+ szHexAsciiFlags,
+ &cbData
+ );
+
+ if (ERROR_SUCCESS != lError) {
+ goto Cleanup;
+ }
+
+ if (REG_SZ != dwType) {
+ goto Cleanup;
+ }
+
+ //
+ // Force the string to lowercase for the convenience of sscanf.
+ //
+
+ _strlwr(szHexAsciiFlags);
+
+ //
+ // sscanf() returns the number of fields converted.
+ //
+
+ if (1 != sscanf(szHexAsciiFlags, "0x%lx", &ul)) {
+ goto Cleanup;
+ }
+
+ if ((ul & WOWCF_NOTDOSSPAWNABLE) != 0)
+ Result = FALSE;
+
+Cleanup:
+ if (hKey) {
+ RegCloseKey(hKey);
+ }
+
+ return Result;
+}
+
+/* cmdCheckBinary - check that the supplied binary name is a 32bit binary
+ *
+ *
+ * Entry - Client (DS:DX) - pointer to pathname for the executable to be tested
+ * Client (ES:BX) - pointer to parameter block
+ *
+ * EXIT - SUCCESS Client (CY) clear
+ * FAILURE Client (CY) set
+ * Client (AX) - error_not_enough_memory if command tail
+ * cannot accomodate /z
+ * - error_file_not_found if patname not found
+ */
+
+VOID cmdCheckBinary (VOID)
+{
+
+ LPSTR lpAppName;
+ ULONG BinaryType;
+ PPARAMBLOCK lpParamBlock;
+ PCHAR lpCommandTail,lpTemp;
+ ULONG AppNameLen,CommandTailLen = 0;
+ USHORT CommandTailOff,CommandTailSeg,usTemp;
+ NTSTATUS Status;
+ UNICODE_STRING Unicode;
+ OEM_STRING OemString;
+ ANSI_STRING AnsiString;
+
+
+ if(DontCheckDosBinaryType){
+ setCF(0);
+ return; // DOS Exe
+ }
+
+ lpAppName = (LPSTR) GetVDMAddr (getDS(),getDX());
+
+ Unicode.Buffer = NULL;
+ AnsiString.Buffer = NULL;
+ RtlInitString((PSTRING)&OemString, lpAppName);
+ Status = RtlOemStringToUnicodeString(&Unicode,&OemString,TRUE);
+ if ( NT_SUCCESS(Status) ) {
+ Status = RtlUnicodeStringToAnsiString(&AnsiString, &Unicode, TRUE);
+ }
+ if ( !NT_SUCCESS(Status) ) {
+ Status = RtlNtStatusToDosError(Status);
+ }
+ else if (GetBinaryType (AnsiString.Buffer,(LPLONG)&BinaryType) == FALSE)
+ {
+ Status = GetLastError();
+ }
+
+ if (Unicode.Buffer != NULL) {
+ RtlFreeUnicodeString( &Unicode );
+ }
+ if (AnsiString.Buffer != NULL) {
+ RtlFreeAnsiString( &AnsiString);
+ }
+
+ if (Status){
+ setCF(1);
+ setAX((USHORT)Status);
+ return; // Invalid path
+ }
+
+
+ if (BinaryType == SCS_DOS_BINARY) {
+ setCF(0);
+ return; // DOS Exe
+ }
+ // Prevent certain WOW apps from being spawned by DOS exe's
+ // This is for win31 compatibility
+ else if (BinaryType == SCS_WOW_BINARY) {
+ if (!IsWowAppRunnable(lpAppName)) {
+ setCF(0);
+ return; // Run as DOS Exe
+ }
+ }
+
+
+ if (VDMForWOW && BinaryType == SCS_WOW_BINARY && IsFirstWOWCheckBinary) {
+ IsFirstWOWCheckBinary = FALSE;
+ setCF(0);
+ return; // Special Hack for krnl286.exe
+ }
+
+ // dont allow running 32bit binaries from autoexec.nt. Reason is that
+ // running non-dos binary requires that we should have read the actual
+ // command from GetNextVDMCommand. Otherwise the whole design gets into
+ // synchronization problems.
+
+ if (IsFirstCall) {
+ setCF(1);
+ setAX((USHORT)ERROR_FILE_NOT_FOUND);
+ return;
+ }
+
+ // Its a 32bit exe, replace the command with "command.com /z" and add the
+ // original binary name to command tail.
+
+ AppNameLen = strlen (lpAppName);
+
+ lpParamBlock = (PPARAMBLOCK) GetVDMAddr (getES(),getBX());
+
+ if (lpParamBlock) {
+ CommandTailOff = FETCHWORD(lpParamBlock->OffCmdTail);
+ CommandTailSeg = FETCHWORD(lpParamBlock->SegCmdTail);
+
+ lpCommandTail = (PCHAR) GetVDMAddr (CommandTailSeg,CommandTailOff);
+
+ if (lpCommandTail){
+ CommandTailLen = *(PCHAR)lpCommandTail;
+ lpCommandTail++; // point to the actual command tail
+ if (CommandTailLen)
+ CommandTailLen++; // For CR
+ }
+
+ // We are adding 3 below for "/z<space>" and anothre space between
+ // AppName and CommandTail.
+
+ if ((3 + AppNameLen + CommandTailLen ) > 128){
+ setCF(1);
+ setAX((USHORT)ERROR_NOT_ENOUGH_MEMORY);
+ return;
+ }
+ }
+
+ // copy the stub command.com name
+ strcpy ((PCHAR)&pSCSInfo->SCS_ComSpec,lpszComSpec+8);
+ lpTemp = (PCHAR) &pSCSInfo->SCS_ComSpec;
+ lpTemp = (PCHAR)((ULONG)lpTemp - (ULONG)GetVDMAddr(0,0));
+ usTemp = (USHORT)((ULONG)lpTemp >> 4);
+ setDS(usTemp);
+ usTemp = (USHORT)((ULONG)lpTemp & 0x0f);
+ setDX((usTemp));
+
+ // Form the command tail, first "3" is for "/z "
+ pSCSInfo->SCS_CmdTail [0] = (UCHAR)(3 +
+ AppNameLen +
+ CommandTailLen);
+ RtlCopyMemory ((PCHAR)&pSCSInfo->SCS_CmdTail[1],"/z ",3);
+ strcpy ((PCHAR)&pSCSInfo->SCS_CmdTail[4],lpAppName);
+ if (CommandTailLen) {
+ pSCSInfo->SCS_CmdTail[4+AppNameLen] = ' ';
+ RtlCopyMemory ((PCHAR)((ULONG)&pSCSInfo->SCS_CmdTail[4]+AppNameLen+1),
+ lpCommandTail,
+ CommandTailLen);
+ }
+ else {
+ pSCSInfo->SCS_CmdTail[4+AppNameLen] = 0xd;
+ }
+
+ // Set the parameter Block
+ if (lpParamBlock) {
+ STOREWORD(pSCSInfo->SCS_ParamBlock.SegEnv,lpParamBlock->SegEnv);
+ STOREDWORD(pSCSInfo->SCS_ParamBlock.pFCB1,lpParamBlock->pFCB1);
+ STOREDWORD(pSCSInfo->SCS_ParamBlock.pFCB2,lpParamBlock->pFCB2);
+ }
+ else {
+ STOREWORD(pSCSInfo->SCS_ParamBlock.SegEnv,0);
+ STOREDWORD(pSCSInfo->SCS_ParamBlock.pFCB1,0);
+ STOREDWORD(pSCSInfo->SCS_ParamBlock.pFCB2,0);
+ }
+
+ lpTemp = (PCHAR) &pSCSInfo->SCS_CmdTail;
+ lpTemp = (PCHAR)((ULONG)lpTemp - (ULONG)GetVDMAddr(0,0));
+ usTemp = (USHORT)((ULONG)lpTemp & 0x0f);
+ STOREWORD(pSCSInfo->SCS_ParamBlock.OffCmdTail,usTemp);
+ usTemp = (USHORT)((ULONG)lpTemp >> 4);
+ STOREWORD(pSCSInfo->SCS_ParamBlock.SegCmdTail,usTemp);
+
+ lpTemp = (PCHAR) &pSCSInfo->SCS_ParamBlock;
+ lpTemp = (PCHAR)((ULONG)lpTemp - (ULONG)GetVDMAddr(0,0));
+ usTemp = (USHORT)((ULONG)lpTemp >> 4);
+ setES (usTemp);
+ usTemp = (USHORT)((ULONG)lpTemp & 0x0f);
+ setBX (usTemp);
+
+ setCF(0);
+ return;
+}
+
+#define MAX_DIR 68
+
+VOID cmdCreateProcess ( VOID )
+{
+
+ VDMINFO VDMInfoForCount;
+ STARTUPINFO StartupInfo;
+ PROCESS_INFORMATION ProcessInformation;
+ HANDLE hStd16In,hStd16Out,hStd16Err;
+ CHAR CurDirVar [] = "=?:";
+ CHAR Buffer [MAX_DIR];
+ CHAR *CurDir = Buffer;
+ DWORD dwRet;
+ BOOL Status;
+ NTSTATUS NtStatus;
+ UNICODE_STRING Unicode;
+ OEM_STRING OemString;
+ LPVOID lpNewEnv=NULL;
+ PSTD_HANDLES pStdHandles;
+ ANSI_STRING Env_A;
+
+ // we have one more 32 executable active
+ Exe32ActiveCount++;
+
+ // Increment the Re-enterancy count for the VDM
+ VDMInfoForCount.VDMState = INCREMENT_REENTER_COUNT;
+ GetNextVDMCommand (&VDMInfoForCount);
+
+ RtlZeroMemory((PVOID)&StartupInfo,sizeof(STARTUPINFO));
+ StartupInfo.cb = sizeof(STARTUPINFO);
+
+ CurDirVar [1] = chDefaultDrive;
+
+ dwRet = GetEnvironmentVariable (CurDirVar,Buffer,MAX_DIR);
+
+ if (dwRet == 0 || dwRet == MAX_DIR)
+ CurDir = NULL;
+
+ pStdHandles = (PSTD_HANDLES) GetVDMAddr (getSS(), getBP());
+ if ((hStd16In = (HANDLE) FETCHDWORD(pStdHandles->hStdIn)) != (HANDLE)-1)
+ SetStdHandle (STD_INPUT_HANDLE, hStd16In);
+
+ if ((hStd16Out = (HANDLE) FETCHDWORD(pStdHandles->hStdOut)) != (HANDLE)-1)
+ SetStdHandle (STD_OUTPUT_HANDLE, hStd16Out);
+
+ if ((hStd16Err = (HANDLE) FETCHDWORD(pStdHandles->hStdErr)) != (HANDLE)-1)
+ SetStdHandle (STD_ERROR_HANDLE, hStd16Err);
+
+ /*
+ * Warning, pEnv32 currently points to an ansi environment.
+ * The DOS is using an ANSI env which isn't quite correct.
+ * If the DOS is changed to use an OEM env then we will
+ * have to convert the env back to ansi before spawning
+ * non-dos exes ?!?
+ * 16-Jan-1993 Jonle
+ */
+
+ Env_A.Buffer = NULL;
+
+ RtlInitString((PSTRING)&OemString, pCommand32);
+ NtStatus = RtlOemStringToUnicodeString(&Unicode,&OemString,TRUE);
+ if (NT_SUCCESS(NtStatus)) {
+ NtStatus = RtlUnicodeStringToAnsiString((PANSI_STRING)&OemString, &Unicode, FALSE);
+ RtlFreeUnicodeString( &Unicode );
+ }
+ if (!NT_SUCCESS(NtStatus)) {
+ SetLastError(RtlNtStatusToDosError(NtStatus));
+ Status = FALSE;
+ }
+ else {
+ if (pEnv32 != NULL && !cmdXformEnvironment (pEnv32, &Env_A)) {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ Status = FALSE;
+ }
+ else {
+
+ Status = CreateProcess (
+ NULL,
+ (LPTSTR)pCommand32,
+ NULL,
+ NULL,
+ TRUE,
+ CREATE_SUSPENDED | CREATE_DEFAULT_ERROR_MODE,
+ Env_A.Buffer,
+ (LPTSTR)CurDir,
+ &StartupInfo,
+ &ProcessInformation);
+ }
+ }
+
+ if (Status == FALSE)
+ dwExitCode32 = GetLastError ();
+
+ if (hStd16In != (HANDLE)-1)
+ SetStdHandle (STD_INPUT_HANDLE, SCS_hStdIn);
+
+ if (hStd16Out != (HANDLE)-1)
+ SetStdHandle (STD_OUTPUT_HANDLE, SCS_hStdOut);
+
+ if (hStd16Err != (HANDLE)-1)
+ SetStdHandle (STD_ERROR_HANDLE, SCS_hStdErr);
+
+ if (Status) {
+ ResumeThread (ProcessInformation.hThread);
+ WaitForSingleObject(ProcessInformation.hProcess, (DWORD)-1);
+ GetExitCodeProcess (ProcessInformation.hProcess, &dwExitCode32);
+ CloseHandle (ProcessInformation.hProcess);
+ CloseHandle (ProcessInformation.hThread);
+ }
+
+ if (Env_A.Buffer)
+ RtlFreeAnsiString(&Env_A);
+
+ // Decrement the Re-enterancy count for the VDM
+ VDMInfoForCount.VDMState = DECREMENT_REENTER_COUNT;
+ GetNextVDMCommand (&VDMInfoForCount);
+
+ // one less 32 executable active
+ Exe32ActiveCount--;
+
+ // Kill this thread
+ ExitThread (0);
+}
+
+
+VOID cmdExec32 (PCHAR pCmd32, PCHAR pEnv)
+{
+
+ DWORD dwThreadId;
+ HANDLE hThread;
+
+ pCommand32 = pCmd32;
+ pEnv32 = pEnv;
+
+ CntrlHandlerState = (CntrlHandlerState & ~CNTRL_SHELLCOUNT) |
+ (((WORD)(CntrlHandlerState & CNTRL_SHELLCOUNT))+1);
+
+ nt_block_event_thread(0);
+ fSoftpcRedirectionOnShellOut = fSoftpcRedirection;
+ fBlock = TRUE;
+
+ if((hThread = CreateThread (NULL,
+ 0,
+ (LPTHREAD_START_ROUTINE)cmdCreateProcess,
+ NULL,
+ 0,
+ &dwThreadId)) == FALSE) {
+ setCF(0);
+ setAL((UCHAR)GetLastError());
+ nt_resume_event_thread();
+ nt_std_handle_notification(fSoftpcRedirectionOnShellOut);
+ fBlock = FALSE;
+ CntrlHandlerState = (CntrlHandlerState & ~CNTRL_SHELLCOUNT) |
+ (((WORD)(CntrlHandlerState & CNTRL_SHELLCOUNT))-1);
+ return;
+ }
+ else
+ CloseHandle (hThread);
+
+ // Wait for next command to be re-entered
+ VDMInfo.VDMState = NO_PARENT_TO_WAKE | RETURN_ON_NO_COMMAND;
+ VDMInfo.EnviornmentSize = 0;
+ VDMInfo.ErrorCode = 0;
+ VDMInfo.CmdSize = 0;
+ VDMInfo.TitleLen = 0;
+ VDMInfo.ReservedLen = 0;
+ VDMInfo.DesktopLen = 0;
+ VDMInfo.CurDirectoryLen = 0;
+ GetNextVDMCommand (&VDMInfo);
+ if (VDMInfo.CmdSize > 0){
+ setCF(1);
+ IsRepeatCall = TRUE;
+ }
+ else {
+ setCF(0);
+ setAL((UCHAR)dwExitCode32);
+ nt_resume_event_thread();
+ nt_std_handle_notification(fSoftpcRedirectionOnShellOut);
+ fBlock = FALSE;
+ }
+
+
+ CntrlHandlerState = (CntrlHandlerState & ~CNTRL_SHELLCOUNT) |
+ (((WORD)(CntrlHandlerState & CNTRL_SHELLCOUNT))-1);
+ return;
+}
+
+/* cmdExecComspec32 - Exec 32bit COMSPEC
+ *
+ *
+ * Entry - Client (ES) - environment segment
+ * Client (AL) - default drive
+ *
+ * EXIT - SUCCESS Client (CY) Clear - AL has return error code
+ * FAILURE Client (CY) set - means DOS is being re-entered
+ */
+
+VOID cmdExecComspec32 (VOID)
+{
+
+ CHAR Buffer[MAX_PATH];
+ DWORD dwRet;
+ PCHAR pEnv;
+
+ dwRet = GetEnvironmentVariable ("COMSPEC",Buffer,MAX_PATH);
+
+ if (dwRet == 0 || dwRet >= MAX_PATH){
+ setCF(0);
+ setAL((UCHAR)ERROR_BAD_ENVIRONMENT);
+ return;
+ }
+
+ pEnv = (PCHAR) GetVDMAddr ((USHORT)getES(),0);
+
+ chDefaultDrive = (CHAR)(getAL() + 'A');
+
+ cmdExec32 (Buffer,pEnv);
+
+ return;
+}
+
+/* cmdExec - Exec a non-dos binary
+ *
+ *
+ * Entry - Client (DS:SI) - command to execute
+ * Client (AL) - default drive
+ * Client (ES) - environment segment
+ * Client (SS:BP) - Pointer to STD_HANDLES
+ * Client (AH) - if 1 means do "cmd /c command" else "command"
+ *
+ * EXIT - SUCCESS Client (CY) Clear - AL has return error code
+ * FAILURE Client (CY) set - means DOS is being re-entered
+ */
+
+VOID cmdExec (VOID)
+{
+
+ DWORD i;
+ DWORD dwRet;
+ PCHAR pCommandTail;
+ PCHAR pEnv;
+ CHAR Buffer[MAX_PATH];
+
+ pCommandTail = (PCHAR) GetVDMAddr ((USHORT)getDS(),(USHORT)getSI());
+ pEnv = (PCHAR) GetVDMAddr ((USHORT)getES(),0);
+ for (i=0 ; i<124 ; i++) {
+ if (pCommandTail[i] == 0x0d){
+ pCommandTail[i] = 0;
+ break;
+ }
+ }
+
+ if (i == 124){
+ setCF(0);
+ setAL((UCHAR)ERROR_BAD_FORMAT);
+ return;
+ }
+
+ chDefaultDrive = (CHAR)(getAL() + 'A');
+
+ if (getAH() == 0) {
+ cmdExec32 (pCommandTail,pEnv);
+ }
+ else {
+ dwRet = GetEnvironmentVariable ("COMSPEC",Buffer,MAX_PATH);
+
+ if (dwRet == 0 || dwRet >= MAX_PATH){
+ setCF(0);
+ setAL((UCHAR)ERROR_BAD_ENVIRONMENT);
+ return;
+ }
+
+ if ((dwRet + 4 + strlen(pCommandTail)) > MAX_PATH) {
+ setCF(0);
+ setAL((UCHAR)ERROR_BAD_ENVIRONMENT);
+ return;
+ }
+
+ strcat (Buffer, " /c ");
+ strcat (Buffer, pCommandTail);
+ cmdExec32 (Buffer,pEnv);
+ }
+
+ return;
+}
+
+/* cmdReturnExitCode - command.com has run a dos binary and returing
+ * the exit code.
+ *
+ * Entry - Client (DX) - exit code
+ * Client (AL) - current drive
+ * Client (BX:CX) - RdrInfo address
+ *
+ * Exit
+ * Client Carry Set - Reenter i.e. a new DOS binary to execute.
+ * Client Carry Clear - This shelled out session is over.
+ */
+
+VOID cmdReturnExitCode (VOID)
+{
+VDMINFO VDMInfo;
+PREDIRCOMPLETE_INFO pRdrInfo;
+
+ VDMInfo.VDMState = RETURN_ON_NO_COMMAND;
+ VDMInfo.EnviornmentSize = 0;
+ VDMInfo.ErrorCode = (ULONG)getDX();
+ VDMInfo.CmdSize = 0;
+ VDMInfo.TitleLen = 0;
+ VDMInfo.ReservedLen = 0;
+ VDMInfo.DesktopLen = 0;
+ VDMInfo.CurDirectoryLen = 0;
+
+
+ CntrlHandlerState = (CntrlHandlerState & ~CNTRL_SHELLCOUNT) |
+ (((WORD)(CntrlHandlerState & CNTRL_SHELLCOUNT))+1);
+
+ nt_block_event_thread(0);
+ fBlock = TRUE;
+
+ // a dos program just terminate, inherit its current directories
+ // and tell base too.
+ cmdUpdateCurrentDirectories((BYTE)getAL());
+
+ // Check for any copying needed for redirection
+ pRdrInfo = (PREDIRCOMPLETE_INFO) (((ULONG)getBX() << 16) + (ULONG)getCX());
+
+ if (cmdCheckCopyForRedirection (pRdrInfo) == FALSE)
+ VDMInfo.ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+
+ GetNextVDMCommand (&VDMInfo);
+ if (VDMInfo.CmdSize > 0){
+ setCF(1);
+ IsRepeatCall = TRUE;
+ }
+ else {
+ setCF(0);
+ setAL((UCHAR)dwExitCode32);
+ nt_resume_event_thread();
+ nt_std_handle_notification(fSoftpcRedirectionOnShellOut);
+ fBlock = FALSE;
+ }
+
+ CntrlHandlerState = (CntrlHandlerState & ~CNTRL_SHELLCOUNT) |
+ (((WORD)(CntrlHandlerState & CNTRL_SHELLCOUNT))-1);
+
+ return;
+}
diff --git a/private/mvdm/dos/command/cmdexit.c b/private/mvdm/dos/command/cmdexit.c
new file mode 100644
index 000000000..ead4c1434
--- /dev/null
+++ b/private/mvdm/dos/command/cmdexit.c
@@ -0,0 +1,31 @@
+/* cmdexit.c - Exit related SVC routines
+ *
+ * cmdExit
+ *
+ * Modification History:
+ *
+ * Sudeepb 05-Jul-1991 Created
+ */
+
+#include "cmd.h"
+
+#include <cmdsvc.h>
+#include <softpc.h>
+#include <winbase.h>
+
+/* cmdExitVDM - Terminate the VDM
+ *
+ *
+ * Entry - None
+ *
+ * Exit - None
+ *
+ *
+ *
+ */
+
+VOID cmdExitVDM (VOID)
+{
+ // Kill the VDM process
+ TerminateVDM();
+}
diff --git a/private/mvdm/dos/command/cmdkeyb.c b/private/mvdm/dos/command/cmdkeyb.c
new file mode 100644
index 000000000..f32a394d7
--- /dev/null
+++ b/private/mvdm/dos/command/cmdkeyb.c
@@ -0,0 +1,251 @@
+/* cmdkeyb.c - Keyboard layout support routines
+ *
+ *
+ * Modification History:
+ *
+ * YST 14-Jan_1993 Created
+ */
+
+#include "cmd.h"
+#include <winconp.h>
+#include <cmdsvc.h>
+#include <softpc.h>
+#include <mvdm.h>
+#include <ctype.h>
+#include <string.H>
+#include "cmdkeyb.h"
+
+CHAR szPrev[5] = "US";
+INT iPrevCP = 437;
+CHAR szPrevKbdID[8] = "";
+
+extern BOOL bPifFastPaste;
+
+
+
+
+/************************************************************************\
+*
+* FUNCTION: VOID cmdGetKbdLayout( VOID )
+*
+* Input Client (DX) = 0 - Keyb.com not installed
+* 1 - Keyb.com installed
+* Client (DS:SI) = pointer where exe name has to be placed
+* Client (DS:CX) = pointer where command options are placed
+*
+* Output
+* Success (DX = 1 )
+* Client (DS:SI) = Keyb.com execuatable string
+* Client (DS:CX) = command options
+*
+* Failure (DX = 0)
+*
+* COMMENTS: This function check KEYBOARD ID for Win session
+* and if ID != US then return lines with
+* filename and options to COMMAND.COM
+*
+* If bPifFastPaste is FALSE, then we always run kb16
+* for all keyboard ID including US, to give us a more
+* bios compatible Int 9 handler. 10-Jun-1993 Jonle
+*
+*
+* HISTORY: 01/05/93 YSt Created.
+*
+\************************************************************************/
+
+VOID cmdGetKbdLayout( VOID )
+{
+ INT iSize,iSaveSize;
+ CHAR szKeybCode[12];
+ CHAR szDir[MAX_PATH+15];
+ CHAR szBuf[28];
+ CHAR szNewKbdID[8];
+ CHAR szAutoLine[MAX_PATH+40];
+ PCHAR pVDMKeyb;
+
+ INT iKeyb;
+ HKEY hKey;
+ DWORD dwType;
+ DWORD retCode;
+ INT iNewCP;
+ DWORD cbData;
+ OFSTRUCT ofstr;
+
+
+
+// Get information about 16 bit KEYB.COM from VDM
+ iKeyb = getDX();
+
+
+// Get Keyboard Layout Code (hec string)
+
+ if (!GetConsoleKeyboardLayoutName(szKeybCode)) {
+ goto NoInstallkb16;
+ }
+
+
+// if we have US code 0000409 and KB16 not installed then
+// do nothing and return
+
+ if(bPifFastPaste &&
+ !strcmp(szKeybCode, US_CODE) && !iKeyb) {
+ goto NoInstallkb16;
+ }
+
+// Get keyboard ID from REGISTRY file.
+// Default is US
+
+ // OPEN THE KEY.
+ sprintf(szAutoLine, "%s%s", KBDLAYOUT_PATH, DOSCODES_PATH);
+ retCode = RegOpenKeyEx (HKEY_LOCAL_MACHINE, // Key handle at root level.
+ szAutoLine, // Path name of child key.
+ 0, // Reserved.
+ KEY_EXECUTE, // Requesting read access.
+ &hKey); // Address of key to be returned.
+
+// If retCode != 0 then we cannot find section in Register file
+ if (retCode)
+ {
+ goto NoInstallkb16;
+ }
+
+
+ dwType = REG_SZ;
+ cbData = sizeof(szBuf);
+// Query for line from REGISTER file
+ retCode = RegQueryValueEx( hKey,
+ szKeybCode,
+ NULL,
+ &dwType,
+ szBuf,
+ &cbData);
+
+ RegCloseKey(hKey);
+
+ if (retCode)
+ {
+ goto NoInstallkb16;
+ }
+
+ // look for keyboard id number. For Daytona, Turkish and Italian both
+ // have one key code and two layouts.
+ szNewKbdID[0] = '\0';
+ dwType = REG_SZ;
+ cbData = sizeof(szNewKbdID);
+ sprintf(szAutoLine, "%s%s", KBDLAYOUT_PATH, DOSIDS_PATH);
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ szAutoLine,
+ 0,
+ KEY_EXECUTE,
+ &hKey
+ ) == ERROR_SUCCESS) {
+ if (RegQueryValueEx( hKey,
+ szKeybCode,
+ NULL,
+ &dwType,
+ szNewKbdID,
+ &cbData
+ ) != ERROR_SUCCESS)
+ szNewKbdID[0] = '\0';
+
+ RegCloseKey(hKey);
+ }
+
+ iNewCP = GetConsoleCP();
+
+
+// If keycode, code page and keyboard id aren't changed, do nothing more
+
+ if(bPifFastPaste && iNewCP == iPrevCP &&
+ !_stricmp(szBuf, szPrev) &&
+ !_stricmp(szNewKbdID, szPrevKbdID)) {
+ goto NoInstallkb16;
+ }
+
+ iSaveSize = iSize = GetSystemDirectory(szDir, MAX_PATH);
+
+ if (iSize > MAX_PATH) {
+ goto NoInstallkb16;
+ }
+
+
+// If keyboard ID not found or it is US then return
+
+ if( bPifFastPaste &&
+ !_stricmp(szBuf, DEFAULT_KB_ID) && !iKeyb) {
+ goto NoInstallkb16;
+ }
+
+// Create line: SYSTEMROOT\KB16.COM
+
+ szDir[iSaveSize] = '\0';
+
+// Copy this line for COMMAND.COM
+
+ pVDMKeyb = (PCHAR) GetVDMAddr((USHORT) getDS(), (USHORT) getSI());
+
+ if ((iSaveSize+sizeof(KEYB_COM)) > 128){
+ goto NoInstallkb16;
+ }
+
+
+ sprintf(szAutoLine, "%s%s",
+ szDir, // System directory
+ KEYB_COM // keyb.com
+ );
+
+// if KB16.COM not exist then return
+ dwType = GetFileAttributes(szAutoLine);
+ if (dwType == 0xFFFFFFFF || (dwType & FILE_ATTRIBUTE_DIRECTORY) != 0)
+ {
+ goto NoInstallkb16;
+ }
+
+ strcpy(pVDMKeyb,szAutoLine);
+
+// Checking KEYBOARD.SYS
+ sprintf(szAutoLine, "%s%s",
+ szDir, // System directory
+ KEYBOARD_SYS // keyb.com
+ );
+
+ dwType = GetFileAttributes(szAutoLine);
+ if (dwType == 0xFFFFFFFF || (dwType & FILE_ATTRIBUTE_DIRECTORY) != 0)
+ {
+ goto NoInstallkb16;
+ }
+
+
+// Create line: XX,YYY,SYSTEMROOT\Keyboard.sys
+ pVDMKeyb = (PCHAR) GetVDMAddr((USHORT) getDS(), (USHORT) getCX());
+
+ sprintf(szAutoLine, " %s,%d,%s%s",
+ szBuf, // keyboard code
+ iNewCP, // new code page
+ szDir, // System directory
+ KEYBOARD_SYS // keyboard.sys
+ );
+ iSize = strlen(szAutoLine);
+ if (szNewKbdID[0] != '\0') {
+ sprintf(&szAutoLine[iSize], " /ID:%s", szNewKbdID);
+ iSize = strlen(szAutoLine);
+ }
+ szAutoLine[iSize] = 0xd;
+ *pVDMKeyb = iSize;
+ RtlMoveMemory(pVDMKeyb + 1, szAutoLine, iSize + 1);
+
+
+// Save new layout ID and code page for next call
+ strcpy(szPrev, szBuf);
+ strcpy(szPrevKbdID, szNewKbdID);
+ iPrevCP = iNewCP;
+
+ setDX(1);
+ return;
+
+NoInstallkb16:
+ setDX(0);
+ cmdInitConsole(); // make sure conoutput is on
+ return;
+
+}
diff --git a/private/mvdm/dos/command/cmdkeyb.h b/private/mvdm/dos/command/cmdkeyb.h
new file mode 100644
index 000000000..a7c0e5578
--- /dev/null
+++ b/private/mvdm/dos/command/cmdkeyb.h
@@ -0,0 +1,18 @@
+/* cmdkeyb.h - Keyboard layout support routines
+ * include file for CMDKEYB.C
+ *
+ * Modification History:
+ *
+ * YST 14-Jan_1993 Created
+ */
+
+
+#define DOSKEYBCODES "DOSKeybCodes" // section name in layout.inf
+#define LAYOUT_FILE "\\LAYOUT.INF" // INF file name
+#define DEFAULT_KB_ID "US" // Default keyboard ID
+#define KEYBOARD_SYS "\\KEYBOARD.SYS" // Data file for KEYB.COM
+#define US_CODE "00000409" // Code for US keyboard in REGISTER.INI
+#define KEYB_COM "\\KB16.COM" // File name for keyboard program
+#define KBDLAYOUT_PATH "System\\CurrentControlSet\\Control\\Keyboard Layout\\"
+#define DOSCODES_PATH "DosKeybCodes"
+#define DOSIDS_PATH "DosKeybIDs"
diff --git a/private/mvdm/dos/command/cmdmisc.c b/private/mvdm/dos/command/cmdmisc.c
new file mode 100644
index 000000000..4e8ed2557
--- /dev/null
+++ b/private/mvdm/dos/command/cmdmisc.c
@@ -0,0 +1,897 @@
+/* cmdmisc.c - Misc. SVC routines of Command.lib
+ *
+ *
+ * Modification History:
+ *
+ * Sudeepb 17-Sep-1991 Created
+ */
+
+#include "cmd.h"
+
+#include <cmdsvc.h>
+#include <demexp.h>
+#include <softpc.h>
+#include <mvdm.h>
+#include <ctype.h>
+#include <memory.h>
+#include "oemuni.h"
+#include "nt_pif.h"
+#include "nt_uis.h" // For resource id
+
+
+VOID GetWowKernelCmdLine(VOID);
+extern ULONG fSeparateWow;
+
+VOID cmdGetNextCmd (VOID)
+{
+LPSTR lpszCmd;
+PCMDINFO pCMDInfo;
+ULONG cb;
+PREDIRCOMPLETE_INFO pRdrInfo;
+VDMINFO MyVDMInfo;
+
+char *pSrc, *pDst;
+char achCurDirectory[MAXIMUM_VDM_CURRENT_DIR + 4];
+char CmdLine[MAX_PATH];
+
+ //
+ // This routine is called once for WOW VDMs, to retrieve the
+ // "krnl386" command line.
+ // 5
+ if (VDMForWOW) {
+ GetWowKernelCmdLine();
+ return;
+ }
+
+ VDMInfo.VDMState = 0;
+ pCMDInfo = (LPVOID) GetVDMAddr ((USHORT)getDS(),(USHORT)getDX());
+
+ VDMInfo.ErrorCode = FETCHWORD(pCMDInfo->ReturnCode);
+ VDMInfo.CmdSize = sizeof(CmdLine);
+ VDMInfo.CmdLine = CmdLine;
+ VDMInfo.AppName = (PVOID)GetVDMAddr(FETCHWORD(pCMDInfo->ExecPathSeg),
+ FETCHWORD(pCMDInfo->ExecPathOff));
+ VDMInfo.AppLen = FETCHWORD(pCMDInfo->ExecPathSize);
+ VDMInfo.PifLen = 0;
+ VDMInfo.EnviornmentSize = 0;
+ VDMInfo.Enviornment = NULL;
+ VDMInfo.CurDrive = 0;
+ VDMInfo.TitleLen = 0;
+ VDMInfo.ReservedLen = 0;
+ VDMInfo.DesktopLen = 0;
+ VDMInfo.CurDirectoryLen = MAX_PATH + 1;
+ VDMInfo.CurDirectory = achCurDirectory;
+
+ if(IsFirstCall){
+ VDMInfo.VDMState = ASKING_FOR_FIRST_COMMAND;
+ VDMInfo.ErrorCode = 0;
+
+ DeleteConfigFiles(); // get rid of the temp boot files
+
+ // When COMMAND.COM issues first cmdGetNextCmd, it has
+ // a completed environment already(cmdGetInitEnvironment),
+ // Therefore, we don't have to ask environment from BASE
+ cmdVDMEnvBlk.lpszzEnv = (PVOID)GetVDMAddr(FETCHWORD(pCMDInfo->EnvSeg),0);
+ cmdVDMEnvBlk.cchEnv = FETCHWORD(pCMDInfo->EnvSize);
+
+ //clear bits that track printer flushing
+ host_lpt_flush_initialize();
+ }
+ else {
+
+ // program has terminated. If the termiation was issued from
+ // second(or later) instance of command.com(cmd.exe), don't
+ // reset the flag.
+ if (Exe32ActiveCount == 0)
+ DontCheckDosBinaryType = FALSE;
+
+ // tell the base our new current directories (in ANSI)
+ // we don't do it on repeat call(the shell out case is handled in
+ // return exit code
+ if (!IsRepeatCall) {
+ cmdUpdateCurrentDirectories((BYTE)pCMDInfo->CurDrive);
+ }
+
+ VDMInfo.VDMState = 0;
+ if(!IsRepeatCall){
+ demCloseAllPSPRecords ();
+
+ if (!pfdata.CloseOnExit && DosSessionId)
+ nt_block_event_thread(1);
+ else
+ nt_block_event_thread(0);
+
+ if (DosSessionId) {
+ if (!pfdata.CloseOnExit){
+ char achTitle[MAX_PATH];
+ char achInactive[60]; //should be plenty for 'inactive'
+ strcpy (achTitle, "[");
+ if (!LoadString(GetModuleHandle(NULL), EXIT_NO_CLOSE,
+ achInactive, 60))
+ strcat (achTitle, "Inactive ");
+ else
+ strcat(achTitle, achInactive);
+ cb = strlen(achTitle);
+ // GetConsoleTitleA and SetConsoleTitleA
+ // are working on OEM character set.
+ GetConsoleTitleA(achTitle + cb, MAX_PATH - cb - 1);
+ cb = strlen(achTitle);
+ achTitle[cb] = ']';
+ achTitle[cb + 1] = '\0';
+ SetConsoleTitleA(achTitle);
+ Sleep(INFINITE);
+ }
+ else {
+ VdmExitCode = VDMInfo.ErrorCode;
+ TerminateVDM();
+ }
+ }
+ fBlock = TRUE;
+ }
+ }
+
+ if(IsRepeatCall) {
+ VDMInfo.VDMState |= ASKING_FOR_SECOND_TIME;
+ if( VDMInfo.ErrorCode != 0 )
+ IsRepeatCall = FALSE;
+ }
+
+ VDMInfo.VDMState |= ASKING_FOR_DOS_BINARY;
+
+ if (!IsFirstCall && !(VDMInfo.VDMState & ASKING_FOR_SECOND_TIME)) {
+ pRdrInfo = (PREDIRCOMPLETE_INFO) FETCHDWORD(pCMDInfo->pRdrInfo);
+ if (cmdCheckCopyForRedirection (pRdrInfo) == FALSE)
+ VDMInfo.ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ // Leave the current directory in a safe place, so that other 32bit
+ // apps etc. can delnode this directory (and other such operations) later.
+ if ( IsFirstCall == FALSE && IsRepeatCall == FALSE )
+ SetCurrentDirectory (cmdHomeDirectory);
+
+ // TSRExit will be set to 1, only if we are coming from command.com's
+ // prompt and user typed an exit. We need to kill our parent also, so we
+ // should write an exit in the console buffer.
+ if (FETCHWORD(pCMDInfo->fTSRExit)) {
+ cmdPushExitInConsoleBuffer ();
+ }
+
+ /**
+ Merging environment is required if
+ (1). Not the first comamnd &&
+ (2). NTVDM is running on an existing console ||
+ NTVDM has been shelled out.
+ Note that WOW doesn't need enviornment merging.
+ **/
+ if (!DosEnvCreated && !IsFirstCall && (!DosSessionId || Exe32ActiveCount)) {
+ RtlZeroMemory(&MyVDMInfo, sizeof(VDMINFO));
+ MyVDMInfo.VDMState = ASKING_FOR_ENVIRONMENT | ASKING_FOR_DOS_BINARY;
+ if (IsRepeatCall) {
+ MyVDMInfo.VDMState |= ASKING_FOR_SECOND_TIME;
+ MyVDMInfo.ErrorCode = 0;
+ }
+ else
+ MyVDMInfo.ErrorCode = VDMInfo.ErrorCode;
+ MyVDMInfo.Enviornment = lpszzVDMEnv32;
+ MyVDMInfo.EnviornmentSize = (USHORT) cchVDMEnv32;
+ if (!GetNextVDMCommand(&MyVDMInfo) && MyVDMInfo.EnviornmentSize > cchVDMEnv32) {
+ MyVDMInfo.Enviornment = realloc(lpszzVDMEnv32, MyVDMInfo.EnviornmentSize);
+ if (MyVDMInfo.Enviornment == NULL) {
+ RcErrorDialogBox(EG_MALLOC_FAILURE, NULL, NULL);
+ TerminateVDM();
+ }
+ lpszzVDMEnv32 = MyVDMInfo.Enviornment;
+ cchVDMEnv32 = MyVDMInfo.EnviornmentSize;
+ MyVDMInfo.VDMState = ASKING_FOR_DOS_BINARY | ASKING_FOR_ENVIRONMENT |
+ ASKING_FOR_SECOND_TIME;
+
+ MyVDMInfo.TitleLen =
+ MyVDMInfo.DesktopLen =
+ MyVDMInfo.ReservedLen =
+ MyVDMInfo.CmdSize =
+ MyVDMInfo.AppLen =
+ MyVDMInfo.PifLen =
+ MyVDMInfo.CurDirectoryLen = 0;
+ MyVDMInfo.ErrorCode = 0;
+ if (!GetNextVDMCommand(&MyVDMInfo)) {
+ RcErrorDialogBox(EG_ENVIRONMENT_ERR, NULL, NULL);
+ TerminateVDM();
+ }
+ }
+ if (!cmdCreateVDMEnvironment(&cmdVDMEnvBlk)) {
+ RcErrorDialogBox(EG_ENVIRONMENT_ERR, NULL, NULL);
+ TerminateVDM();
+ }
+ DosEnvCreated = TRUE;
+ VDMInfo.ErrorCode = 0;
+ }
+ if (cmdVDMEnvBlk.cchEnv > FETCHWORD(pCMDInfo->EnvSize)) {
+ setAX((USHORT)cmdVDMEnvBlk.cchEnv);
+ setCF(1);
+ IsFirstCall = FALSE;
+ IsRepeatCall = TRUE;
+ return;
+ }
+ if (DosEnvCreated)
+ VDMInfo.VDMState |= ASKING_FOR_SECOND_TIME;
+
+ if(!GetNextVDMCommand(&VDMInfo)){
+ RcErrorDialogBox(EG_ENVIRONMENT_ERR, NULL, NULL);
+ TerminateVDM();
+ }
+
+
+ IsRepeatCall = FALSE;
+ IsFirstCall = FALSE;
+
+ if(fBlock){
+ nt_resume_event_thread();
+ fBlock = FALSE;
+ }
+
+ // Sync VDMs enviornment variables for current directories
+ cmdSetDirectories (lpszzVDMEnv32, &VDMInfo);
+
+ // tell DOS that this is a dos executable and no further checking is
+ // necessary
+ *pIsDosBinary = 1;
+
+
+ // Check for PIF files. If a pif file is being executed extract the
+ // executable name, command line, current directory and title from the pif
+ // file and place the stuff appropriately in VDMInfo. Note, if pif file
+ // is invalid, we dont do any thing to vdminfo. In such a case we
+ // pass the pif as it is to scs to execute which we know will fail and
+ // will come back to cmdGettNextCmd with proper error code.
+
+ cmdCheckForPIF (&VDMInfo);
+
+
+ //
+ // if forcedos, then don't check binary type on int 21 exec process,
+ // so that child spawns stay in dos land. Begining with NT 4.0 forcedos.exe
+ // no longer uses pif files to force execution of a binary as a dos exe.
+ // It now uses a bit in CreateProcess (dwCreationFlags).
+ //
+
+ DontCheckDosBinaryType = (VDMInfo.dwCreationFlags & CREATE_FORCEDOS) != 0;
+
+
+ // convert exec path name to upper case. This is what command.com expect
+ if (_strupr(VDMInfo.AppName) == NULL) {
+ pSrc = VDMInfo.AppName;
+ while (*pSrc)
+ *pSrc++ = (char)toupper((int)*pSrc);
+ }
+ // figure out the extention type
+ // at least one char for the base name plus
+ // EXTENTION_STRING_LEN for the extention
+ // plus the NULL char
+ if (VDMInfo.AppLen > 1 + EXTENTION_STRING_LEN + 1) {
+ pSrc = (PCHAR)VDMInfo.AppName + VDMInfo.AppLen - 5;
+ if (!strncmp(pSrc, EXE_EXTENTION_STRING, EXTENTION_STRING_LEN))
+ STOREWORD(pCMDInfo->ExecExtType, EXE_EXTENTION);
+ else if (!strncmp(pSrc, COM_EXTENTION_STRING, EXTENTION_STRING_LEN))
+ STOREWORD(pCMDInfo->ExecExtType, COM_EXTENTION);
+ else if (!strncmp(pSrc, BAT_EXTENTION_STRING, EXTENTION_STRING_LEN))
+ STOREWORD(pCMDInfo->ExecExtType, BAT_EXTENTION);
+ else
+ STOREWORD(pCMDInfo->ExecExtType, UNKNOWN_EXTENTION);
+ }
+ else
+ STOREWORD(pCMDInfo->ExecExtType, UNKNOWN_EXTENTION);
+
+ // tell command.com the length of the app full path name.
+ STOREWORD(pCMDInfo->ExecPathSize, VDMInfo.AppLen);
+
+ //
+ // Prepare ccom's UCOMBUF
+ //
+ lpszCmd = (PVOID)GetVDMAddr(FETCHWORD(pCMDInfo->CmdLineSeg),
+ FETCHWORD(pCMDInfo->CmdLineOff));
+
+ // Copy filepart of AppName excluding extension to ccom's buffer
+ pSrc = strrchr(VDMInfo.AppName, '\\');
+ if (!pSrc) {
+ pSrc = VDMInfo.AppName;
+ }
+ else {
+ pSrc++;
+ }
+ pDst = lpszCmd + 2;
+ while (*pSrc && *pSrc != '.') {
+ *pDst++ = *pSrc++;
+ }
+ cb = strlen(CmdLine);
+
+ // cmd line must be terminated with "\0xd\0xa\0". This is either done
+ // by BASE or cmdCheckForPif function(cmdpif.c).
+
+ ASSERT((cb >= 2) && (0xd == CmdLine[cb - 2]) && (0xa == CmdLine[cb - 1]));
+
+ // if cmd line is not blank, separate program base name and
+ // cmd line with a SPACE. If it IS blank, do not insert any white chars
+ // or we end up passing white chars to the applications as cmd line
+ // and some applications just can not live with that.
+ // We do not strip leading white characters in the passed command line
+ // so the application sees the original data.
+ if (cb > 2)
+ *pDst++ = ' ';
+
+ // append the command tail(at least, "\0xd\0xa")
+ strncpy(pDst, CmdLine, cb + 1);
+
+ // set the count
+ // cb has the cmd line length including the terminated 0xd and 0xa
+ // It does NOT count the terminated NULL char.
+ ASSERT((cb + pDst - lpszCmd - 2) <= 127);
+
+ // minus 2 because the real data in lpszCmd start from lpszCmd[2]
+ lpszCmd[1] = (CHAR)(cb + pDst - lpszCmd - 2);
+
+
+
+ if (DosEnvCreated) {
+ VDMInfo.Enviornment = (PVOID)GetVDMAddr(FETCHWORD(pCMDInfo->EnvSeg),0);
+ RtlMoveMemory(VDMInfo.Enviornment,
+ cmdVDMEnvBlk.lpszzEnv,
+ cmdVDMEnvBlk.cchEnv
+ );
+ STOREWORD(pCMDInfo->EnvSize,cmdVDMEnvBlk.cchEnv);
+ free(cmdVDMEnvBlk.lpszzEnv);
+ DosEnvCreated = FALSE;
+ }
+
+ STOREWORD(pCMDInfo->fBatStatus,(USHORT)VDMInfo.fComingFromBat);
+ STOREWORD(pCMDInfo->CurDrive,VDMInfo.CurDrive);
+ STOREWORD(pCMDInfo->NumDrives,nDrives);
+ VDMInfo.CodePage = (ULONG) cmdMapCodePage (VDMInfo.CodePage);
+ STOREWORD(pCMDInfo->CodePage,(USHORT)VDMInfo.CodePage);
+
+ cmdVDMEnvBlk.lpszzEnv = NULL;
+ cmdVDMEnvBlk.cchEnv = 0;
+
+ IsFirstVDM = FALSE;
+
+ // Handle Standard IO redirection
+ pRdrInfo = cmdCheckStandardHandles (&VDMInfo,&pCMDInfo->bStdHandles);
+ STOREDWORD(pCMDInfo->pRdrInfo,(ULONG)pRdrInfo);
+
+ // Tell DOS that it has to invalidate the CDSs
+ *pSCS_ToSync = (CHAR)0xff;
+ setCF(0);
+
+ return;
+}
+
+
+
+VOID GetWowKernelCmdLine(VOID)
+{
+CMDINFO UNALIGNED *pCMDInfo;
+PCHAR pch, pEnvStrings;
+PCHAR pSlash;
+int Len;
+LPSTR pszCmdLine;
+
+
+ DeleteConfigFiles(); // get rid of the temp boot files
+ host_lpt_flush_initialize();
+
+ //
+ // Only a few things need be set for WOW.
+ // 1. NumDrives
+ // 2. Environment (get from current 32-bit env.)
+ // 3. Kernel CmdLine (get from ntvdm command tail)
+ // 4. Current drive
+ //
+
+ pCMDInfo = (LPVOID) GetVDMAddr ((USHORT)getDS(),(USHORT)getDX());
+ pCMDInfo->NumDrives = nDrives;
+
+ //
+ // Get the process's environment into lpszzVDMEnv32 and count
+ // its size into cchVDMEnv32.
+ //
+
+ pEnvStrings = pch = lpszzVDMEnv32 = GetEnvironmentStrings();
+ cchVDMEnv32 = 0;
+ while (pch[0] || pch[1]) {
+ cchVDMEnv32++;
+ pch++;
+ }
+ cchVDMEnv32 += 2; // two terminating nulls not counted in loop.
+
+ //
+ // Transform environment to suit VDM. cmdCreateVDMEnvironment
+ // uses lpszzVDMEnv32 and cchVDMEnv32 as the source.
+ //
+
+ if (!cmdCreateVDMEnvironment(&cmdVDMEnvBlk)) {
+ RcErrorDialogBox(EG_ENVIRONMENT_ERR, NULL, NULL);
+ TerminateVDM();
+ }
+
+ //
+ // Copy the transformed environment to real mode mem and then free it.
+ //
+
+ pch = (PVOID)GetVDMAddr(FETCHWORD(pCMDInfo->EnvSeg),0);
+ RtlMoveMemory(pch,
+ cmdVDMEnvBlk.lpszzEnv,
+ cmdVDMEnvBlk.cchEnv
+ );
+ STOREWORD(pCMDInfo->EnvSize,cmdVDMEnvBlk.cchEnv);
+ free(cmdVDMEnvBlk.lpszzEnv);
+ // GetEnvironmentStrings needs us to call its corresponding function
+ // to free the memory it allocated.
+ FreeEnvironmentStrings(pEnvStrings);
+
+ //
+ // Get the command line parameter, which consists of a fully
+ // qualified short path file name: "-a %SystemRoot%\system32\krnl386.exe".
+ //
+ // Note that the first token of cmdline is "%SystemRoot%\system32\ntvdm ",
+ // and may be a long file name surrounded by quotes.
+ //
+ pszCmdLine = GetCommandLine();
+ if (pszCmdLine) {
+
+ // skip leading spaces
+ while (*pszCmdLine && !isgraph(*pszCmdLine)) {
+ pszCmdLine++;
+ }
+
+ // skip first token
+ if (*pszCmdLine == '"') {
+ pszCmdLine++;
+ while (*pszCmdLine && *pszCmdLine++ != '"')
+ ;
+ }
+ else {
+ while (isgraph(*pszCmdLine)) {
+ pszCmdLine++;
+ }
+ }
+
+ // mov to beg of WowKernelPathName
+ pszCmdLine = strstr(pszCmdLine, " -a ");
+ pszCmdLine += 4;
+ while (*pszCmdLine && *pszCmdLine == ' ') {
+ pszCmdLine++;
+ }
+ }
+
+ if (!pszCmdLine || !*pszCmdLine) {
+ RcErrorDialogBox(EG_ENVIRONMENT_ERR, NULL, NULL);
+ TerminateVDM();
+ }
+
+
+ //
+ // Copy first token to ExecPath, and find the beg of the file part.
+ //
+ Len = FETCHWORD(pCMDInfo->ExecPathSize);
+ pch = (PVOID)GetVDMAddr(FETCHWORD(pCMDInfo->ExecPathSeg),
+ FETCHWORD(pCMDInfo->ExecPathOff));
+
+ pSlash = pszCmdLine;
+ while (--Len && isgraph(*pszCmdLine)) {
+ if (*pszCmdLine == '\\') {
+ pSlash = pszCmdLine + 1;
+ }
+ *pch++ = *pszCmdLine++;
+ }
+ *pch = '\0';
+ pCMDInfo->ExecPathSize -= Len;
+ pCMDInfo->ExecExtType = EXE_EXTENTION; // for WOW, use EXE extention
+
+ pszCmdLine = pSlash; // filepart begins here
+
+
+ //
+ // Copy filepart of first token and rest to CmdLine buffer
+ //
+ Len = FETCHWORD(pCMDInfo->CmdLineSize);
+ pch = (PVOID)GetVDMAddr(FETCHWORD(pCMDInfo->CmdLineSeg),
+ FETCHWORD(pCMDInfo->CmdLineOff));
+
+ while (--Len && *pszCmdLine) {
+ *pch++ = *pszCmdLine++;
+ }
+ strcpy(pch, "\x0d\x0a");
+
+
+ *pIsDosBinary = 1;
+ IsRepeatCall = FALSE;
+ IsFirstCall = FALSE;
+
+ // Tell DOS that it has to invalidate the CDSs
+ *pSCS_ToSync = (CHAR)0xff;
+ setCF(0);
+
+ return;
+}
+
+
+/* cmdGetCurrentDir - Return the current directory for a drive.
+ *
+ *
+ * Entry - Client (DS:SI) - buffer to return the directory
+ * Client (AL) - drive being queried (0 = A)
+ *
+ * EXIT - SUCCESS Client (CY) clear
+ * FAILURE Client (CY) set
+ * (AX) = 0 (Directory was bigger than 64)
+ * (AX) = 1 (the drive is not valid)
+ *
+ */
+
+VOID cmdGetCurrentDir (VOID)
+{
+PCHAR lpszCurDir;
+UCHAR chDrive;
+CHAR EnvVar[] = "=?:";
+CHAR RootName[] = "?:\\";
+DWORD EnvVarLen;
+UINT DriveType;
+
+
+ lpszCurDir = (PCHAR) GetVDMAddr ((USHORT)getDS(),(USHORT)getSI());
+ chDrive = getAL();
+ EnvVar[1] = chDrive + 'A';
+ RootName[0] = chDrive + 'A';
+
+ // if the drive doesn't exist, blindly clear the environment var
+ // and return error
+ DriveType = demGetPhysicalDriveType(chDrive);
+ if (DriveType == DRIVE_UNKNOWN) {
+ DriveType = GetDriveTypeOem(RootName);
+ }
+
+ if (DriveType == DRIVE_UNKNOWN || DriveType == DRIVE_NO_ROOT_DIR){
+ SetEnvironmentVariableOem(EnvVar, NULL);
+ setCF(1);
+ setAX(0);
+ return;
+ }
+
+ if((EnvVarLen = GetEnvironmentVariableOem (EnvVar,lpszCurDir,
+ MAXIMUM_VDM_CURRENT_DIR+3)) == 0){
+
+ // if its not in env then and drive exist then we have'nt
+ // yet touched it.
+ strcpy(lpszCurDir, RootName);
+ SetEnvironmentVariableOem (EnvVar,RootName);
+ setCF(0);
+ return;
+ }
+ if (EnvVarLen > MAXIMUM_VDM_CURRENT_DIR+3) {
+ setCF(1);
+ setAX(0);
+ }
+ else {
+ setCF(0);
+ }
+ return;
+}
+
+/* cmdSetInfo - Set the address of SCS_ToSync variable in DOSDATA.
+ * This variable is set whenever SCS dispatches a new
+ * command to command.com. Setting of this variable
+ * indicates to dos to validate all the CDS structures
+ * for local drives.
+ *
+ *
+ * Entry - Client (DS:DX) - pointer to SCSINFO.
+ *
+ * EXIT - None
+ */
+
+VOID cmdSetInfo (VOID)
+{
+
+ pSCSInfo = (PSCSINFO) GetVDMAddr (getDS(),getDX());
+
+ pSCS_ToSync = (PCHAR) &pSCSInfo->SCS_ToSync;
+
+ pIsDosBinary = (BYTE *) GetVDMAddr(getDS(), getBX());
+
+ pFDAccess = (WORD *) GetVDMAddr(getDS(), getCX());
+ return;
+}
+
+
+VOID cmdSetDirectories (PCHAR lpszzEnv, VDMINFO * pVdmInfo)
+{
+LPSTR lpszVal;
+CHAR ch, chDrive, achEnvDrive[] = "=?:";
+
+ ch = pVdmInfo->CurDrive + 'A';
+ if (pVdmInfo->CurDirectoryLen != 0){
+ SetCurrentDirectory(pVdmInfo->CurDirectory);
+ achEnvDrive[1] = ch;
+ SetEnvironmentVariable(achEnvDrive, pVdmInfo->CurDirectory);
+ }
+ if (lpszzEnv) {
+ while(*lpszzEnv) {
+ if(*lpszzEnv == '=' &&
+ (chDrive = toupper(*(lpszzEnv+1))) >= 'A' &&
+ chDrive <= 'Z' &&
+ (*(PCHAR)((ULONG)lpszzEnv+2) == ':') &&
+ chDrive != ch) {
+ lpszVal = (PCHAR)((ULONG)lpszzEnv + 4);
+ achEnvDrive[1] = chDrive;
+ SetEnvironmentVariable (achEnvDrive,lpszVal);
+ }
+ lpszzEnv = strchr(lpszzEnv,'\0');
+ lpszzEnv++;
+ }
+ }
+}
+
+static BOOL fConOutput = FALSE;
+
+VOID cmdComSpec (VOID)
+{
+LPSTR lpszCS;
+
+
+ if(IsFirstCall == FALSE)
+ return;
+
+ lpszCS = (LPVOID) GetVDMAddr ((USHORT)getDS(),(USHORT)getDX());
+ strcpy(lpszComSpec,"COMSPEC=");
+ strcpy(lpszComSpec+8,lpszCS);
+ cbComSpec = strlen(lpszComSpec) +1;
+
+ setAL((BYTE)(!fConOutput || VDMForWOW));
+
+ return;
+}
+
+
+VOID cmdSaveWorld (VOID)
+{
+#ifdef CHECK_IT_LATER
+SAVEWORLD VDMState;
+HANDLE hFile;
+PCHAR pVDM;
+DWORD dwBytesWritten;
+
+ if(IsFirstVDMInSystem) {
+ IsFirstVDMInSystem = FALSE;
+ if ((hFile = CreateFile("c:\\nt\\bin86\\savevdm.wld",
+ GENERIC_WRITE,
+ 0,
+ NULL,
+ OPEN_ALWAYS,
+ 0,
+ NULL)) == (HANDLE)-1){
+ SaveWorldCreated = FALSE;
+ return;
+ }
+ VDMState.ax = getAX();
+ VDMState.bx = getBX();
+ VDMState.cx = getCX();
+ VDMState.dx = getDX();
+ VDMState.cs = getCS();
+ VDMState.ss = getSS();
+ VDMState.ds = getDS();
+ VDMState.es = getES();
+ VDMState.si = getSI();
+ VDMState.di = getDI();
+ VDMState.bp = getBP();
+ VDMState.sp = getSP();
+ VDMState.ip = getIP() + 1;
+ VDMState.flag = 0;
+ VDMState.ImageSize = 1024*1024;
+
+ pVDM = (PVOID)GetVDMAddr(0,0);
+
+ if (WriteFile (hFile,
+ (LPVOID)&VDMState,
+ (DWORD)sizeof(VDMState),
+ &dwBytesWritten,
+ NULL) == FALSE){
+ SaveWorldCreated = FALSE;
+ CloseHandle(hFile);
+ return;
+ }
+
+ if (WriteFile (hFile,
+ (LPVOID)pVDM,
+ (DWORD)VDMState.ImageSize,
+ &dwBytesWritten,
+ NULL) == FALSE){
+ SaveWorldCreated = FALSE;
+ CloseHandle(hFile);
+ return;
+ }
+ CloseHandle(hFile);
+ }
+#endif
+ return;
+}
+
+
+/* cmdInitConsole - Let Video VDD know that it can start console output
+ * operations.
+ *
+ *
+ * Entry - None
+ *
+ *
+ * EXIT - None
+ *
+ */
+
+VOID cmdInitConsole (VOID)
+{
+ if (fConOutput == FALSE) {
+ fConOutput = TRUE;
+ nt_init_event_thread ();
+ }
+ return;
+}
+
+
+/* cmdMapCodePage - Map the Win32 Code page to DOS code page
+ */
+
+USHORT cmdMapCodePage (ULONG CodePage)
+{
+ // Currently We understand US code page only
+ if (CodePage == 1252)
+ return 437;
+ else
+ return ((USHORT)CodePage);
+}
+
+
+
+/* GetWOWShortCutInfo - returns the startupinf.reserved field of
+ * vdminfo for the first wow task.
+ *
+ * Input - Bufsize - pointer to bufsize
+ * Buf - buffer where the info is returned
+ *
+ * Output
+ * Success - returns TRUE, BufSize has the length of buffer filled in
+ * Failure - returns FALSE, Bufsize has the required buffer size.
+ */
+
+BOOL GetWOWShortCutInfo (PULONG Bufsize, PVOID Buf)
+{
+ if (*Bufsize >= VDMInfo.ReservedLen) {
+ *Bufsize = VDMInfo.ReservedLen;
+ if (Bufsize)
+ strncpy (Buf, VDMInfo.Reserved, VDMInfo.ReservedLen);
+ return TRUE;
+ }
+ else {
+ *Bufsize = VDMInfo.ReservedLen;
+ return FALSE;
+ }
+}
+
+VOID cmdUpdateCurrentDirectories(BYTE CurDrive)
+{
+ DWORD cchRemain, cchCurDir;
+ CHAR *lpszCurDir;
+ BYTE Drive;
+ DWORD DriveType;
+ CHAR achName[] = "=?:";
+ CHAR RootName[] = "?:\\";
+
+
+ // allocate new space for the new current directories
+ lpszzCurrentDirectories = (CHAR*) malloc(MAX_PATH);
+ cchCurrentDirectories = 0;
+ cchRemain = MAX_PATH;
+ lpszCurDir = lpszzCurrentDirectories;
+ if (lpszCurDir != NULL) {
+ Drive = 0;
+ // current directory is the first entry
+ achName[1] = CurDrive + 'A';
+ cchCurrentDirectories = GetEnvironmentVariable(
+ achName,
+ lpszCurDir,
+ cchRemain
+ );
+
+ if (cchCurrentDirectories == 0 || cchCurrentDirectories > MAX_PATH) {
+ free(lpszzCurrentDirectories);
+ lpszzCurrentDirectories = NULL;
+ cchCurrentDirectories = 0;
+ return;
+ }
+
+ cchRemain -= ++cchCurrentDirectories;
+ // we got current directory already. Keep the drive number
+ lpszCurDir += cchCurrentDirectories;
+
+ while (Drive < 26) {
+
+ // ignore invalid drives and current drive
+ if (Drive != CurDrive) {
+ DriveType = demGetPhysicalDriveType(Drive);
+ if (DriveType == DRIVE_UNKNOWN) {
+ RootName[0] = (CHAR)('A' + Drive);
+ DriveType = GetDriveTypeOem(RootName);
+ }
+
+ if (DriveType != DRIVE_UNKNOWN &&
+ DriveType != DRIVE_NO_ROOT_DIR )
+ {
+ achName[1] = Drive + 'A';
+ cchCurDir = GetEnvironmentVariable(
+ achName,
+ lpszCurDir,
+ cchRemain
+ );
+ if(cchCurDir > cchRemain) {
+ lpszCurDir = (CHAR *)realloc(lpszzCurrentDirectories,
+ cchRemain + MAX_PATH + cchCurrentDirectories
+ );
+ if (lpszCurDir == NULL) {
+ free(lpszzCurrentDirectories);
+ lpszzCurrentDirectories = NULL;
+ cchCurrentDirectories = 0;
+ return;
+ }
+ lpszzCurrentDirectories = lpszCurDir;
+ lpszCurDir += cchCurrentDirectories;
+ cchRemain += MAX_PATH;
+ cchCurDir = GetEnvironmentVariable(
+ achName,
+ lpszCurDir,
+ cchRemain
+ );
+ }
+ if (cchCurDir != 0) {
+ // GetEnvironmentVariable doesn't count the NULL char
+ lpszCurDir += ++cchCurDir;
+ cchRemain -= cchCurDir;
+ cchCurrentDirectories += cchCurDir;
+ }
+ }
+ }
+ // next drive
+ Drive++;
+ }
+
+
+ lpszCurDir = lpszzCurrentDirectories;
+ // need space for the ending NULL and shrink the space if necessary
+ lpszzCurrentDirectories = (CHAR *) realloc(lpszCurDir, cchCurrentDirectories + 1);
+ if (lpszzCurrentDirectories != NULL && cchCurrentDirectories != 0){
+ lpszzCurrentDirectories[cchCurrentDirectories++] = '\0';
+ SetVDMCurrentDirectories(cchCurrentDirectories, lpszzCurrentDirectories);
+ free(lpszzCurrentDirectories);
+ lpszzCurrentDirectories = NULL;
+ cchCurrentDirectories = 0;
+ }
+ else {
+ free(lpszCurDir);
+ cchCurrentDirectories = 0;
+ }
+
+ }
+}
+
+/* This SVC function tells command.com, if the VDM was started without an
+ * existing console. If so, on finding a TSR, command.com will return
+ * back to GetNextVDMCommand, rather than putting its own popup.
+ *
+ * Entry - None
+ *
+ * Exit - Client (AL) = 0 if started with an existing console
+ * Client (AL) = 1 if started with new console
+ */
+
+VOID cmdGetStartInfo (VOID)
+{
+ setAL((BYTE) (DosSessionId ? 1 : 0));
+ return;
+}
diff --git a/private/mvdm/dos/command/cmdpif.c b/private/mvdm/dos/command/cmdpif.c
new file mode 100644
index 000000000..5fa2c2190
--- /dev/null
+++ b/private/mvdm/dos/command/cmdpif.c
@@ -0,0 +1,289 @@
+/* cmdpif.c - PIF Handling Routines For SCS
+ *
+ *
+ * Modification History:
+ *
+ * Sudeepb 19-Aug-1992 Created
+ * williamh 10-Nov-1992 (1). get params from w386 extention if exist
+ * (2). null terminate caption
+ * williamh 27-May-1993 almost rewrote for better pif support
+ */
+
+#include "cmd.h"
+#include <ctype.h>
+#include <pif.h>
+#include <cmdsvc.h>
+#include <softpc.h>
+#include <mvdm.h>
+#include <oemuni.h>
+#include "nt_pif.h"
+
+VOID cmdCheckForPIF (PVDMINFO pvi)
+{
+PCHAR pCmdLine = pvi->CmdLine;
+PCHAR pDot;
+ULONG size;
+UCHAR ch;
+DWORD dw;
+CHAR lpszEnvDir [] = "=?:";
+CHAR FullPathName[MAX_PATH + 1];
+CHAR * pFilePart;
+BOOL IsPIFFile, IsFromForceDos;
+CHAR AppFullPathName[MAX_PATH + 1];
+
+ //
+ // Advance CmdLine pointer to beg of command tail
+ //
+ while (*pCmdLine && !isgraph(*pCmdLine)) { // skip to first nonwhite
+ pCmdLine++;
+ }
+
+ pDot = strrchr(pvi->AppName, '.');
+ if (pDot)
+ IsPIFFile = pDot && !_strnicmp(pDot, ".pif", 4);
+ else
+ IsPIFFile = FALSE;
+
+
+ // if the command is not a pif file and it is not
+ // running on a new console
+ if (!IsPIFFile && !DosSessionId)
+ goto CleanUpAndReturn;
+
+ if (IsPIFFile) {
+ if (!IsFirstVDM) {
+ //
+ // Get the pif data. If no pif data, or not from forcedos
+ // just return -- command.com will receive the pif file
+ // name and fail.
+ //
+ pfdata.AppHasPIFFile =
+ pfdata.IgnoreStartDirInPIF =
+ pfdata.IgnoreTitleInPIF =
+ pfdata.IgnoreCmdLineInPIF =
+ pfdata.IgnoreConfigAutoexec = 1;
+ if (!GetPIFData(&pfdata, pvi->AppName))
+ goto CleanUpAndReturn;
+ }
+
+ // we only run a pif file on two occasions:
+ // (1). it is from a new console
+ // (2). it is from forcedos.
+ if (!DosSessionId && pfdata.SubSysId != SUBSYS_DOS)
+ goto CleanUpAndReturn;
+
+ }
+ if (IsFirstVDM) {
+ // if this is the first vdm, take cmdline, startupdir and title
+ // if they are there
+ if (pfdata.StartDir){
+ dw = cmdExpandEnvironmentStrings(NULL,
+ pfdata.StartDir,
+ FullPathName,
+ MAX_PATH + 1
+ );
+ if (dw != 0 && dw <= MAX_PATH) {
+ dw = GetFullPathNameOem(FullPathName,
+ MAX_PATH + 1,
+ pfdata.StartDir,
+ &pFilePart
+ );
+ }
+
+ if (dw != 0 && dw <= MAX_PATH)
+ dw = GetFileAttributesOem(pfdata.StartDir);
+ else
+ dw = 0;
+
+ if (dw == 0 || dw == 0xFFFFFFFF || !(dw & FILE_ATTRIBUTE_DIRECTORY))
+ {
+ RcMessageBox(EG_PIF_STARTDIR_ERR,
+ NULL,
+ NULL,
+ RMB_ICON_BANG | RMB_ABORT);
+ goto CleanUpAndReturn;
+ }
+
+ dw = GetShortPathNameOem(pfdata.StartDir,
+ pfdata.StartDir,
+ MAX_PATH + 1
+ );
+ if (dw == 0 || dw > MAX_PATH || dw > 64) {
+ RcMessageBox(EG_PIF_STARTDIR_ERR,
+ NULL,
+ NULL,
+ RMB_ICON_BANG | RMB_ABORT);
+ goto CleanUpAndReturn;
+ }
+
+ lpszEnvDir[1] = pfdata.StartDir[0];
+ SetEnvironmentVariableOem(lpszEnvDir, pfdata.StartDir);
+ SetCurrentDirectoryOem(pfdata.StartDir);
+ pvi->CurDrive = toupper(pfdata.StartDir[0]) - 'A';
+ }
+
+ if (pfdata.WinTitle) {
+ strcpy(FullPathName, pfdata.WinTitle);
+ dw = cmdExpandEnvironmentStrings(NULL,
+ FullPathName,
+ pfdata.WinTitle,
+ MAX_PATH + 1
+ );
+ pfdata.WinTitle[MAX_PATH] = '\0';
+ }
+
+ if (!*pCmdLine && pfdata.CmdLine) {
+
+ // if the optinal parameter is '?'
+ // prompt the user
+ pDot = pfdata.CmdLine;
+ while (*pDot && *pDot <= ' ')
+ pDot++;
+
+ if (*pDot == '?') {
+ pfdata.CmdLine[0] = '\0';
+ RcMessageBox(EG_PIF_ASK_CMDLINE,
+ NULL,
+ pfdata.CmdLine,
+ RMB_EDIT | RMB_ICON_INFO | (128 << 16)
+ );
+ }
+
+ if (*pfdata.CmdLine) {
+ strcpy(FullPathName, pfdata.CmdLine);
+ dw = cmdExpandEnvironmentStrings(NULL,
+ FullPathName,
+ pfdata.CmdLine,
+ MAX_PATH + 1
+ );
+ }
+ }
+ }
+
+
+ if(IsPIFFile) {
+ dw = cmdExpandEnvironmentStrings(NULL,
+ pfdata.StartFile,
+ FullPathName,
+ MAX_PATH + 1
+ );
+ if (!dw || dw > MAX_PATH) {
+ RcMessageBox(EG_PIF_STARTFILE_ERR,
+ NULL, NULL, RMB_ICON_BANG | RMB_ABORT);
+ goto CleanUpAndReturn;
+ }
+
+
+
+ // search from the current directory
+ // note that the startup directory specified in
+ // the pif file has been set as our current directory
+ // when we got here
+ dw = SearchPathOem(".",
+ FullPathName,
+ NULL,
+ MAX_PATH + 1,
+ AppFullPathName,
+ &pFilePart
+ );
+ // if couldn't find the file from the current dir
+ // ask win32api help
+ if (dw == 0 || dw > MAX_PATH) {
+ dw = SearchPathOem(NULL,
+ FullPathName,
+ NULL,
+ MAX_PATH + 1,
+ AppFullPathName,
+ &pFilePart
+ );
+ }
+
+ // couldn't find the file, give up
+ if (dw == 0 || dw > MAX_PATH) {
+ RcMessageBox(EG_PIF_STARTFILE_ERR,
+ NULL, NULL, RMB_ICON_BANG | RMB_ABORT);
+ goto CleanUpAndReturn;
+ }
+
+ dw = GetFileAttributesOem(AppFullPathName);
+ if (dw == (DWORD)(-1) || (dw & FILE_ATTRIBUTE_DIRECTORY)) {
+ RcMessageBox(EG_PIF_STARTFILE_ERR, NULL, NULL,
+ RMB_ICON_BANG | RMB_ABORT
+ );
+ goto CleanUpAndReturn;
+ }
+
+ // convert to shortfilename
+ dw = GetShortPathNameOem(AppFullPathName, pvi->AppName,
+ MAX_PATH + 1);
+ if (dw == 0 || dw > MAX_PATH) {
+
+ RcMessageBox(EG_PIF_STARTFILE_ERR, NULL, NULL,
+ RMB_ICON_BANG | RMB_ABORT
+ );
+ goto CleanUpAndReturn;
+ }
+ // update the application path name length(including the terminate NULL)
+ pvi->AppLen = strlen(pvi->AppName) + 1;
+
+ // pvi->AppName contains the application short name.
+ // verify that it has the correct extension(.EXE, .COM or .BAT).
+ pDot = (PCHAR)pvi->AppName + pvi->AppLen - 5;
+ if (pvi->AppLen < 5 ||
+ (_strnicmp(pDot, EXE_EXTENTION_STRING, EXTENTION_STRING_LEN) &&
+ _strnicmp(pDot, COM_EXTENTION_STRING, EXTENTION_STRING_LEN) &&
+ _strnicmp(pDot, BAT_EXTENTION_STRING, EXTENTION_STRING_LEN)))
+ {
+
+ RcMessageBox(EG_DOS_PROG_EXTENSION,AppFullPathName, NULL, RMB_ICON_BANG | RMB_ABORT);
+ goto CleanUpAndReturn;
+
+ }
+ }
+
+
+ //
+ // Copy in pif command tail if original command tail is empty
+ //
+ if (!*pCmdLine && pfdata.CmdLine) {
+ strcpy(FullPathName, pfdata.CmdLine);
+ strcat(FullPathName, "\x0d\x0a");
+ if (strlen(FullPathName) >= 128 - 13) {
+ // too bad, the command line is too long
+ RcMessageBox(EG_PIF_CMDLINE_ERR,NULL,NULL,RMB_ICON_BANG | RMB_ABORT);
+ goto CleanUpAndReturn;
+
+ }
+ strcpy(pvi->CmdLine, FullPathName);
+ pvi->CmdSize = strlen(FullPathName) + 1;
+ }
+
+ if (IsPIFFile)
+ // we don't know the binary type at this point.
+ *pIsDosBinary = 0;
+
+ if (pfdata.WinTitle)
+ SetConsoleTitle(pfdata.WinTitle);
+
+ DontCheckDosBinaryType = (pfdata.SubSysId == SUBSYS_DOS);
+
+CleanUpAndReturn:
+ if (pfdata.CmdLine) {
+ free(pfdata.CmdLine);
+ pfdata.CmdLine = NULL;
+ }
+ if (pfdata.StartDir) {
+ free(pfdata.StartDir);
+ pfdata.StartDir = NULL;
+ }
+ if (pfdata.StartFile) {
+ free(pfdata.StartFile);
+ pfdata.StartFile = NULL;
+ }
+ if (pfdata.WinTitle) {
+ free(pfdata.WinTitle);
+ pfdata.WinTitle = NULL;
+ }
+ return;
+
+}
diff --git a/private/mvdm/dos/command/cmdpif.h b/private/mvdm/dos/command/cmdpif.h
new file mode 100644
index 000000000..bb264236f
--- /dev/null
+++ b/private/mvdm/dos/command/cmdpif.h
@@ -0,0 +1,46 @@
+
+/*================================================================
+Structure used to hold the data that CONFIG will need from the PIF
+file. This is gleaned from both the main data block and from the
+file extensions for Windows 286 and 386.
+================================================================*/
+
+
+/* WARNING !!!!!!
+ This structure is copied from NT_PIF.H in insiginia
+ hsot\inc\nt_pif.h. Make sure you keep them synchronized
+ when you make changes.
+*/
+#pragma pack()
+typedef struct
+ {
+ char *WinTitle; /* caption text(Max. 30 chars) + NULL */
+ char *CmdLine; /* command line (max 63 hars) + NULL */
+ char *StartDir; /* program file name (max 63 chars + NULL */
+ char *StartFile;
+ WORD fullorwin;
+ WORD graphicsortext;
+ WORD memreq;
+ WORD memdes;
+ WORD emsreq;
+ WORD emsdes;
+ WORD xmsreq;
+ WORD xmsdes;
+ char menuclose;
+ char reskey;
+ WORD ShortMod;
+ WORD ShortScan;
+ char idledetect;
+ char fgprio;
+ char CloseOnExit;
+ char AppHasPIFFile;
+ char IgnoreTitleInPIF;
+ char IgnoreStartDirInPIF;
+ char IgnoreShortKeyInPIF;
+ char IgnoreCmdLineInPIF;
+ char IgnoreConfigAutoexec;
+ char SubSysId;
+ } PIF_DATA;
+
+extern PIF_DATA pfdata;
+BOOL GetPIFData(PIF_DATA *, char *);
diff --git a/private/mvdm/dos/command/cmdredir.c b/private/mvdm/dos/command/cmdredir.c
new file mode 100644
index 000000000..5cf700c63
--- /dev/null
+++ b/private/mvdm/dos/command/cmdredir.c
@@ -0,0 +1,664 @@
+/* cmdredir.c - SCS routines for redirection
+ *
+ *
+ * Modification History:
+ *
+ * Sudeepb 22-Apr-1992 Created
+ */
+
+#include "cmd.h"
+
+#include <cmdsvc.h>
+#include <softpc.h>
+#include <mvdm.h>
+#include <ctype.h>
+
+#define CMDREDIR_DEBUG 1
+
+PPIPE_INPUT cmdPipeList = NULL;
+
+BOOL cmdCheckCopyForRedirection (pRdrInfo)
+PREDIRCOMPLETE_INFO pRdrInfo;
+{
+PPIPE_INPUT pPipe, pPipePrev;
+PPIPE_OUTPUT pPipeOut;
+
+ if (pRdrInfo == NULL)
+ return TRUE;
+ if (pRdrInfo->ri_pPipeStdIn != NULL) {
+
+ //Piping and Pipe list is empty?
+ ASSERT(cmdPipeList != NULL);
+
+ // in most cases, we have only one pipe for stdin
+ if (pRdrInfo->ri_pPipeStdIn == cmdPipeList){
+ pPipe = pRdrInfo->ri_pPipeStdIn;
+ cmdPipeList = pPipe->Next;
+ }
+ // multiple piping
+ // search for the right one
+ else {
+ pPipe = pPipePrev = cmdPipeList;
+ while (pPipe != NULL && pPipe != pRdrInfo->ri_pPipeStdIn){
+ pPipePrev = pPipe;
+ pPipe = pPipe->Next;
+ }
+ if (pPipe != NULL)
+ // remove it from the list
+ pPipePrev->Next = pPipe->Next;
+ }
+ if (pPipe != NULL) {
+ // grab the critical section. As soon as we have a
+ // a hold on the critical section, it is safe to kill
+ // the piping thread because it is in dormant unless
+ // it has terminated which is also safe for us.
+ EnterCriticalSection(&pPipe->CriticalSection);
+ // if the thread is till running, kill it
+ if (WaitForSingleObject(pPipe->hThread, 0)) {
+ TerminateThread(pPipe->hThread, 0);
+ WaitForSingleObject(pPipe->hThread, INFINITE);
+ }
+ LeaveCriticalSection(&pPipe->CriticalSection);
+ CloseHandle(pPipe->hFileWrite);
+ CloseHandle(pPipe->hPipe);
+ CloseHandle(pPipe->hDataEvent);
+ CloseHandle(pPipe->hThread);
+ DeleteCriticalSection(&pPipe->CriticalSection);
+ DeleteFile(pPipe->pFileName);
+ free(pPipe->pFileName);
+ free (pPipe);
+ }
+ }
+ // the application is terminating, let the output thread knows
+ // about it so it can exit appropriately.
+ // the output thread is responsible for clean up
+ if (pRdrInfo->ri_pPipeStdOut) {
+ // The output thread must wait for the event before
+ // it can exit.
+ SetEvent((pRdrInfo->ri_pPipeStdOut)->hExitEvent);
+ // wait 1 seconds for the thread to go away.
+ // this is done because our parent process may put up
+ // its prompt before our sibling process has a chance to
+ // completely display data on its display surface.
+ // note that we can not wait forever here because
+ // the sibling process could be the other dos application and
+ // we will be deadlock if it is the case
+ WaitForSingleObject(pRdrInfo->ri_hStdOutThread, 1000);
+ CloseHandle(pRdrInfo->ri_hStdOutThread);
+ }
+ if (pRdrInfo->ri_pPipeStdErr) {
+ SetEvent((pRdrInfo->ri_pPipeStdErr)->hExitEvent);
+ WaitForSingleObject(pRdrInfo->ri_hStdErrThread, 1000);
+ CloseHandle(pRdrInfo->ri_hStdErrThread);
+ }
+ free (pRdrInfo);
+
+ return TRUE;
+}
+
+BOOL cmdCreateTempFile (phTempFile,ppszTempFile)
+PHANDLE phTempFile;
+PCHAR *ppszTempFile;
+{
+
+PCHAR pszTempPath = NULL;
+DWORD TempPathSize;
+PCHAR pszTempFileName;
+HANDLE hTempFile;
+SECURITY_ATTRIBUTES sa;
+
+ pszTempPath = malloc(MAX_PATH + 12);
+
+ if (pszTempPath == NULL)
+ return FALSE;
+
+ if ((TempPathSize = GetTempPath (
+ MAX_PATH,
+ pszTempPath)) == 0){
+ free (pszTempPath);
+ return FALSE;
+ }
+
+ if (TempPathSize >= MAX_PATH) {
+ free (pszTempPath);
+ return FALSE;
+ }
+
+ // CMDCONF.C depends on the size of this buffer
+ if ((pszTempFileName = malloc (MAX_PATH + 13)) == NULL){
+ free (pszTempPath);
+ return FALSE;
+ }
+
+ // if this fails it probably means we have a bad path
+ if (!GetTempFileName(pszTempPath, "scs", 0, pszTempFileName))
+ {
+ // lets get something else, which should succeed
+ TempPathSize = GetWindowsDirectory(pszTempPath, MAX_PATH);
+ if (!TempPathSize || TempPathSize >= MAX_PATH)
+ strcpy(pszTempPath, "\\");
+
+ // try again and hope for the best
+ GetTempFileName(pszTempPath, "scs", 0, pszTempFileName);
+ }
+
+
+ // must have a security descriptor so that the child process
+ // can inherit this file handle. This is done because when we
+ // shell out with piping the 32 bits application must have inherited
+ // the temp filewe created, see cmdGetStdHandle
+ sa.nLength = sizeof(SECURITY_ATTRIBUTES);
+ sa.lpSecurityDescriptor = NULL;
+ sa.bInheritHandle = TRUE;
+
+ if ((hTempFile = CreateFile (pszTempFileName,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ &sa,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_TEMPORARY,
+ NULL)) == (HANDLE)-1){
+ free (pszTempFileName);
+ free (pszTempPath);
+ return FALSE;
+ }
+
+ *phTempFile = hTempFile;
+ *ppszTempFile = pszTempFileName;
+ free (pszTempPath);
+ return TRUE;
+}
+
+/* cmdCheckStandardHandles - Check if we have to do anything to support
+ * standard io redirection, if so save away
+ * pertaining information.
+ *
+ * Entry - pVDMInfo - VDMInfo Structure
+ * pbStdHandle - pointer to bit array for std handles
+ *
+ * EXIT - return NULL if no redirection involved
+ * return pointer to REDIRECTION_INFO
+ */
+
+PREDIRCOMPLETE_INFO cmdCheckStandardHandles (
+ PVDMINFO pVDMInfo,
+ USHORT UNALIGNED *pbStdHandle
+ )
+{
+USHORT bTemp = 0;
+PREDIRCOMPLETE_INFO pRdrInfo;
+
+ if (pVDMInfo->StdIn)
+ bTemp |= MASK_STDIN;
+
+ if (pVDMInfo->StdOut)
+ bTemp |= MASK_STDOUT;
+
+ if (pVDMInfo->StdErr)
+ bTemp |= MASK_STDERR;
+
+ if(bTemp){
+
+ if ((pRdrInfo = malloc (sizeof (REDIRCOMPLETE_INFO))) == NULL) {
+ RcErrorDialogBox(EG_MALLOC_FAILURE, NULL, NULL);
+ TerminateVDM();
+ }
+
+ RtlZeroMemory ((PVOID)pRdrInfo, sizeof(REDIRCOMPLETE_INFO));
+ pRdrInfo->ri_hStdErr = pVDMInfo->StdErr;
+ pRdrInfo->ri_hStdOut = pVDMInfo->StdOut;
+ pRdrInfo->ri_hStdIn = pVDMInfo->StdIn;
+
+ nt_std_handle_notification(TRUE);
+ fSoftpcRedirection = TRUE;
+ }
+ else{
+ pRdrInfo = NULL;
+ nt_std_handle_notification(FALSE);
+ fSoftpcRedirection = FALSE;
+ }
+
+ *pbStdHandle = bTemp;
+ return pRdrInfo;
+}
+
+/* cmdGetStdHandle - Get the 32 bit NT standard handle for the VDM
+ *
+ *
+ * Entry - Client (CX) - 0,1 or 2 (stdin stdout stderr)
+ * Client (AX:BX) - redirinfo pointer
+ *
+ * EXIT - Client (BX:CX) - 32 bit handle
+ * Client (DX:AX) - file size
+ */
+
+VOID cmdGetStdHandle (VOID)
+{
+USHORT iStdHandle;
+PREDIRCOMPLETE_INFO pRdrInfo;
+
+ iStdHandle = getCX();
+ pRdrInfo = (PREDIRCOMPLETE_INFO) (((ULONG)getAX() << 16) + (ULONG)getBX());
+
+ switch (iStdHandle) {
+
+ case HANDLE_STDIN:
+
+ if (GetFileType(pRdrInfo->ri_hStdIn) == FILE_TYPE_PIPE) {
+ if (!cmdHandleStdinWithPipe (pRdrInfo)) {
+ RcErrorDialogBox(EG_MALLOC_FAILURE, NULL, NULL);
+ TerminateVDM();
+ setCF(1);
+ return;
+ }
+ setCX ((USHORT)pRdrInfo->ri_hStdInFile);
+ setBX ((USHORT)((ULONG)pRdrInfo->ri_hStdInFile >> 16));
+ }
+ else {
+ setCX ((USHORT)pRdrInfo->ri_hStdIn);
+ setBX ((USHORT)((ULONG)pRdrInfo->ri_hStdIn >> 16));
+ }
+ break;
+
+ case HANDLE_STDOUT:
+ if (GetFileType (pRdrInfo->ri_hStdOut) == FILE_TYPE_PIPE){
+ if (!cmdHandleStdOutErrWithPipe(pRdrInfo, HANDLE_STDOUT)) {
+ RcErrorDialogBox(EG_MALLOC_FAILURE, NULL, NULL);
+ TerminateVDM();
+ setCF(1);
+ return;
+ }
+ setCX ((USHORT)pRdrInfo->ri_hStdOutFile);
+ setBX ((USHORT)((ULONG)pRdrInfo->ri_hStdOutFile >> 16));
+
+ }
+ else {
+ // sudeepb 16-Mar-1992; This will be a compatibilty problem.
+ // If the user gives the command "dosls > lpt1" we will
+ // inherit the 32 bit handle of lpt1, so the ouput will
+ // directly go to the LPT1 and a DOS TSR/APP hooking int17
+ // wont see this printing. Is this a big deal???
+ setCX ((USHORT)pRdrInfo->ri_hStdOut);
+ setBX ((USHORT)((ULONG)pRdrInfo->ri_hStdOut >> 16));
+ }
+ break;
+
+ case HANDLE_STDERR:
+
+ if (pRdrInfo->ri_hStdErr == pRdrInfo->ri_hStdOut
+ && pRdrInfo->ri_hStdOutFile != 0) {
+ setCX ((USHORT)pRdrInfo->ri_hStdOutFile);
+ setBX ((USHORT)((ULONG)pRdrInfo->ri_hStdOutFile >> 16));
+ pRdrInfo->ri_hStdErrFile = pRdrInfo->ri_hStdOutFile;
+ break;
+ }
+
+ if (GetFileType (pRdrInfo->ri_hStdErr) == FILE_TYPE_PIPE){
+ if(!cmdHandleStdOutErrWithPipe(pRdrInfo, HANDLE_STDERR)) {
+ RcErrorDialogBox(EG_MALLOC_FAILURE, NULL, NULL);
+ TerminateVDM();
+ setCF(1);
+ return;
+ }
+ setCX ((USHORT)pRdrInfo->ri_hStdErrFile);
+ setBX ((USHORT)((ULONG)pRdrInfo->ri_hStdErrFile >> 16));
+ }
+ else {
+ setCX ((USHORT)pRdrInfo->ri_hStdErr);
+ setBX ((USHORT)((ULONG)pRdrInfo->ri_hStdErr >> 16));
+ }
+ break;
+ }
+ setAX(0);
+ setDX(0);
+ setCF(0);
+ return;
+}
+
+BOOL cmdHandleStdOutErrWithPipe(
+ PREDIRCOMPLETE_INFO pRdrInfo,
+ USHORT HandleType
+ )
+{
+
+ HANDLE hFile;
+ PCHAR pFileName;
+ PPIPE_OUTPUT pPipe;
+ BYTE *Buffer;
+ DWORD ThreadId;
+ HANDLE hEvent;
+ HANDLE hFileWrite;
+ HANDLE hThread;
+
+ if(!cmdCreateTempFile(&hFile,&pFileName))
+ return FALSE;
+ // must have a different handle so that writter(dos app) and reader(us)
+ // wont use the same handle object(especially, file position)
+ hFileWrite = CreateFile(pFileName,
+ GENERIC_WRITE | GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_TEMPORARY,
+ NULL
+ );
+ if (hFileWrite == INVALID_HANDLE_VALUE) {
+ CloseHandle(hFile);
+ DeleteFile(pFileName);
+ return FALSE;
+ }
+ Buffer = malloc(sizeof(PIPE_OUTPUT) + PIPE_OUTPUT_BUFFER_SIZE);
+ if (Buffer == NULL) {
+ CloseHandle(hFile);
+ CloseHandle(hFileWrite);
+ DeleteFile(pFileName);
+ return FALSE;
+ }
+ pPipe = (PPIPE_OUTPUT)Buffer;
+ pPipe->Buffer = Buffer + sizeof(PIPE_OUTPUT);
+ pPipe->BufferSize = PIPE_OUTPUT_BUFFER_SIZE;
+ pPipe->hFile = hFileWrite;
+ pPipe->pFileName = pFileName;
+ pPipe->hExitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (pPipe->hExitEvent == NULL) {
+ CloseHandle(hFile);
+ CloseHandle(hFileWrite);
+ DeleteFile(pFileName);
+ free(pPipe);
+ return FALSE;
+ }
+
+ if (HandleType == HANDLE_STDOUT) {
+ pPipe->hPipe = pRdrInfo->ri_hStdOut;
+ pRdrInfo->ri_pPipeStdOut = pPipe;
+ pRdrInfo->ri_hStdOutFile = hFile;
+
+ }
+ else {
+ pPipe->hPipe = pRdrInfo->ri_hStdErr;
+ pRdrInfo->ri_pPipeStdErr = pPipe;
+ pRdrInfo->ri_hStdErrFile = hFile;
+
+ }
+ hThread = CreateThread ((LPSECURITY_ATTRIBUTES)NULL,
+ (DWORD)0,
+ (LPTHREAD_START_ROUTINE)cmdPipeOutThread,
+ (LPVOID)pPipe,
+ 0,
+ &ThreadId
+ );
+ if (hThread == NULL) {
+ CloseHandle(pPipe->hExitEvent);
+ CloseHandle(hFileWrite);
+ CloseHandle(hFile);
+ DeleteFile(pFileName);
+ free(Buffer);
+ return FALSE;
+ }
+ if (HandleType == HANDLE_STDOUT)
+ pRdrInfo->ri_hStdOutThread = hThread;
+ else
+ pRdrInfo->ri_hStdErrThread = hThread;
+ return TRUE;
+}
+
+/* independent thread to read application stdout(file) to NTVDM stdout(PIPE).
+ The CPU thread would notify us through hExitEvent when the application
+ is terminating(thus, we can detect EOF and exit
+ */
+
+VOID cmdPipeOutThread(LPVOID lpParam)
+{
+ PPIPE_OUTPUT pPipe;
+ DWORD BytesRead;
+ DWORD BytesWritten;
+ BOOL ExitPending;
+
+ pPipe = (PPIPE_OUTPUT)lpParam;
+
+ ExitPending = FALSE;
+
+ while(ReadFile(pPipe->hFile, pPipe->Buffer, pPipe->BufferSize, &BytesRead, NULL) ) {
+ // go nothing doesn't mean it hits EOF!!!!!!
+ // we can not just exit now, instead, we have to wait and poll
+ // until the application is terminated.
+ //
+ if (BytesRead == 0) {
+ // if read nothing and the application is gone, we can quit now
+ if (ExitPending)
+ break;
+ if (!WaitForSingleObject(pPipe->hExitEvent, PIPE_OUTPUT_TIMEOUT))
+ ExitPending = TRUE;
+ }
+ else {
+ if (!WriteFile(pPipe->hPipe, pPipe->Buffer, BytesRead, &BytesWritten, NULL) ||
+ BytesWritten != BytesRead)
+ break;
+ }
+ }
+ // if we were out of loop because of errors, wait for the cpu thread.
+ if (!ExitPending)
+ WaitForSingleObject(pPipe->hExitEvent, INFINITE);
+
+ CloseHandle(pPipe->hFile);
+ CloseHandle(pPipe->hPipe);
+ CloseHandle(pPipe->hExitEvent);
+ DeleteFile(pPipe->pFileName);
+ free(pPipe->pFileName);
+ free(pPipe);
+ ExitThread(0);
+}
+
+BOOL cmdHandleStdinWithPipe (
+ PREDIRCOMPLETE_INFO pRdrInfo
+ )
+{
+
+ HANDLE hStdinFile;
+ PCHAR pStdinFileName;
+ PPIPE_INPUT pPipe;
+ BYTE *Buffer;
+ DWORD ThreadId;
+ HANDLE hEvent;
+ HANDLE hFileWrite;
+
+ if(!cmdCreateTempFile(&hStdinFile,&pStdinFileName))
+ return FALSE;
+
+
+ // must have a different handle so that reader(dos app) and writter(us)
+ // wont use the same handle object(especially, file position)
+ hFileWrite = CreateFile(pStdinFileName,
+ GENERIC_WRITE | GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_TEMPORARY,
+ NULL
+ );
+ if (hFileWrite == INVALID_HANDLE_VALUE) {
+ CloseHandle(hStdinFile);
+ DeleteFile(pStdinFileName);
+ return FALSE;
+ }
+ Buffer = malloc(sizeof(PIPE_INPUT) + PIPE_INPUT_BUFFER_SIZE);
+ if (Buffer == NULL) {
+ CloseHandle(hStdinFile);
+ CloseHandle(hFileWrite);
+ DeleteFile(pStdinFileName);
+ return FALSE;
+ }
+ hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (hEvent == NULL) {
+ CloseHandle(hStdinFile);
+ CloseHandle(hFileWrite);
+ DeleteFile(pStdinFileName);
+ free(Buffer);
+ return FALSE;
+ }
+ pPipe = (PPIPE_INPUT)Buffer;
+ pPipe->Buffer = Buffer + sizeof(PIPE_INPUT);
+ pPipe->BufferSize = PIPE_INPUT_BUFFER_SIZE;
+ pPipe->fEOF = FALSE;
+ pPipe->hFileWrite = hFileWrite;
+ pPipe->hFileRead = hStdinFile;
+ pPipe->hDataEvent = hEvent;
+ pPipe->hPipe = pRdrInfo->ri_hStdIn;
+ pPipe->pFileName = pStdinFileName;
+ InitializeCriticalSection(&pPipe->CriticalSection);
+ pPipe->hThread = CreateThread ((LPSECURITY_ATTRIBUTES)NULL,
+ (DWORD)0,
+ (LPTHREAD_START_ROUTINE)cmdPipeInThread,
+ (LPVOID)pPipe,
+ 0,
+ &ThreadId
+ );
+ if (pPipe->hThread == NULL) {
+ CloseHandle(hFileWrite);
+ CloseHandle(pPipe->hDataEvent);
+ CloseHandle(hStdinFile);
+ DeleteFile(pStdinFileName);
+ free(Buffer);
+ return FALSE;
+ }
+ // always have the new node in the head of the list because
+ // it is the node used by the top command.com running in the process.
+ // We may have multiple command.com instances running in the same
+ // ntvdm proecess and each command.com has a private PREDIRCOMPLETE_INFO
+ // associated with it if its stdin is redirected to a pipe.
+ pPipe->Next = cmdPipeList;
+ cmdPipeList = pPipe;
+ pRdrInfo->ri_hStdInFile = hStdinFile;
+ pRdrInfo->ri_pPipeStdIn = pPipe;
+ return TRUE;
+}
+
+/* Independent thread to read from pipe(NTVDM STDIN) and write to
+ file(DOS application STDIN) until either the pipe is broken or
+ there are some errors.
+ This thread may never terminate itself because it can block
+ in the ReadFile call to the pipe forever. If this is the case,
+ we have to rely on the CPU thread to kill it. To allow the CPU
+ thread safely launching the killing, this thread yields the
+ critical section when it is safe to be killed and the CPU thread
+ would claim the critical section first before going for kill.
+ */
+
+VOID cmdPipeInThread(LPVOID lpParam)
+{
+ PPIPE_INPUT pPipe;
+ DWORD BytesRead, BytesWritten;
+ BOOL ReadStatus, WriteStatus;
+ BOOL ApplicationTerminated, fEOF;
+
+ pPipe = (PPIPE_INPUT)lpParam;
+ while (TRUE) {
+
+ // this read can take forever without getting back anything
+ ReadStatus = ReadFile(pPipe->hPipe, pPipe->Buffer,
+ pPipe->BufferSize, &BytesRead, NULL);
+
+ // claim the critical section so we won't get killed
+ // by the CPU thread
+ EnterCriticalSection(&pPipe->CriticalSection);
+ if (ReadStatus) {
+ if (BytesRead != 0) {
+ WriteStatus = WriteFile(pPipe->hFileWrite,
+ pPipe->Buffer,
+ BytesRead,
+ &BytesWritten,
+ NULL
+ );
+ if (pPipe->WaitData && WriteStatus && BytesWritten != 0)
+ SetEvent(pPipe->hDataEvent);
+ }
+ }
+ else {
+ if (GetLastError() == ERROR_BROKEN_PIPE) {
+
+ // pipe is broken and more data to read?
+ ASSERT(BytesRead == 0);
+ pPipe->fEOF = TRUE;
+ LeaveCriticalSection(&pPipe->CriticalSection);
+ break;
+ }
+ }
+ // as soon as we leave the critical seciton, the CPU thread may
+ // step in and kill us
+ LeaveCriticalSection(&pPipe->CriticalSection);
+ }
+ ExitThread(0);
+}
+
+/* cmdPipeFileDataEOF - Check for new data or EOF
+ *
+ *
+ * Entry - hFile, DOS application STDIN file handle(file)
+ * &fEOF, to return if the pipe is broken
+ * EXIT - TRUE if either there are new data or EOF is true
+ * *fEOF == TRUE if EOF
+ */
+
+BOOL cmdPipeFileDataEOF(HANDLE hFile, BOOL *fEOF)
+{
+ PPIPE_INPUT pPipe;
+ BOOL NewData;
+ DWORD WaitStatus;
+
+ pPipe = cmdPipeList;
+ while (pPipe != NULL && pPipe->hFileRead != hFile)
+ pPipe = pPipe->Next;
+
+ NewData = TRUE;
+ *fEOF = TRUE;
+
+ if (pPipe != NULL) {
+ EnterCriticalSection(&pPipe->CriticalSection);
+ *fEOF = pPipe->fEOF;
+ if (!(*fEOF)) {
+ pPipe->WaitData = TRUE;
+ LeaveCriticalSection(&pPipe->CriticalSection);
+ WaitStatus = WaitForSingleObject(pPipe->hDataEvent, PIPE_INPUT_TIMEOUT);
+ EnterCriticalSection(&pPipe->CriticalSection);
+ *fEOF = pPipe->fEOF;
+ pPipe->WaitData = FALSE;
+ NewData = WaitStatus == 0 ? TRUE : FALSE;
+ }
+ LeaveCriticalSection(&pPipe->CriticalSection);
+ }
+ return(NewData || *fEOF);
+}
+
+/* cmdPipeFileEOF - Check if the pipe is broken
+ *
+ *
+ * Entry - hFile, DOS application STDIN file handle(file)
+ *
+ * EXIT - TRUE if the write end of the pipe is closed
+ */
+
+
+BOOL cmdPipeFileEOF(HANDLE hFile)
+{
+ PPIPE_INPUT pPipe;
+ BOOL fEOF;
+
+ pPipe = cmdPipeList;
+ while (pPipe != NULL && pPipe->hFileRead != hFile)
+ pPipe = pPipe->Next;
+
+ fEOF = TRUE;
+
+ if (pPipe != NULL) {
+ EnterCriticalSection(&pPipe->CriticalSection);
+ fEOF = pPipe->fEOF;
+ LeaveCriticalSection(&pPipe->CriticalSection);
+ }
+ if (!fEOF) {
+ Sleep(PIPE_INPUT_TIMEOUT);
+ EnterCriticalSection(&pPipe->CriticalSection);
+ fEOF = pPipe->fEOF;
+ LeaveCriticalSection(&pPipe->CriticalSection);
+ }
+ return (fEOF);
+}
diff --git a/private/mvdm/dos/command/makefile b/private/mvdm/dos/command/makefile
new file mode 100644
index 000000000..985386d82
--- /dev/null
+++ b/private/mvdm/dos/command/makefile
@@ -0,0 +1,9 @@
+# Command makefile
+# 17-Sep-1991 Sudeep Bharati Created
+#
+
+# 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/mvdm/dos/command/sources b/private/mvdm/dos/command/sources
new file mode 100644
index 000000000..5d0049299
--- /dev/null
+++ b/private/mvdm/dos/command/sources
@@ -0,0 +1,60 @@
+!IF 0
+
+Copyright (c) 1989-1991 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.
+
+
+History:
+ Created 17-Sep-1991 by Sudeep Bharati (sudeepb)
+ from template created 12-Apr-1990 by Steve Wood (stevewo)
+
+
+NOTE: Commented description of this file is in \nt\public\oak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=mvdm
+MINORCOMP=command
+
+TARGETNAME=command
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=LIBRARY
+TARGETLIBS=
+
+SOFTPC_TREE=$(BASEDIR)\private\mvdm\softpc.new
+
+INCLUDES=..\..\inc;..\..\..\windows\inc;$(SOFTPC_TREE)\base\inc;$(SOFTPC_TREE)\host\inc
+
+
+NTPROFILEINPUT=YES
+
+SOURCES=cmd.c \
+ cmddata.c \
+ cmddisp.c \
+ cmdexec.c \
+ cmdexit.c \
+ cmdmisc.c \
+ cmdpif.c \
+ cmdredir.c \
+ cmdconf.c \
+ cmdkeyb.c \
+ cmdenv.c
+
+I386_SOURCES=
+MIPS_SOURCES=
+
+C_DEFINES=-DWIN_32 -DNTVDM
+
+UMTYPE=console
+UMTEST=
+UMLIBS=