780efda7fcb834e399b2880cf421764db0fe0676
[profile/ivi/qtbase.git] / src / corelib / io / qprocess_win.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.  For licensing terms and
14 ** conditions see http://qt.digia.com/licensing.  For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights.  These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file.  Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qprocess.h"
43 #include "qprocess_p.h"
44 #include "qwindowspipereader_p.h"
45 #include "qwindowspipewriter_p.h"
46
47 #include <qdatetime.h>
48 #include <qdir.h>
49 #include <qelapsedtimer.h>
50 #include <qfileinfo.h>
51 #include <qregexp.h>
52 #include <qtimer.h>
53 #include <qwineventnotifier.h>
54 #include <private/qthread_p.h>
55 #include <qdebug.h>
56
57 #include "private/qfsfileengine_p.h" // for longFileName
58
59 #ifndef PIPE_REJECT_REMOTE_CLIENTS
60 #define PIPE_REJECT_REMOTE_CLIENTS 0x08
61 #endif
62
63 #ifndef QT_NO_PROCESS
64
65 QT_BEGIN_NAMESPACE
66
67 //#define QPROCESS_DEBUG
68
69 #define NOTIFYTIMEOUT 100
70
71 static void qt_create_pipe(Q_PIPE *pipe, bool isInputPipe)
72 {
73     // Anomymous pipes do not support asynchronous I/O. Thus we
74     // create named pipes for redirecting stdout, stderr and stdin.
75
76     SECURITY_ATTRIBUTES secAtt = { sizeof(SECURITY_ATTRIBUTES), 0, false };
77     secAtt.bInheritHandle = isInputPipe;    // The read handle must be non-inheritable for output pipes.
78
79     HANDLE hRead;
80     wchar_t pipeName[256];
81     unsigned int attempts = 1000;
82     forever {
83         // ### The user must make sure to call qsrand() to make the pipe names less predictable.
84         // ### Replace the call to qrand() with a secure version, once we have it in Qt.
85         swprintf(pipeName, sizeof(pipeName) / sizeof(pipeName[0]),
86                 L"\\\\.\\pipe\\qt-%X", qrand());
87
88         DWORD dwPipeFlags = PIPE_TYPE_BYTE | PIPE_WAIT;
89         if (QSysInfo::windowsVersion() >= QSysInfo::WV_VISTA)
90             dwPipeFlags |= PIPE_REJECT_REMOTE_CLIENTS;
91         const DWORD dwPipeBufferSize = 1024 * 1024;
92         hRead = CreateNamedPipe(pipeName,
93                                 PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
94                                 dwPipeFlags,
95                                 1,                      // only one pipe instance
96                                 0,                      // output buffer size
97                                 dwPipeBufferSize,       // input buffer size
98                                 0,
99                                 &secAtt);
100         if (hRead != INVALID_HANDLE_VALUE)
101             break;
102         DWORD dwError = GetLastError();
103         if (dwError != ERROR_PIPE_BUSY || !--attempts) {
104             qErrnoWarning(dwError, "QProcess: CreateNamedPipe failed.");
105             return;
106         }
107     }
108
109     // The write handle must be non-inheritable for input pipes.
110     secAtt.bInheritHandle = !isInputPipe;
111
112     HANDLE hWrite = INVALID_HANDLE_VALUE;
113     hWrite = CreateFile(pipeName,
114                         GENERIC_WRITE,
115                         0,
116                         &secAtt,
117                         OPEN_EXISTING,
118                         FILE_FLAG_OVERLAPPED,
119                         NULL);
120     if (hWrite == INVALID_HANDLE_VALUE) {
121         qErrnoWarning("QProcess: CreateFile failed.");
122         CloseHandle(hRead);
123         return;
124     }
125
126     // Wait until connection is in place.
127     ConnectNamedPipe(hRead, NULL);
128
129     pipe[0] = hRead;
130     pipe[1] = hWrite;
131 }
132
133 static void duplicateStdWriteChannel(Q_PIPE *pipe, DWORD nStdHandle)
134 {
135     pipe[0] = INVALID_Q_PIPE;
136     HANDLE hStdWriteChannel = GetStdHandle(nStdHandle);
137     HANDLE hCurrentProcess = GetCurrentProcess();
138     DuplicateHandle(hCurrentProcess, hStdWriteChannel, hCurrentProcess,
139                     &pipe[1], 0, TRUE, DUPLICATE_SAME_ACCESS);
140 }
141
142 /*
143     Create the pipes to a QProcessPrivate::Channel.
144
145     This function must be called in order: stdin, stdout, stderr
146 */
147 bool QProcessPrivate::createChannel(Channel &channel)
148 {
149     Q_Q(QProcess);
150
151     if (&channel == &stderrChannel && processChannelMode == QProcess::MergedChannels) {
152         return DuplicateHandle(GetCurrentProcess(), stdoutChannel.pipe[1], GetCurrentProcess(),
153                                &stderrChannel.pipe[1], 0, TRUE, DUPLICATE_SAME_ACCESS);
154     }
155
156     if (channel.type == Channel::Normal) {
157         // we're piping this channel to our own process
158         const bool isStdInChannel = (&channel == &stdinChannel);
159         if (isStdInChannel || processChannelMode != QProcess::ForwardedChannels)
160             qt_create_pipe(channel.pipe, isStdInChannel);
161         else
162             duplicateStdWriteChannel(channel.pipe, (&channel == &stdoutChannel) ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE);
163
164         if (processChannelMode != QProcess::ForwardedChannels) {
165             QWindowsPipeReader *pipeReader = 0;
166             if (&channel == &stdoutChannel) {
167                 if (!stdoutReader) {
168                     stdoutReader = new QWindowsPipeReader(q);
169                     q->connect(stdoutReader, SIGNAL(readyRead()), SLOT(_q_canReadStandardOutput()));
170                 }
171                 pipeReader = stdoutReader;
172             } else if (&channel == &stderrChannel) {
173                 if (!stderrReader) {
174                     stderrReader = new QWindowsPipeReader(q);
175                     q->connect(stderrReader, SIGNAL(readyRead()), SLOT(_q_canReadStandardError()));
176                 }
177                 pipeReader = stderrReader;
178             }
179             if (pipeReader) {
180                 pipeReader->setHandle(channel.pipe[0]);
181                 pipeReader->startAsyncRead();
182             }
183         }
184
185         return true;
186     } else if (channel.type == Channel::Redirect) {
187         // we're redirecting the channel to/from a file
188         SECURITY_ATTRIBUTES secAtt = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
189
190         if (&channel == &stdinChannel) {
191             // try to open in read-only mode
192             channel.pipe[1] = INVALID_Q_PIPE;
193             channel.pipe[0] =
194                 CreateFile((const wchar_t*)QFSFileEnginePrivate::longFileName(channel.file).utf16(),
195                            GENERIC_READ,
196                            FILE_SHARE_READ | FILE_SHARE_WRITE,
197                            &secAtt,
198                            OPEN_EXISTING,
199                            FILE_ATTRIBUTE_NORMAL,
200                            NULL);
201
202             if (channel.pipe[0] != INVALID_Q_PIPE)
203                 return true;
204
205             q->setErrorString(QProcess::tr("Could not open input redirection for reading"));
206         } else {
207             // open in write mode
208             channel.pipe[0] = INVALID_Q_PIPE;
209             channel.pipe[1] =
210                 CreateFile((const wchar_t *)QFSFileEnginePrivate::longFileName(channel.file).utf16(),
211                            GENERIC_WRITE,
212                            FILE_SHARE_READ | FILE_SHARE_WRITE,
213                            &secAtt,
214                            channel.append ? OPEN_ALWAYS : CREATE_ALWAYS,
215                            FILE_ATTRIBUTE_NORMAL,
216                            NULL);
217
218             if (channel.pipe[1] != INVALID_Q_PIPE) {
219                 if (channel.append) {
220                     SetFilePointer(channel.pipe[1], 0, NULL, FILE_END);
221                 }
222                 return true;
223             }
224
225             q->setErrorString(QProcess::tr("Could not open output redirection for writing"));
226         }
227
228         // could not open file
229         processError = QProcess::FailedToStart;
230         emit q->error(processError);
231         cleanup();
232         return false;
233     } else {
234         Q_ASSERT_X(channel.process, "QProcess::start", "Internal error");
235
236         Channel *source;
237         Channel *sink;
238
239         if (channel.type == Channel::PipeSource) {
240             // we are the source
241             source = &channel;
242             sink = &channel.process->stdinChannel;
243
244             if (source->pipe[1] != INVALID_Q_PIPE) {
245                 // already constructed by the sink
246                 // make it inheritable
247                 HANDLE tmpHandle = source->pipe[1];
248                 if (!DuplicateHandle(GetCurrentProcess(), tmpHandle,
249                                      GetCurrentProcess(), &source->pipe[1],
250                                      0, TRUE, DUPLICATE_SAME_ACCESS))
251                     return false;
252
253                 CloseHandle(tmpHandle);
254                 return true;
255             }
256
257             Q_ASSERT(source == &stdoutChannel);
258             Q_ASSERT(sink->process == this && sink->type == Channel::PipeSink);
259
260             qt_create_pipe(source->pipe, /* in = */ false); // source is stdout
261             sink->pipe[0] = source->pipe[0];
262             source->pipe[0] = INVALID_Q_PIPE;
263
264             return true;
265         } else {
266             // we are the sink;
267             source = &channel.process->stdoutChannel;
268             sink = &channel;
269
270             if (sink->pipe[0] != INVALID_Q_PIPE) {
271                 // already constructed by the source
272                 // make it inheritable
273                 HANDLE tmpHandle = sink->pipe[0];
274                 if (!DuplicateHandle(GetCurrentProcess(), tmpHandle,
275                                      GetCurrentProcess(), &sink->pipe[0],
276                                      0, TRUE, DUPLICATE_SAME_ACCESS))
277                     return false;
278
279                 CloseHandle(tmpHandle);
280                 return true;
281             }
282             Q_ASSERT(sink == &stdinChannel);
283             Q_ASSERT(source->process == this && source->type == Channel::PipeSource);
284
285             qt_create_pipe(sink->pipe, /* in = */ true); // sink is stdin
286             source->pipe[1] = sink->pipe[1];
287             sink->pipe[1] = INVALID_Q_PIPE;
288
289             return true;
290         }
291     }
292 }
293
294 void QProcessPrivate::destroyPipe(Q_PIPE pipe[2])
295 {
296     if (pipe[0] != INVALID_Q_PIPE) {
297         CloseHandle(pipe[0]);
298         pipe[0] = INVALID_Q_PIPE;
299     }
300     if (pipe[1] != INVALID_Q_PIPE) {
301         CloseHandle(pipe[1]);
302         pipe[1] = INVALID_Q_PIPE;
303     }
304 }
305
306 void QProcessPrivate::destroyChannel(Channel *channel)
307 {
308     if (channel == &stdinChannel) {
309         if (pipeWriter) {
310             delete pipeWriter;
311             pipeWriter = 0;
312         }
313     } else if (channel == &stdoutChannel) {
314         if (stdoutReader) {
315             stdoutReader->deleteLater();
316             stdoutReader = 0;
317         }
318     } else if (channel == &stderrChannel) {
319         if (stderrReader) {
320             stderrReader->deleteLater();
321             stderrReader = 0;
322         }
323     }
324     destroyPipe(channel->pipe);
325 }
326
327 static QString qt_create_commandline(const QString &program, const QStringList &arguments)
328 {
329     QString args;
330     if (!program.isEmpty()) {
331         QString programName = program;
332         if (!programName.startsWith(QLatin1Char('\"')) && !programName.endsWith(QLatin1Char('\"')) && programName.contains(QLatin1Char(' ')))
333             programName = QLatin1Char('\"') + programName + QLatin1Char('\"');
334         programName.replace(QLatin1Char('/'), QLatin1Char('\\'));
335
336         // add the prgram as the first arg ... it works better
337         args = programName + QLatin1Char(' ');
338     }
339
340     for (int i=0; i<arguments.size(); ++i) {
341         QString tmp = arguments.at(i);
342         // Quotes are escaped and their preceding backslashes are doubled.
343         tmp.replace(QRegExp(QLatin1String("(\\\\*)\"")), QLatin1String("\\1\\1\\\""));
344         if (tmp.isEmpty() || tmp.contains(QLatin1Char(' ')) || tmp.contains(QLatin1Char('\t'))) {
345             // The argument must not end with a \ since this would be interpreted
346             // as escaping the quote -- rather put the \ behind the quote: e.g.
347             // rather use "foo"\ than "foo\"
348             int i = tmp.length();
349             while (i > 0 && tmp.at(i - 1) == QLatin1Char('\\'))
350                 --i;
351             tmp.insert(i, QLatin1Char('"'));
352             tmp.prepend(QLatin1Char('"'));
353         }
354         args += QLatin1Char(' ') + tmp;
355     }
356     return args;
357 }
358
359 QProcessEnvironment QProcessEnvironment::systemEnvironment()
360 {
361     QProcessEnvironment env;
362     // Calls to setenv() affect the low-level environment as well.
363     // This is not the case the other way round.
364     if (wchar_t *envStrings = GetEnvironmentStringsW()) {
365         for (const wchar_t *entry = envStrings; *entry; ) {
366             const int entryLen = int(wcslen(entry));
367             if (const wchar_t *equal = wcschr(entry, L'=')) {
368                 int nameLen = equal - entry;
369                 QString name = QString::fromWCharArray(entry, nameLen);
370                 QString value = QString::fromWCharArray(equal + 1, entryLen - nameLen - 1);
371                 env.d->hash.insert(QProcessEnvironmentPrivate::Key(name), value);
372             }
373             entry += entryLen + 1;
374         }
375         FreeEnvironmentStringsW(envStrings);
376     }
377     return env;
378 }
379
380 static QByteArray qt_create_environment(const QProcessEnvironmentPrivate::Hash &environment)
381 {
382     QByteArray envlist;
383     if (!environment.isEmpty()) {
384         QProcessEnvironmentPrivate::Hash copy = environment;
385
386         // add PATH if necessary (for DLL loading)
387         QProcessEnvironmentPrivate::Key pathKey(QLatin1String("PATH"));
388         if (!copy.contains(pathKey)) {
389             QByteArray path = qgetenv("PATH");
390             if (!path.isEmpty())
391                 copy.insert(pathKey, QString::fromLocal8Bit(path));
392         }
393
394         // add systemroot if needed
395         QProcessEnvironmentPrivate::Key rootKey(QLatin1String("SystemRoot"));
396         if (!copy.contains(rootKey)) {
397             QByteArray systemRoot = qgetenv("SystemRoot");
398             if (!systemRoot.isEmpty())
399                 copy.insert(rootKey, QString::fromLocal8Bit(systemRoot));
400         }
401
402         int pos = 0;
403         QProcessEnvironmentPrivate::Hash::ConstIterator it = copy.constBegin(),
404                                                        end = copy.constEnd();
405
406         static const wchar_t equal = L'=';
407         static const wchar_t nul = L'\0';
408
409         for ( ; it != end; ++it) {
410             uint tmpSize = sizeof(wchar_t) * (it.key().length() + it.value().length() + 2);
411             // ignore empty strings
412             if (tmpSize == sizeof(wchar_t) * 2)
413                 continue;
414             envlist.resize(envlist.size() + tmpSize);
415
416             tmpSize = it.key().length() * sizeof(wchar_t);
417             memcpy(envlist.data()+pos, it.key().utf16(), tmpSize);
418             pos += tmpSize;
419
420             memcpy(envlist.data()+pos, &equal, sizeof(wchar_t));
421             pos += sizeof(wchar_t);
422
423             tmpSize = it.value().length() * sizeof(wchar_t);
424             memcpy(envlist.data()+pos, it.value().utf16(), tmpSize);
425             pos += tmpSize;
426
427             memcpy(envlist.data()+pos, &nul, sizeof(wchar_t));
428             pos += sizeof(wchar_t);
429         }
430         // add the 2 terminating 0 (actually 4, just to be on the safe side)
431         envlist.resize( envlist.size()+4 );
432         envlist[pos++] = 0;
433         envlist[pos++] = 0;
434         envlist[pos++] = 0;
435         envlist[pos++] = 0;
436     }
437     return envlist;
438 }
439
440 void QProcessPrivate::startProcess()
441 {
442     Q_Q(QProcess);
443
444     bool success = false;
445
446     if (pid) {
447         CloseHandle(pid->hThread);
448         CloseHandle(pid->hProcess);
449         delete pid;
450         pid = 0;
451     }
452     pid = new PROCESS_INFORMATION;
453     memset(pid, 0, sizeof(PROCESS_INFORMATION));
454
455     q->setProcessState(QProcess::Starting);
456
457     if (!createChannel(stdinChannel) ||
458         !createChannel(stdoutChannel) ||
459         !createChannel(stderrChannel))
460         return;
461
462     QString args = qt_create_commandline(program, arguments);
463     QByteArray envlist;
464     if (environment.d.constData())
465         envlist = qt_create_environment(environment.d.constData()->hash);
466     if (!nativeArguments.isEmpty()) {
467         if (!args.isEmpty())
468              args += QLatin1Char(' ');
469         args += nativeArguments;
470     }
471
472 #if defined QPROCESS_DEBUG
473     qDebug("Creating process");
474     qDebug("   program : [%s]", program.toLatin1().constData());
475     qDebug("   args : %s", args.toLatin1().constData());
476     qDebug("   pass environment : %s", environment.isEmpty() ? "no" : "yes");
477 #endif
478
479     // Forwarded channels must not set the CREATE_NO_WINDOW flag because this
480     // will render the stdout/stderr handles we're passing useless.
481     DWORD dwCreationFlags = (processChannelMode == QProcess::ForwardedChannels ? 0 : CREATE_NO_WINDOW);
482     dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
483     STARTUPINFOW startupInfo = { sizeof( STARTUPINFO ), 0, 0, 0,
484                                  (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT,
485                                  (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT,
486                                  0, 0, 0,
487                                  STARTF_USESTDHANDLES,
488                                  0, 0, 0,
489                                  stdinChannel.pipe[0], stdoutChannel.pipe[1], stderrChannel.pipe[1]
490     };
491     success = CreateProcess(0, (wchar_t*)args.utf16(),
492                             0, 0, TRUE, dwCreationFlags,
493                             environment.isEmpty() ? 0 : envlist.data(),
494                             workingDirectory.isEmpty() ? 0 : (wchar_t*)QDir::toNativeSeparators(workingDirectory).utf16(),
495                             &startupInfo, pid);
496     if (!success) {
497         // Capture the error string before we do CloseHandle below
498         q->setErrorString(QProcess::tr("Process failed to start: %1").arg(qt_error_string()));
499     }
500
501     if (stdinChannel.pipe[0] != INVALID_Q_PIPE) {
502         CloseHandle(stdinChannel.pipe[0]);
503         stdinChannel.pipe[0] = INVALID_Q_PIPE;
504     }
505     if (stdoutChannel.pipe[1] != INVALID_Q_PIPE) {
506         CloseHandle(stdoutChannel.pipe[1]);
507         stdoutChannel.pipe[1] = INVALID_Q_PIPE;
508     }
509     if (stderrChannel.pipe[1] != INVALID_Q_PIPE) {
510         CloseHandle(stderrChannel.pipe[1]);
511         stderrChannel.pipe[1] = INVALID_Q_PIPE;
512     }
513
514     if (!success) {
515         cleanup();
516         processError = QProcess::FailedToStart;
517         emit q->error(processError);
518         q->setProcessState(QProcess::NotRunning);
519         return;
520     }
521
522     q->setProcessState(QProcess::Running);
523     // User can call kill()/terminate() from the stateChanged() slot
524     // so check before proceeding
525     if (!pid)
526         return;
527
528     if (threadData->eventDispatcher) {
529         processFinishedNotifier = new QWinEventNotifier(pid->hProcess, q);
530         QObject::connect(processFinishedNotifier, SIGNAL(activated(HANDLE)), q, SLOT(_q_processDied()));
531         processFinishedNotifier->setEnabled(true);
532         notifier = new QTimer(q);
533         QObject::connect(notifier, SIGNAL(timeout()), q, SLOT(_q_notified()));
534         notifier->start(NOTIFYTIMEOUT);
535     }
536
537     _q_startupNotification();
538 }
539
540 bool QProcessPrivate::processStarted()
541 {
542     return processState == QProcess::Running;
543 }
544
545 qint64 QProcessPrivate::bytesAvailableFromStdout() const
546 {
547     if (stdoutChannel.pipe[0] == INVALID_Q_PIPE)
548         return 0;
549
550     if (!stdoutReader)
551         return 0;
552
553     DWORD bytesAvail = stdoutReader->bytesAvailable();
554 #if defined QPROCESS_DEBUG
555     qDebug("QProcessPrivate::bytesAvailableFromStdout() == %d", bytesAvail);
556 #endif
557     return bytesAvail;
558 }
559
560 qint64 QProcessPrivate::bytesAvailableFromStderr() const
561 {
562     if (stderrChannel.pipe[0] == INVALID_Q_PIPE)
563         return 0;
564
565     if (!stderrReader)
566         return 0;
567
568     DWORD bytesAvail = stderrReader->bytesAvailable();
569 #if defined QPROCESS_DEBUG
570     qDebug("QProcessPrivate::bytesAvailableFromStderr() == %d", bytesAvail);
571 #endif
572     return bytesAvail;
573 }
574
575 qint64 QProcessPrivate::readFromStdout(char *data, qint64 maxlen)
576 {
577     return stdoutReader ? stdoutReader->read(data, maxlen) : 0;
578 }
579
580 qint64 QProcessPrivate::readFromStderr(char *data, qint64 maxlen)
581 {
582     return stderrReader ? stderrReader->read(data, maxlen) : 0;
583 }
584
585
586 static BOOL QT_WIN_CALLBACK qt_terminateApp(HWND hwnd, LPARAM procId)
587 {
588     DWORD currentProcId = 0;
589     GetWindowThreadProcessId(hwnd, &currentProcId);
590     if (currentProcId == (DWORD)procId)
591             PostMessage(hwnd, WM_CLOSE, 0, 0);
592
593     return TRUE;
594 }
595
596 void QProcessPrivate::terminateProcess()
597 {
598     if (pid) {
599         EnumWindows(qt_terminateApp, (LPARAM)pid->dwProcessId);
600         PostThreadMessage(pid->dwThreadId, WM_CLOSE, 0, 0);
601     }
602 }
603
604 void QProcessPrivate::killProcess()
605 {
606     if (pid)
607         TerminateProcess(pid->hProcess, 0xf291);
608 }
609
610 bool QProcessPrivate::waitForStarted(int)
611 {
612     Q_Q(QProcess);
613
614     if (processStarted())
615         return true;
616
617     if (processError == QProcess::FailedToStart)
618         return false;
619
620     processError = QProcess::Timedout;
621     q->setErrorString(QProcess::tr("Process operation timed out"));
622     return false;
623 }
624
625 static bool drainOutputPipes(QProcessPrivate *d)
626 {
627     if (!d->stdoutReader && !d->stderrReader)
628         return false;
629
630     bool readyReadEmitted = false;
631     forever {
632         bool readOperationActive = false;
633         if (d->stdoutReader) {
634             readyReadEmitted |= d->stdoutReader->waitForReadyRead(0);
635             readOperationActive = d->stdoutReader->isReadOperationActive();
636         }
637         if (d->stderrReader) {
638             readyReadEmitted |= d->stderrReader->waitForReadyRead(0);
639             readOperationActive |= d->stderrReader->isReadOperationActive();
640         }
641         if (!readOperationActive)
642             break;
643         Sleep(100);
644     }
645
646     return readyReadEmitted;
647 }
648
649 bool QProcessPrivate::waitForReadyRead(int msecs)
650 {
651     Q_Q(QProcess);
652
653     QIncrementalSleepTimer timer(msecs);
654
655     forever {
656         if (!writeBuffer.isEmpty() && !_q_canWrite())
657             return false;
658         if (pipeWriter && pipeWriter->waitForWrite(0))
659             timer.resetIncrements();
660
661         if (processChannelMode != QProcess::ForwardedChannels
662                 && ((stdoutReader && stdoutReader->waitForReadyRead(0))
663                     || (stderrReader && stderrReader->waitForReadyRead(0))))
664             return true;
665
666         if (!pid)
667             return false;
668         if (WaitForSingleObject(pid->hProcess, 0) == WAIT_OBJECT_0) {
669             bool readyReadEmitted = drainOutputPipes(this);
670             _q_processDied();
671             return readyReadEmitted;
672         }
673
674         Sleep(timer.nextSleepTime());
675         if (timer.hasTimedOut())
676             break;
677     }
678
679     processError = QProcess::Timedout;
680     q->setErrorString(QProcess::tr("Process operation timed out"));
681     return false;
682 }
683
684 bool QProcessPrivate::waitForBytesWritten(int msecs)
685 {
686     Q_Q(QProcess);
687
688     QIncrementalSleepTimer timer(msecs);
689
690     forever {
691         // Check if we have any data pending: the pipe writer has
692         // bytes waiting to written, or it has written data since the
693         // last time we called pipeWriter->waitForWrite().
694         bool pendingDataInPipe = pipeWriter && (pipeWriter->bytesToWrite() || pipeWriter->hadWritten());
695
696         // If we don't have pending data, and our write buffer is
697         // empty, we fail.
698         if (!pendingDataInPipe && writeBuffer.isEmpty())
699             return false;
700
701         // If we don't have pending data and we do have data in our
702         // write buffer, try to flush that data over to the pipe
703         // writer.  Fail on error.
704         if (!pendingDataInPipe) {
705             if (!_q_canWrite())
706                 return false;
707         }
708
709         // Wait for the pipe writer to acknowledge that it has
710         // written. This will succeed if either the pipe writer has
711         // already written the data, or if it manages to write data
712         // within the given timeout. If the write buffer was non-empty
713         // and the pipeWriter is now dead, that means _q_canWrite()
714         // destroyed the writer after it successfully wrote the last
715         // batch.
716         if (!pipeWriter || pipeWriter->waitForWrite(0))
717             return true;
718
719         // If we wouldn't write anything, check if we can read stdout.
720         if (bytesAvailableFromStdout() != 0) {
721             _q_canReadStandardOutput();
722             timer.resetIncrements();
723         }
724
725         // Check if we can read stderr.
726         if (bytesAvailableFromStderr() != 0) {
727             _q_canReadStandardError();
728             timer.resetIncrements();
729         }
730
731         // Check if the process died while reading.
732         if (!pid)
733             return false;
734
735         // Wait for the process to signal any change in its state,
736         // such as incoming data, or if the process died.
737         if (WaitForSingleObject(pid->hProcess, 0) == WAIT_OBJECT_0) {
738             _q_processDied();
739             return false;
740         }
741
742         // Only wait for as long as we've been asked.
743         if (timer.hasTimedOut())
744             break;
745     }
746
747     processError = QProcess::Timedout;
748     q->setErrorString(QProcess::tr("Process operation timed out"));
749     return false;
750 }
751
752 bool QProcessPrivate::waitForFinished(int msecs)
753 {
754     Q_Q(QProcess);
755 #if defined QPROCESS_DEBUG
756     qDebug("QProcessPrivate::waitForFinished(%d)", msecs);
757 #endif
758
759     QIncrementalSleepTimer timer(msecs);
760
761     forever {
762         if (!writeBuffer.isEmpty() && !_q_canWrite())
763             return false;
764         if (pipeWriter && pipeWriter->waitForWrite(0))
765             timer.resetIncrements();
766         if (stdoutReader && stdoutReader->waitForReadyRead(0))
767             timer.resetIncrements();
768         if (stderrReader && stderrReader->waitForReadyRead(0))
769             timer.resetIncrements();
770
771         if (!pid) {
772             drainOutputPipes(this);
773             return true;
774         }
775
776         if (WaitForSingleObject(pid->hProcess, timer.nextSleepTime()) == WAIT_OBJECT_0) {
777             drainOutputPipes(this);
778             _q_processDied();
779             return true;
780         }
781
782         if (timer.hasTimedOut())
783             break;
784     }
785
786     processError = QProcess::Timedout;
787     q->setErrorString(QProcess::tr("Process operation timed out"));
788     return false;
789 }
790
791
792 void QProcessPrivate::findExitCode()
793 {
794     DWORD theExitCode;
795     if (GetExitCodeProcess(pid->hProcess, &theExitCode)) {
796         exitCode = theExitCode;
797         //### for now we assume a crash if exit code is less than -1 or the magic number
798         crashed = (exitCode == 0xf291 || (int)exitCode < 0);
799     }
800 }
801
802 void QProcessPrivate::flushPipeWriter()
803 {
804     if (pipeWriter && pipeWriter->bytesToWrite() > 0) {
805         pipeWriter->waitForWrite(ULONG_MAX);
806     }
807 }
808
809 qint64 QProcessPrivate::pipeWriterBytesToWrite() const
810 {
811     return pipeWriter ? pipeWriter->bytesToWrite() : qint64(0);
812 }
813
814 qint64 QProcessPrivate::writeToStdin(const char *data, qint64 maxlen)
815 {
816     Q_Q(QProcess);
817
818     if (!pipeWriter) {
819         pipeWriter = new QWindowsPipeWriter(stdinChannel.pipe[1], q);
820         pipeWriter->start();
821     }
822
823     return pipeWriter->write(data, maxlen);
824 }
825
826 bool QProcessPrivate::waitForWrite(int msecs)
827 {
828     Q_Q(QProcess);
829
830     if (!pipeWriter || pipeWriter->waitForWrite(msecs))
831         return true;
832
833     processError = QProcess::Timedout;
834     q->setErrorString(QProcess::tr("Process operation timed out"));
835     return false;
836 }
837
838 void QProcessPrivate::_q_notified()
839 {
840     notifier->stop();
841
842     if (!writeBuffer.isEmpty() && (!pipeWriter || pipeWriter->waitForWrite(0)))
843         _q_canWrite();
844
845     if (processState != QProcess::NotRunning)
846         notifier->start(NOTIFYTIMEOUT);
847 }
848
849 bool QProcessPrivate::startDetached(const QString &program, const QStringList &arguments, const QString &workingDir, qint64 *pid)
850 {
851     QString args = qt_create_commandline(program, arguments);
852     bool success = false;
853     PROCESS_INFORMATION pinfo;
854
855     STARTUPINFOW startupInfo = { sizeof( STARTUPINFO ), 0, 0, 0,
856                                  (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT,
857                                  (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT,
858                                  0, 0, 0, 0, 0, 0, 0, 0, 0, 0
859                                };
860     success = CreateProcess(0, (wchar_t*)args.utf16(),
861                             0, 0, FALSE, CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_CONSOLE, 0,
862                             workingDir.isEmpty() ? 0 : (wchar_t*)workingDir.utf16(),
863                             &startupInfo, &pinfo);
864
865     if (success) {
866         CloseHandle(pinfo.hThread);
867         CloseHandle(pinfo.hProcess);
868         if (pid)
869             *pid = pinfo.dwProcessId;
870     }
871
872     return success;
873 }
874
875 QT_END_NAMESPACE
876
877 #endif // QT_NO_PROCESS