[CRT]: Add a missing _munlock call, caught by Serge Gautherie.
[reactos.git] / reactos / sdk / lib / crt / stdio / popen.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS C runtime library
4 * FILE: lib/sdk/crt/stdio/popen.c
5 * PURPOSE: Pipe Functions
6 * PROGRAMMERS: Eric Kohl
7 * Hartmut Birr
8 * Also adapted from Wine team code by Andreas Maier.
9 */
10
11 #include <precomp.h>
12 #include <tchar.h>
13
14 #ifdef _UNICODE
15 #define sT "S"
16 #else
17 #define sT "s"
18 #endif
19
20 #define MK_STR(s) #s
21
22 int msvcrt_alloc_fd(HANDLE hand, int flag); //FIXME: Remove
23 unsigned split_oflags(unsigned oflags); //FIXME: Remove
24
25 #ifndef _UNICODE
26 struct popen_handle *popen_handles = NULL;
27 DWORD popen_handles_size = 0;
28
29 void msvcrt_free_popen_data(void)
30 {
31 free(popen_handles);
32 }
33 #endif
34
35 /*
36 * @implemented
37 */
38 FILE *_tpopen (const _TCHAR *cm, const _TCHAR *md) /* program name, pipe mode */
39 {
40 _TCHAR *szCmdLine=NULL;
41 _TCHAR *szComSpec=NULL;
42 _TCHAR *s;
43 FILE *ret;
44 HANDLE hReadPipe, hWritePipe;
45 BOOL result;
46 STARTUPINFO StartupInfo;
47 PROCESS_INFORMATION ProcessInformation;
48 SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
49 struct popen_handle *container;
50 DWORD i;
51
52 TRACE(MK_STR(_tpopen)"('%"sT"', '%"sT"')\n", cm, md);
53
54 if (cm == NULL)
55 return NULL;
56
57 szComSpec = _tgetenv(_T("COMSPEC"));
58 if (szComSpec == NULL)
59 {
60 szComSpec = _T("cmd.exe");
61 }
62
63 s = max(_tcsrchr(szComSpec, '\\'), _tcsrchr(szComSpec, '/'));
64 if (s == NULL)
65 s = szComSpec;
66 else
67 s++;
68
69 szCmdLine = malloc((_tcslen(s) + 4 + _tcslen(cm) + 1) * sizeof(_TCHAR));
70 if (szCmdLine == NULL)
71 {
72 return NULL;
73 }
74
75 _tcscpy(szCmdLine, s);
76 s = _tcsrchr(szCmdLine, '.');
77 if (s)
78 *s = 0;
79 _tcscat(szCmdLine, _T(" /C "));
80 _tcscat(szCmdLine, cm);
81
82 if ( !CreatePipe(&hReadPipe,&hWritePipe,&sa,1024))
83 {
84 free (szCmdLine);
85 return NULL;
86 }
87
88 memset(&ProcessInformation, 0, sizeof(ProcessInformation));
89 memset(&StartupInfo, 0, sizeof(STARTUPINFO));
90 StartupInfo.cb = sizeof(STARTUPINFO);
91
92 if (*md == 'r' ) {
93 StartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
94 StartupInfo.hStdOutput = hWritePipe;
95 StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
96 }
97 else if ( *md == 'w' ) {
98 StartupInfo.hStdInput = hReadPipe;
99 StartupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
100 StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
101 }
102
103 if (StartupInfo.dwFlags & STARTF_USESTDHANDLES)
104 StartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
105
106 result = CreateProcess(szComSpec,
107 szCmdLine,
108 NULL,
109 NULL,
110 TRUE,
111 0,
112 NULL,
113 NULL,
114 &StartupInfo,
115 &ProcessInformation);
116 free (szCmdLine);
117
118 if (result == FALSE)
119 {
120 CloseHandle(hReadPipe);
121 CloseHandle(hWritePipe);
122 return NULL;
123 }
124
125 CloseHandle(ProcessInformation.hThread);
126
127 _mlock(_POPEN_LOCK);
128 for(i=0; i<popen_handles_size; i++)
129 {
130 if (!popen_handles[i].f)
131 break;
132 }
133 if (i==popen_handles_size)
134 {
135 i = (popen_handles_size ? popen_handles_size*2 : 8);
136 container = realloc(popen_handles, i*sizeof(*container));
137 if (!container) goto error;
138
139 popen_handles = container;
140 container = popen_handles+popen_handles_size;
141 memset(container, 0, (i-popen_handles_size)*sizeof(*container));
142 popen_handles_size = i;
143 }
144 else container = popen_handles+i;
145
146 if ( *md == 'r' )
147 {
148 ret = _tfdopen(msvcrt_alloc_fd(hReadPipe, split_oflags(_fmode)) , _T("r"));
149 CloseHandle(hWritePipe);
150 }
151 else
152 {
153 ret = _tfdopen( msvcrt_alloc_fd(hWritePipe, split_oflags(_fmode)) , _T("w"));
154 CloseHandle(hReadPipe);
155 }
156
157 container->f = ret;
158 container->proc = ProcessInformation.hProcess;
159 _munlock(_POPEN_LOCK);
160
161 return ret;
162
163 error:
164 _munlock(_POPEN_LOCK);
165 if (ProcessInformation.hProcess != 0)
166 CloseHandle(ProcessInformation.hProcess);
167 return NULL;
168 }
169
170 #ifndef _UNICODE
171
172 /*
173 * @implemented
174 */
175 int CDECL _pclose(FILE* file)
176 {
177 HANDLE h;
178 DWORD i;
179
180 if (!MSVCRT_CHECK_PMT(file != NULL)) return -1;
181
182 _mlock(_POPEN_LOCK);
183 for(i=0; i<popen_handles_size; i++)
184 {
185 if (popen_handles[i].f == file)
186 break;
187 }
188 if(i == popen_handles_size)
189 {
190 _munlock(_POPEN_LOCK);
191 *_errno() = EBADF;
192 return -1;
193 }
194
195 h = popen_handles[i].proc;
196 popen_handles[i].f = NULL;
197 _munlock(_POPEN_LOCK);
198
199 fclose(file);
200 if(WaitForSingleObject(h, INFINITE)==WAIT_FAILED || !GetExitCodeProcess(h, &i))
201 {
202 _dosmaperr(GetLastError());
203 CloseHandle(h);
204 return -1;
205 }
206
207 CloseHandle(h);
208 return i;
209 }
210
211 #endif