bug #28689 [Process] fix locking of pipe files on Windows (nicolas-grekas)
This PR was merged into the 2.8 branch.
Discussion
----------
[Process] fix locking of pipe files on Windows
| Q | A
| ------------- | ---
| Branch? | 2.8
| Bug fix? | yes
| New feature? | no
| BC breaks? | no
| Deprecations? | no
| Tests pass? | yes
| Fixed tickets | #28655
| License | MIT
| Doc PR | -
Commits
-------
d64bd3b181
[Process] fix locking of pipe files on Windows
This commit is contained in:
commit
9fdc64b479
@ -28,6 +28,7 @@ class WindowsPipes extends AbstractPipes
|
|||||||
{
|
{
|
||||||
private $files = array();
|
private $files = array();
|
||||||
private $fileHandles = array();
|
private $fileHandles = array();
|
||||||
|
private $lockHandles = array();
|
||||||
private $readBytes = array(
|
private $readBytes = array(
|
||||||
Process::STDOUT => 0,
|
Process::STDOUT => 0,
|
||||||
Process::STDERR => 0,
|
Process::STDERR => 0,
|
||||||
@ -47,31 +48,33 @@ class WindowsPipes extends AbstractPipes
|
|||||||
Process::STDOUT => Process::OUT,
|
Process::STDOUT => Process::OUT,
|
||||||
Process::STDERR => Process::ERR,
|
Process::STDERR => Process::ERR,
|
||||||
);
|
);
|
||||||
$tmpCheck = false;
|
|
||||||
$tmpDir = sys_get_temp_dir();
|
$tmpDir = sys_get_temp_dir();
|
||||||
$lastError = 'unknown reason';
|
$lastError = 'unknown reason';
|
||||||
set_error_handler(function ($type, $msg) use (&$lastError) { $lastError = $msg; });
|
set_error_handler(function ($type, $msg) use (&$lastError) { $lastError = $msg; });
|
||||||
for ($i = 0;; ++$i) {
|
for ($i = 0;; ++$i) {
|
||||||
foreach ($pipes as $pipe => $name) {
|
foreach ($pipes as $pipe => $name) {
|
||||||
$file = sprintf('%s\\sf_proc_%02X.%s', $tmpDir, $i, $name);
|
$file = sprintf('%s\\sf_proc_%02X.%s', $tmpDir, $i, $name);
|
||||||
if (file_exists($file) && !unlink($file)) {
|
|
||||||
continue 2;
|
if (!$h = fopen($file.'.lock', 'w')) {
|
||||||
}
|
|
||||||
$h = fopen($file, 'xb');
|
|
||||||
if (!$h) {
|
|
||||||
$error = $lastError;
|
|
||||||
if ($tmpCheck || $tmpCheck = unlink(tempnam(false, 'sf_check_'))) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
restore_error_handler();
|
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;
|
continue 2;
|
||||||
}
|
}
|
||||||
if (isset($this->files[$pipe])) {
|
if (isset($this->lockHandles[$pipe])) {
|
||||||
unlink($this->files[$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;
|
$this->files[$pipe] = $file;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -85,7 +88,6 @@ class WindowsPipes extends AbstractPipes
|
|||||||
public function __destruct()
|
public function __destruct()
|
||||||
{
|
{
|
||||||
$this->close();
|
$this->close();
|
||||||
$this->removeFiles();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -145,8 +147,11 @@ class WindowsPipes extends AbstractPipes
|
|||||||
$read[$type] = $data;
|
$read[$type] = $data;
|
||||||
}
|
}
|
||||||
if ($close) {
|
if ($close) {
|
||||||
|
ftruncate($fileHandle, 0);
|
||||||
fclose($fileHandle);
|
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 @@ class WindowsPipes extends AbstractPipes
|
|||||||
public function close()
|
public function close()
|
||||||
{
|
{
|
||||||
parent::close();
|
parent::close();
|
||||||
foreach ($this->fileHandles as $handle) {
|
foreach ($this->fileHandles as $type => $handle) {
|
||||||
|
ftruncate($handle, 0);
|
||||||
fclose($handle);
|
fclose($handle);
|
||||||
|
flock($this->lockHandles[$type], LOCK_UN);
|
||||||
|
fclose($this->lockHandles[$type]);
|
||||||
}
|
}
|
||||||
$this->fileHandles = array();
|
$this->fileHandles = $this->lockHandles = array();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -185,17 +193,4 @@ class WindowsPipes extends AbstractPipes
|
|||||||
{
|
{
|
||||||
return new static($process->isOutputDisabled(), $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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user