diff --git a/src/Symfony/Component/Process/Pipes/WindowsPipes.php b/src/Symfony/Component/Process/Pipes/WindowsPipes.php index f81f65facae1..0b2a76387fdf 100644 --- a/src/Symfony/Component/Process/Pipes/WindowsPipes.php +++ b/src/Symfony/Component/Process/Pipes/WindowsPipes.php @@ -28,6 +28,7 @@ class WindowsPipes extends AbstractPipes { private $files = array(); private $fileHandles = array(); + private $lockHandles = array(); private $readBytes = array( Process::STDOUT => 0, Process::STDERR => 0, @@ -47,31 +48,33 @@ public function __construct($disableOutput, $input) Process::STDOUT => Process::OUT, Process::STDERR => Process::ERR, ); - $tmpCheck = false; $tmpDir = sys_get_temp_dir(); $lastError = 'unknown reason'; set_error_handler(function ($type, $msg) use (&$lastError) { $lastError = $msg; }); for ($i = 0;; ++$i) { foreach ($pipes as $pipe => $name) { $file = sprintf('%s\\sf_proc_%02X.%s', $tmpDir, $i, $name); - if (file_exists($file) && !unlink($file)) { - continue 2; - } - $h = fopen($file, 'xb'); - if (!$h) { - $error = $lastError; - if ($tmpCheck || $tmpCheck = unlink(tempnam(false, 'sf_check_'))) { - continue; - } + + if (!$h = fopen($file.'.lock', 'w')) { restore_error_handler(); - throw new RuntimeException(sprintf('A temporary file could not be opened to write the process output: %s', $error)); + throw new RuntimeException(sprintf('A temporary file could not be opened to write the process output: %s', $lastError)); } - if (!$h || !$this->fileHandles[$pipe] = fopen($file, 'rb')) { + if (!flock($h, LOCK_EX | LOCK_NB)) { continue 2; } - if (isset($this->files[$pipe])) { - unlink($this->files[$pipe]); + if (isset($this->lockHandles[$pipe])) { + flock($this->lockHandles[$pipe], LOCK_UN); + fclose($this->lockHandles[$pipe]); } + $this->lockHandles[$pipe] = $h; + + if (!fclose(fopen($file, 'w')) || !$h = fopen($file, 'r')) { + flock($this->lockHandles[$pipe], LOCK_UN); + fclose($this->lockHandles[$pipe]); + unset($this->lockHandles[$pipe]); + continue 2; + } + $this->fileHandles[$pipe] = $h; $this->files[$pipe] = $file; } break; @@ -85,7 +88,6 @@ public function __construct($disableOutput, $input) public function __destruct() { $this->close(); - $this->removeFiles(); } /** @@ -145,8 +147,11 @@ public function readAndWrite($blocking, $close = false) $read[$type] = $data; } if ($close) { + ftruncate($fileHandle, 0); fclose($fileHandle); - unset($this->fileHandles[$type]); + flock($this->lockHandles[$type], LOCK_UN); + fclose($this->lockHandles[$type]); + unset($this->fileHandles[$type], $this->lockHandles[$type]); } } @@ -167,10 +172,13 @@ public function areOpen() public function close() { parent::close(); - foreach ($this->fileHandles as $handle) { + foreach ($this->fileHandles as $type => $handle) { + ftruncate($handle, 0); fclose($handle); + flock($this->lockHandles[$type], LOCK_UN); + fclose($this->lockHandles[$type]); } - $this->fileHandles = array(); + $this->fileHandles = $this->lockHandles = array(); } /** @@ -185,17 +193,4 @@ public static function create(Process $process, $input) { return new static($process->isOutputDisabled(), $input); } - - /** - * Removes temporary files. - */ - private function removeFiles() - { - foreach ($this->files as $filename) { - if (file_exists($filename)) { - @unlink($filename); - } - } - $this->files = array(); - } }