From 25381a2809d43348ed2ad0be0d45d433238c096e Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Thu, 25 May 2017 11:59:42 +0200 Subject: [PATCH] [Filesystem] improve error handling in lock() --- .../Component/Filesystem/LockHandler.php | 9 +++-- .../Filesystem/Tests/LockHandlerTest.php | 40 +++++++++++++++++++ 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Filesystem/LockHandler.php b/src/Symfony/Component/Filesystem/LockHandler.php index 67e6f8f522..3496faae21 100644 --- a/src/Symfony/Component/Filesystem/LockHandler.php +++ b/src/Symfony/Component/Filesystem/LockHandler.php @@ -68,8 +68,12 @@ class LockHandler return true; } + $error = null; + // Silence error reporting - set_error_handler(function () {}); + set_error_handler(function ($errno, $msg) use (&$error) { + $error = $msg; + }); if (!$this->handle = fopen($this->file, 'r')) { if ($this->handle = fopen($this->file, 'x')) { @@ -82,8 +86,7 @@ class LockHandler restore_error_handler(); if (!$this->handle) { - $error = error_get_last(); - throw new IOException($error['message'], 0, null, $this->file); + throw new IOException($error, 0, null, $this->file); } // On Windows, even if PHP doc says the contrary, LOCK_NB works, see diff --git a/src/Symfony/Component/Filesystem/Tests/LockHandlerTest.php b/src/Symfony/Component/Filesystem/Tests/LockHandlerTest.php index 1fc2ebc0c1..0791cebc69 100644 --- a/src/Symfony/Component/Filesystem/Tests/LockHandlerTest.php +++ b/src/Symfony/Component/Filesystem/Tests/LockHandlerTest.php @@ -12,6 +12,8 @@ namespace Symfony\Component\Filesystem\Tests; use PHPUnit\Framework\TestCase; +use Symfony\Component\Filesystem\Exception\IOException; +use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\Filesystem\LockHandler; class LockHandlerTest extends TestCase @@ -40,6 +42,44 @@ class LockHandlerTest extends TestCase new LockHandler('lock', '/'); } + public function testErrorHandlingInLockIfLockPathBecomesUnwritable() + { + // skip test on Windows; PHP can't easily set file as unreadable on Windows + if ('\\' === DIRECTORY_SEPARATOR) { + $this->markTestSkipped('This test cannot run on Windows.'); + } + + $lockPath = sys_get_temp_dir().'/'.uniqid(); + $e = null; + $wrongMessage = null; + + try { + mkdir($lockPath); + + $lockHandler = new LockHandler('lock', $lockPath); + + chmod($lockPath, 0444); + + $lockHandler->lock(); + } catch (IOException $e) { + if (false === strpos($e->getMessage(), 'Permission denied')) { + $wrongMessage = $e->getMessage(); + } else { + $this->addToAssertionCount(1); + } + } catch (\Exception $e) { + } catch (\Throwable $e) { + } + + if (is_dir($lockPath)) { + $fs = new Filesystem(); + $fs->remove($lockPath); + } + + $this->assertInstanceOf('Symfony\Component\Filesystem\Exception\IOException', $e, sprintf('Expected IOException to be thrown, got %s instead.', get_class($e))); + $this->assertNull($wrongMessage, sprintf('Expected exception message to contain "Permission denied", got "%s" instead.', $wrongMessage)); + } + public function testConstructSanitizeName() { $lock = new LockHandler('');