Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

744 lines
24 KiB

  1. /* cmdredir.c - SCS routines for redirection
  2. *
  3. *
  4. * Modification History:
  5. *
  6. * Sudeepb 22-Apr-1992 Created
  7. */
  8. #include "cmd.h"
  9. #include <cmdsvc.h>
  10. #include <softpc.h>
  11. #include <mvdm.h>
  12. #include <ctype.h>
  13. #define CMDREDIR_DEBUG 1
  14. PPIPE_INPUT cmdPipeList = NULL;
  15. BOOL cmdCheckCopyForRedirection (pRdrInfo, bIsNTVDMDying)
  16. PREDIRCOMPLETE_INFO pRdrInfo;
  17. BOOL bIsNTVDMDying;
  18. {
  19. PPIPE_INPUT pPipe, pPipePrev;
  20. PPIPE_OUTPUT pPipeOut;
  21. if (pRdrInfo == NULL)
  22. return TRUE;
  23. if (pRdrInfo->ri_pPipeStdIn != NULL) {
  24. //Piping and Pipe list is empty?
  25. ASSERT(cmdPipeList != NULL);
  26. // in most cases, we have only one pipe for stdin
  27. if (pRdrInfo->ri_pPipeStdIn == cmdPipeList){
  28. pPipe = pRdrInfo->ri_pPipeStdIn;
  29. cmdPipeList = pPipe->Next;
  30. }
  31. // multiple piping
  32. // search for the right one
  33. else {
  34. pPipe = pPipePrev = cmdPipeList;
  35. while (pPipe != NULL && pPipe != pRdrInfo->ri_pPipeStdIn){
  36. pPipePrev = pPipe;
  37. pPipe = pPipe->Next;
  38. }
  39. if (pPipe != NULL)
  40. // remove it from the list
  41. pPipePrev->Next = pPipe->Next;
  42. }
  43. if (pPipe != NULL) {
  44. // grab the critical section. As soon as we have a
  45. // a hold on the critical section, it is safe to kill
  46. // the piping thread because it is in dormant unless
  47. // it has terminated which is also safe for us.
  48. EnterCriticalSection(&pPipe->CriticalSection);
  49. // if the thread is till running, kill it
  50. if (WaitForSingleObject(pPipe->hThread, 0)) {
  51. TerminateThread(pPipe->hThread, 0);
  52. WaitForSingleObject(pPipe->hThread, INFINITE);
  53. }
  54. LeaveCriticalSection(&pPipe->CriticalSection);
  55. CloseHandle(pPipe->hFileWrite);
  56. CloseHandle(pPipe->hPipe);
  57. CloseHandle(pPipe->hDataEvent);
  58. CloseHandle(pPipe->hThread);
  59. DeleteCriticalSection(&pPipe->CriticalSection);
  60. DeleteFile(pPipe->pFileName);
  61. free(pPipe->pFileName);
  62. free (pPipe);
  63. }
  64. }
  65. // the application is terminating, let the output thread knows
  66. // about it so it can exit appropriately.
  67. // the output thread is responsible for clean up
  68. if (pRdrInfo->ri_pPipeStdOut) {
  69. // The output thread must wait for the event before
  70. // it can exit.
  71. SetEvent((pRdrInfo->ri_pPipeStdOut)->hExitEvent);
  72. // If NTVDM is terminating, we have to wait for
  73. // the output thread until it is done, otherwise, the
  74. // thread may be killed while it still has some
  75. // output to do.
  76. // if NTVDM is not terminating, we can not wait for
  77. // the output thread to exit because a scenario like
  78. // "dosapp1 | dosapp2" would deadlock. Also
  79. // we can not return immediately because
  80. // our parent process may put up its prompt before our sibling
  81. // process has a chance to completely display data on
  82. // its display surface, for example:
  83. // <cmd> "dosapp | cat32"
  84. // <cmd>
  85. // so here, we wait for 1 second to give the output
  86. // thread a chance to flush all its output.
  87. WaitForSingleObject(pRdrInfo->ri_hStdOutThread,
  88. bIsNTVDMDying ? INFINITE : 1000);
  89. CloseHandle(pRdrInfo->ri_hStdOutThread);
  90. }
  91. if (pRdrInfo->ri_pPipeStdErr) {
  92. SetEvent((pRdrInfo->ri_pPipeStdErr)->hExitEvent);
  93. WaitForSingleObject(pRdrInfo->ri_hStdErrThread,
  94. bIsNTVDMDying ? INFINITE : 1000);
  95. CloseHandle(pRdrInfo->ri_hStdErrThread);
  96. }
  97. free (pRdrInfo);
  98. return TRUE;
  99. }
  100. // this function is in cmdenv.c and is used to retrieve temp directory for
  101. // 16-bit apps
  102. BOOL cmdCreateTempEnvironmentVar(
  103. LPSTR lpszTmpVar, // temp variable (or just it's name)
  104. DWORD Length, // the length of TmpVar or 0
  105. LPSTR lpszBuffer, // buffer containing
  106. DWORD LengthBuffer
  107. );
  108. DWORD cmdGetTempPathConfig(
  109. DWORD Length,
  110. LPSTR lpszPath)
  111. {
  112. CHAR szTempPath[MAX_PATH+4];
  113. PCHAR pchPath;
  114. DWORD PathSize = 0;
  115. BOOL fOk;
  116. fOk = cmdCreateTempEnvironmentVar("",
  117. 0,
  118. szTempPath,
  119. sizeof(szTempPath)/sizeof(szTempPath[0]));
  120. if (fOk) {
  121. pchPath = &szTempPath[1]; // the very first char is '='
  122. PathSize = strlen(pchPath);
  123. if ((PathSize + 1) < Length) {
  124. strcpy(lpszPath, pchPath);
  125. }
  126. }
  127. return(PathSize);
  128. }
  129. BOOL cmdCreateTempFile (phTempFile,ppszTempFile)
  130. PHANDLE phTempFile;
  131. PCHAR *ppszTempFile;
  132. {
  133. PCHAR pszTempPath = NULL;
  134. DWORD TempPathSize;
  135. PCHAR pszTempFileName;
  136. HANDLE hTempFile;
  137. SECURITY_ATTRIBUTES sa;
  138. pszTempPath = malloc(MAX_PATH + 12);
  139. if (pszTempPath == NULL)
  140. return FALSE;
  141. TempPathSize = cmdGetTempPathConfig(MAX_PATH, pszTempPath);
  142. if (0 == TempPathSize || MAX_PATH <= TempPathSize) {
  143. free(pszTempPath);
  144. return(FALSE);
  145. }
  146. // CMDCONF.C depends on the size of this buffer
  147. if ((pszTempFileName = malloc (MAX_PATH + 13)) == NULL){
  148. free (pszTempPath);
  149. return FALSE;
  150. }
  151. // if this fails it probably means we have a bad path
  152. if (!GetTempFileName(pszTempPath, "scs", 0, pszTempFileName))
  153. {
  154. // lets get something else, which should succeed
  155. TempPathSize = GetWindowsDirectory(pszTempPath, MAX_PATH);
  156. if (!TempPathSize || TempPathSize >= MAX_PATH)
  157. strcpy(pszTempPath, "\\");
  158. // try again and hope for the best
  159. GetTempFileName(pszTempPath, "scs", 0, pszTempFileName);
  160. }
  161. // must have a security descriptor so that the child process
  162. // can inherit this file handle. This is done because when we
  163. // shell out with piping the 32 bits application must have inherited
  164. // the temp filewe created, see cmdGetStdHandle
  165. sa.nLength = sizeof(SECURITY_ATTRIBUTES);
  166. sa.lpSecurityDescriptor = NULL;
  167. sa.bInheritHandle = TRUE;
  168. if ((hTempFile = CreateFile (pszTempFileName,
  169. GENERIC_READ | GENERIC_WRITE,
  170. FILE_SHARE_READ | FILE_SHARE_WRITE,
  171. &sa,
  172. OPEN_ALWAYS,
  173. FILE_ATTRIBUTE_TEMPORARY,
  174. NULL)) == (HANDLE)-1){
  175. free (pszTempFileName);
  176. free (pszTempPath);
  177. return FALSE;
  178. }
  179. *phTempFile = hTempFile;
  180. *ppszTempFile = pszTempFileName;
  181. free (pszTempPath);
  182. return TRUE;
  183. }
  184. /* cmdCheckStandardHandles - Check if we have to do anything to support
  185. * standard io redirection, if so save away
  186. * pertaining information.
  187. *
  188. * Entry - pVDMInfo - VDMInfo Structure
  189. * pbStdHandle - pointer to bit array for std handles
  190. *
  191. * EXIT - return NULL if no redirection involved
  192. * return pointer to REDIRECTION_INFO
  193. */
  194. PREDIRCOMPLETE_INFO cmdCheckStandardHandles (
  195. PVDMINFO pVDMInfo,
  196. USHORT UNALIGNED *pbStdHandle
  197. )
  198. {
  199. USHORT bTemp = 0;
  200. PREDIRCOMPLETE_INFO pRdrInfo;
  201. if (pVDMInfo->StdIn)
  202. bTemp |= MASK_STDIN;
  203. if (pVDMInfo->StdOut)
  204. bTemp |= MASK_STDOUT;
  205. if (pVDMInfo->StdErr)
  206. bTemp |= MASK_STDERR;
  207. if(bTemp){
  208. if ((pRdrInfo = malloc (sizeof (REDIRCOMPLETE_INFO))) == NULL) {
  209. RcErrorDialogBox(EG_MALLOC_FAILURE, NULL, NULL);
  210. TerminateVDM();
  211. }
  212. RtlZeroMemory ((PVOID)pRdrInfo, sizeof(REDIRCOMPLETE_INFO));
  213. pRdrInfo->ri_hStdErr = pVDMInfo->StdErr;
  214. pRdrInfo->ri_hStdOut = pVDMInfo->StdOut;
  215. pRdrInfo->ri_hStdIn = pVDMInfo->StdIn;
  216. nt_std_handle_notification(TRUE);
  217. fSoftpcRedirection = TRUE;
  218. }
  219. else{
  220. pRdrInfo = NULL;
  221. nt_std_handle_notification(FALSE);
  222. fSoftpcRedirection = FALSE;
  223. }
  224. *pbStdHandle = bTemp;
  225. return pRdrInfo;
  226. }
  227. /* cmdGetStdHandle - Get the 32 bit NT standard handle for the VDM
  228. *
  229. *
  230. * Entry - Client (CX) - 0,1 or 2 (stdin stdout stderr)
  231. * Client (AX:BX) - redirinfo pointer
  232. *
  233. * EXIT - Client (BX:CX) - 32 bit handle
  234. * Client (DX:AX) - file size
  235. */
  236. VOID cmdGetStdHandle (VOID)
  237. {
  238. USHORT iStdHandle;
  239. PREDIRCOMPLETE_INFO pRdrInfo;
  240. iStdHandle = getCX();
  241. pRdrInfo = (PREDIRCOMPLETE_INFO) (((ULONG)getAX() << 16) + (ULONG)getBX());
  242. switch (iStdHandle) {
  243. case HANDLE_STDIN:
  244. if (GetFileType(pRdrInfo->ri_hStdIn) == FILE_TYPE_PIPE) {
  245. if (!cmdHandleStdinWithPipe (pRdrInfo)) {
  246. RcErrorDialogBox(EG_MALLOC_FAILURE, NULL, NULL);
  247. TerminateVDM();
  248. setCF(1);
  249. return;
  250. }
  251. setCX ((USHORT)pRdrInfo->ri_hStdInFile);
  252. setBX ((USHORT)((ULONG)pRdrInfo->ri_hStdInFile >> 16));
  253. }
  254. else {
  255. setCX ((USHORT)pRdrInfo->ri_hStdIn);
  256. setBX ((USHORT)((ULONG)pRdrInfo->ri_hStdIn >> 16));
  257. }
  258. break;
  259. case HANDLE_STDOUT:
  260. if (GetFileType (pRdrInfo->ri_hStdOut) == FILE_TYPE_PIPE){
  261. if (!cmdHandleStdOutErrWithPipe(pRdrInfo, HANDLE_STDOUT)) {
  262. RcErrorDialogBox(EG_MALLOC_FAILURE, NULL, NULL);
  263. TerminateVDM();
  264. setCF(1);
  265. return;
  266. }
  267. setCX ((USHORT)pRdrInfo->ri_hStdOutFile);
  268. setBX ((USHORT)((ULONG)pRdrInfo->ri_hStdOutFile >> 16));
  269. }
  270. else {
  271. // sudeepb 16-Mar-1992; This will be a compatibilty problem.
  272. // If the user gives the command "dosls > lpt1" we will
  273. // inherit the 32 bit handle of lpt1, so the ouput will
  274. // directly go to the LPT1 and a DOS TSR/APP hooking int17
  275. // wont see this printing. Is this a big deal???
  276. setCX ((USHORT)pRdrInfo->ri_hStdOut);
  277. setBX ((USHORT)((ULONG)pRdrInfo->ri_hStdOut >> 16));
  278. }
  279. break;
  280. case HANDLE_STDERR:
  281. if (pRdrInfo->ri_hStdErr == pRdrInfo->ri_hStdOut
  282. && pRdrInfo->ri_hStdOutFile != 0) {
  283. setCX ((USHORT)pRdrInfo->ri_hStdOutFile);
  284. setBX ((USHORT)((ULONG)pRdrInfo->ri_hStdOutFile >> 16));
  285. pRdrInfo->ri_hStdErrFile = pRdrInfo->ri_hStdOutFile;
  286. break;
  287. }
  288. if (GetFileType (pRdrInfo->ri_hStdErr) == FILE_TYPE_PIPE){
  289. if(!cmdHandleStdOutErrWithPipe(pRdrInfo, HANDLE_STDERR)) {
  290. RcErrorDialogBox(EG_MALLOC_FAILURE, NULL, NULL);
  291. TerminateVDM();
  292. setCF(1);
  293. return;
  294. }
  295. setCX ((USHORT)pRdrInfo->ri_hStdErrFile);
  296. setBX ((USHORT)((ULONG)pRdrInfo->ri_hStdErrFile >> 16));
  297. }
  298. else {
  299. setCX ((USHORT)pRdrInfo->ri_hStdErr);
  300. setBX ((USHORT)((ULONG)pRdrInfo->ri_hStdErr >> 16));
  301. }
  302. break;
  303. }
  304. setAX(0);
  305. setDX(0);
  306. setCF(0);
  307. return;
  308. }
  309. BOOL cmdHandleStdOutErrWithPipe(
  310. PREDIRCOMPLETE_INFO pRdrInfo,
  311. USHORT HandleType
  312. )
  313. {
  314. HANDLE hFile;
  315. PCHAR pFileName;
  316. PPIPE_OUTPUT pPipe;
  317. BYTE *Buffer;
  318. DWORD ThreadId;
  319. HANDLE hEvent;
  320. HANDLE hFileWrite;
  321. HANDLE hThread;
  322. if(!cmdCreateTempFile(&hFile,&pFileName))
  323. return FALSE;
  324. // must have a different handle so that writter(dos app) and reader(us)
  325. // wont use the same handle object(especially, file position)
  326. hFileWrite = CreateFile(pFileName,
  327. GENERIC_WRITE | GENERIC_READ,
  328. FILE_SHARE_READ | FILE_SHARE_WRITE,
  329. NULL,
  330. OPEN_EXISTING,
  331. FILE_ATTRIBUTE_TEMPORARY,
  332. NULL
  333. );
  334. if (hFileWrite == INVALID_HANDLE_VALUE) {
  335. CloseHandle(hFile);
  336. DeleteFile(pFileName);
  337. return FALSE;
  338. }
  339. Buffer = malloc(sizeof(PIPE_OUTPUT) + PIPE_OUTPUT_BUFFER_SIZE);
  340. if (Buffer == NULL) {
  341. CloseHandle(hFile);
  342. CloseHandle(hFileWrite);
  343. DeleteFile(pFileName);
  344. return FALSE;
  345. }
  346. pPipe = (PPIPE_OUTPUT)Buffer;
  347. pPipe->Buffer = Buffer + sizeof(PIPE_OUTPUT);
  348. pPipe->BufferSize = PIPE_OUTPUT_BUFFER_SIZE;
  349. pPipe->hFile = hFileWrite;
  350. pPipe->pFileName = pFileName;
  351. pPipe->hExitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  352. if (pPipe->hExitEvent == NULL) {
  353. CloseHandle(hFile);
  354. CloseHandle(hFileWrite);
  355. DeleteFile(pFileName);
  356. free(pPipe);
  357. return FALSE;
  358. }
  359. if (HandleType == HANDLE_STDOUT) {
  360. pPipe->hPipe = pRdrInfo->ri_hStdOut;
  361. pRdrInfo->ri_pPipeStdOut = pPipe;
  362. pRdrInfo->ri_hStdOutFile = hFile;
  363. }
  364. else {
  365. pPipe->hPipe = pRdrInfo->ri_hStdErr;
  366. pRdrInfo->ri_pPipeStdErr = pPipe;
  367. pRdrInfo->ri_hStdErrFile = hFile;
  368. }
  369. hThread = CreateThread ((LPSECURITY_ATTRIBUTES)NULL,
  370. (DWORD)0,
  371. (LPTHREAD_START_ROUTINE)cmdPipeOutThread,
  372. (LPVOID)pPipe,
  373. 0,
  374. &ThreadId
  375. );
  376. if (hThread == NULL) {
  377. CloseHandle(pPipe->hExitEvent);
  378. CloseHandle(hFileWrite);
  379. CloseHandle(hFile);
  380. DeleteFile(pFileName);
  381. free(Buffer);
  382. return FALSE;
  383. }
  384. if (HandleType == HANDLE_STDOUT)
  385. pRdrInfo->ri_hStdOutThread = hThread;
  386. else
  387. pRdrInfo->ri_hStdErrThread = hThread;
  388. return TRUE;
  389. }
  390. /* independent thread to read application stdout(file) to NTVDM stdout(PIPE).
  391. The CPU thread would notify us through hExitEvent when the application
  392. is terminating(thus, we can detect EOF and exit
  393. */
  394. VOID cmdPipeOutThread(LPVOID lpParam)
  395. {
  396. PPIPE_OUTPUT pPipe;
  397. DWORD BytesRead;
  398. DWORD BytesWritten;
  399. BOOL ExitPending;
  400. pPipe = (PPIPE_OUTPUT)lpParam;
  401. ExitPending = FALSE;
  402. while(ReadFile(pPipe->hFile, pPipe->Buffer, pPipe->BufferSize, &BytesRead, NULL) ) {
  403. // go nothing doesn't mean it hits EOF!!!!!!
  404. // we can not just exit now, instead, we have to wait and poll
  405. // until the application is terminated.
  406. //
  407. if (BytesRead == 0) {
  408. // if read nothing and the application is gone, we can quit now
  409. if (ExitPending)
  410. break;
  411. if (!WaitForSingleObject(pPipe->hExitEvent, PIPE_OUTPUT_TIMEOUT))
  412. ExitPending = TRUE;
  413. }
  414. else {
  415. if (!WriteFile(pPipe->hPipe, pPipe->Buffer, BytesRead, &BytesWritten, NULL) ||
  416. BytesWritten != BytesRead)
  417. break;
  418. }
  419. }
  420. // if we were out of loop because of errors, wait for the cpu thread.
  421. if (!ExitPending)
  422. WaitForSingleObject(pPipe->hExitEvent, INFINITE);
  423. CloseHandle(pPipe->hFile);
  424. CloseHandle(pPipe->hPipe);
  425. CloseHandle(pPipe->hExitEvent);
  426. DeleteFile(pPipe->pFileName);
  427. free(pPipe->pFileName);
  428. free(pPipe);
  429. ExitThread(0);
  430. }
  431. BOOL cmdHandleStdinWithPipe (
  432. PREDIRCOMPLETE_INFO pRdrInfo
  433. )
  434. {
  435. HANDLE hStdinFile;
  436. PCHAR pStdinFileName;
  437. PPIPE_INPUT pPipe;
  438. BYTE *Buffer;
  439. DWORD ThreadId;
  440. HANDLE hEvent;
  441. HANDLE hFileWrite;
  442. if(!cmdCreateTempFile(&hStdinFile,&pStdinFileName))
  443. return FALSE;
  444. // must have a different handle so that reader(dos app) and writter(us)
  445. // wont use the same handle object(especially, file position)
  446. hFileWrite = CreateFile(pStdinFileName,
  447. GENERIC_WRITE | GENERIC_READ,
  448. FILE_SHARE_READ | FILE_SHARE_WRITE,
  449. NULL,
  450. OPEN_EXISTING,
  451. FILE_ATTRIBUTE_TEMPORARY,
  452. NULL
  453. );
  454. if (hFileWrite == INVALID_HANDLE_VALUE) {
  455. CloseHandle(hStdinFile);
  456. DeleteFile(pStdinFileName);
  457. return FALSE;
  458. }
  459. Buffer = malloc(sizeof(PIPE_INPUT) + PIPE_INPUT_BUFFER_SIZE);
  460. if (Buffer == NULL) {
  461. CloseHandle(hStdinFile);
  462. CloseHandle(hFileWrite);
  463. DeleteFile(pStdinFileName);
  464. return FALSE;
  465. }
  466. hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  467. if (hEvent == NULL) {
  468. CloseHandle(hStdinFile);
  469. CloseHandle(hFileWrite);
  470. DeleteFile(pStdinFileName);
  471. free(Buffer);
  472. return FALSE;
  473. }
  474. pPipe = (PPIPE_INPUT)Buffer;
  475. pPipe->Buffer = Buffer + sizeof(PIPE_INPUT);
  476. pPipe->BufferSize = PIPE_INPUT_BUFFER_SIZE;
  477. pPipe->fEOF = FALSE;
  478. pPipe->hFileWrite = hFileWrite;
  479. pPipe->hFileRead = hStdinFile;
  480. pPipe->hDataEvent = hEvent;
  481. pPipe->hPipe = pRdrInfo->ri_hStdIn;
  482. pPipe->pFileName = pStdinFileName;
  483. InitializeCriticalSection(&pPipe->CriticalSection);
  484. pPipe->hThread = CreateThread ((LPSECURITY_ATTRIBUTES)NULL,
  485. (DWORD)0,
  486. (LPTHREAD_START_ROUTINE)cmdPipeInThread,
  487. (LPVOID)pPipe,
  488. 0,
  489. &ThreadId
  490. );
  491. if (pPipe->hThread == NULL) {
  492. CloseHandle(hFileWrite);
  493. CloseHandle(pPipe->hDataEvent);
  494. CloseHandle(hStdinFile);
  495. DeleteFile(pStdinFileName);
  496. free(Buffer);
  497. return FALSE;
  498. }
  499. // always have the new node in the head of the list because
  500. // it is the node used by the top command.com running in the process.
  501. // We may have multiple command.com instances running in the same
  502. // ntvdm proecess and each command.com has a private PREDIRCOMPLETE_INFO
  503. // associated with it if its stdin is redirected to a pipe.
  504. pPipe->Next = cmdPipeList;
  505. cmdPipeList = pPipe;
  506. pRdrInfo->ri_hStdInFile = hStdinFile;
  507. pRdrInfo->ri_pPipeStdIn = pPipe;
  508. return TRUE;
  509. }
  510. /* Independent thread to read from pipe(NTVDM STDIN) and write to
  511. file(DOS application STDIN) until either the pipe is broken or
  512. there are some errors.
  513. This thread may never terminate itself because it can block
  514. in the ReadFile call to the pipe forever. If this is the case,
  515. we have to rely on the CPU thread to kill it. To allow the CPU
  516. thread safely launching the killing, this thread yields the
  517. critical section when it is safe to be killed and the CPU thread
  518. would claim the critical section first before going for kill.
  519. */
  520. VOID cmdPipeInThread(LPVOID lpParam)
  521. {
  522. PPIPE_INPUT pPipe;
  523. DWORD BytesRead, BytesWritten;
  524. BOOL ReadStatus, WriteStatus;
  525. BOOL ApplicationTerminated, fEOF;
  526. pPipe = (PPIPE_INPUT)lpParam;
  527. while (TRUE) {
  528. // this read can take forever without getting back anything
  529. ReadStatus = ReadFile(pPipe->hPipe, pPipe->Buffer,
  530. pPipe->BufferSize, &BytesRead, NULL);
  531. // claim the critical section so we won't get killed
  532. // by the CPU thread
  533. EnterCriticalSection(&pPipe->CriticalSection);
  534. if (ReadStatus) {
  535. if (BytesRead != 0) {
  536. WriteStatus = WriteFile(pPipe->hFileWrite,
  537. pPipe->Buffer,
  538. BytesRead,
  539. &BytesWritten,
  540. NULL
  541. );
  542. if (pPipe->WaitData && WriteStatus && BytesWritten != 0) {
  543. PulseEvent(pPipe->hDataEvent);
  544. //
  545. // Reset WaitData so we won't signal Event again before
  546. // data is read out.
  547. //
  548. pPipe->WaitData = FALSE;
  549. }
  550. }
  551. } else {
  552. if (GetLastError() == ERROR_BROKEN_PIPE) {
  553. // pipe is broken and more data to read?
  554. ASSERT(BytesRead == 0);
  555. pPipe->fEOF = TRUE;
  556. LeaveCriticalSection(&pPipe->CriticalSection);
  557. break;
  558. }
  559. }
  560. // as soon as we leave the critical seciton, the CPU thread may
  561. // step in and kill us
  562. LeaveCriticalSection(&pPipe->CriticalSection);
  563. }
  564. ExitThread(0);
  565. }
  566. /* cmdPipeFileDataEOF - Check for new data or EOF
  567. *
  568. *
  569. * Entry - hFile, DOS application STDIN file handle(file)
  570. * &fEOF, to return if the pipe is broken
  571. * EXIT - TRUE if either there are new data or EOF is true
  572. * *fEOF == TRUE if EOF
  573. */
  574. BOOL cmdPipeFileDataEOF(HANDLE hFile, BOOL *fEOF)
  575. {
  576. PPIPE_INPUT pPipe;
  577. BOOL NewData = FALSE;
  578. DWORD WaitStatus;
  579. DWORD FilePointerLow, FilePointerHigh = 0;
  580. DWORD FileSizeLow, FileSizeHigh;
  581. pPipe = cmdPipeList;
  582. while (pPipe != NULL && pPipe->hFileRead != hFile)
  583. pPipe = pPipe->Next;
  584. if (pPipe != NULL) {
  585. *fEOF = pPipe->fEOF;
  586. if (!(*fEOF)) {
  587. //
  588. // If not EOF, check file pointer and file size to see
  589. // if new data is available.
  590. //
  591. FilePointerLow = SetFilePointer(
  592. hFile,
  593. (LONG)0,
  594. &FilePointerHigh,
  595. (DWORD)FILE_CURRENT
  596. );
  597. ASSERT(FilePointerLow != 0xffffffff);
  598. EnterCriticalSection(&pPipe->CriticalSection);
  599. *fEOF = pPipe->fEOF;
  600. FileSizeLow = GetFileSize(hFile, &FileSizeHigh);
  601. ASSERT(FileSizeLow != 0xffffffff);
  602. //
  603. // If (file size == file pointer) there is NO new data
  604. // Just in case the file grows bigger than 4G. We compare the
  605. // whole 64 bits.
  606. //
  607. if ((FilePointerLow == FileSizeLow) && (FilePointerHigh == FileSizeHigh)) {
  608. pPipe->WaitData = TRUE;
  609. } else {
  610. NewData = TRUE;
  611. }
  612. LeaveCriticalSection(&pPipe->CriticalSection);
  613. if (!NewData) {
  614. //
  615. // If InThread enters critical section, writes data and
  616. // pulses event before we start wait. We will not be waken up.
  617. // But, we should be able to pick up the new data next
  618. // time we enter this routine.
  619. //
  620. WaitStatus = WaitForSingleObject(pPipe->hDataEvent, PIPE_INPUT_TIMEOUT);
  621. NewData = WaitStatus == WAIT_OBJECT_0 ? TRUE : FALSE;
  622. pPipe->WaitData = FALSE; // Not in Critical Section
  623. }
  624. }
  625. } else {
  626. *fEOF = TRUE;
  627. }
  628. return(NewData || *fEOF);
  629. }
  630. /* cmdPipeFileEOF - Check if the pipe is broken
  631. *
  632. *
  633. * Entry - hFile, DOS application STDIN file handle(file)
  634. *
  635. * EXIT - TRUE if the write end of the pipe is closed
  636. */
  637. BOOL cmdPipeFileEOF(HANDLE hFile)
  638. {
  639. PPIPE_INPUT pPipe;
  640. BOOL fEOF;
  641. pPipe = cmdPipeList;
  642. while (pPipe != NULL && pPipe->hFileRead != hFile)
  643. pPipe = pPipe->Next;
  644. fEOF = TRUE;
  645. if (pPipe != NULL) {
  646. EnterCriticalSection(&pPipe->CriticalSection);
  647. fEOF = pPipe->fEOF;
  648. LeaveCriticalSection(&pPipe->CriticalSection);
  649. }
  650. if (!fEOF) {
  651. Sleep(PIPE_INPUT_TIMEOUT);
  652. EnterCriticalSection(&pPipe->CriticalSection);
  653. fEOF = pPipe->fEOF;
  654. LeaveCriticalSection(&pPipe->CriticalSection);
  655. }
  656. return (fEOF);
  657. }