summaryrefslogtreecommitdiffstats
path: root/private/mvdm/dos/command/cmdredir.c
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/cmdredir.c
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/cmdredir.c')
-rw-r--r--private/mvdm/dos/command/cmdredir.c664
1 files changed, 664 insertions, 0 deletions
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);
+}