From 96d82021460c3435e9c2516f98845ea3b8422c19 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Fri, 14 Feb 2020 13:51:44 +0100 Subject: [PATCH] Do not use recursive mkdir() - it's not thread-safe --- src/Cache/FileCacheStorage.php | 36 ++++++++++++++++++++++------------ src/Command/CommandHelper.php | 8 +++++++- src/Testing/TestCase.php | 2 +- tests/bootstrap.php | 7 ++++++- 4 files changed, 38 insertions(+), 15 deletions(-) diff --git a/src/Cache/FileCacheStorage.php b/src/Cache/FileCacheStorage.php index 0895758778..84b5219ad7 100644 --- a/src/Cache/FileCacheStorage.php +++ b/src/Cache/FileCacheStorage.php @@ -15,13 +15,18 @@ public function __construct(string $directory) $this->directory = $directory; } + public function makeRootDir(): void + { + $this->makeDir($this->directory); + } + private function makeDir(string $directory): void { if (is_dir($directory)) { return; } - $result = @mkdir($directory, 0777, true); + $result = @mkdir($directory, 0777); if ($result === false) { clearstatcache(); if (is_dir($directory)) { @@ -41,7 +46,7 @@ private function makeDir(string $directory): void public function load(string $key, string $variableKey) { return (function (string $key, string $variableKey) { - $filePath = $this->getFilePath($key); + [,, $filePath] = $this->getFilePaths($key); if (!is_file($filePath)) { return null; } @@ -66,8 +71,9 @@ public function load(string $key, string $variableKey) */ public function save(string $key, string $variableKey, $data): void { - $path = $this->getFilePath($key); - $this->makeDir(dirname($path)); + [$firstDirectory, $secondDirectory, $path] = $this->getFilePaths($key); + $this->makeDir($firstDirectory); + $this->makeDir($secondDirectory); $tmpPath = sprintf('%s/%s.tmp', $this->directory, Random::generate()); $tmpSuccess = @file_put_contents( @@ -92,16 +98,22 @@ public function save(string $key, string $variableKey, $data): void } } - private function getFilePath(string $key): string + /** + * @param string $key + * @return array{string, string, string} + */ + private function getFilePaths(string $key): array { $keyHash = sha1($key); - return sprintf( - '%s/%s/%s/%s.php', - $this->directory, - substr($keyHash, 0, 2), - substr($keyHash, 2, 2), - $keyHash - ); + $firstDirectory = sprintf('%s/%s', $this->directory, substr($keyHash, 0, 2)); + $secondDirectory = sprintf('%s/%s', $firstDirectory, substr($keyHash, 2, 2)); + $filePath = sprintf('%s/%s.php', $secondDirectory, $keyHash); + + return [ + $firstDirectory, + $secondDirectory, + $filePath, + ]; } } diff --git a/src/Command/CommandHelper.php b/src/Command/CommandHelper.php index bf5cacc8f7..23e63fcd74 100644 --- a/src/Command/CommandHelper.php +++ b/src/Command/CommandHelper.php @@ -9,6 +9,7 @@ use Nette\Schema\Processor; use Nette\Utils\Strings; use Nette\Utils\Validators; +use PHPStan\Cache\FileCacheStorage; use PHPStan\Command\Symfony\SymfonyOutput; use PHPStan\Command\Symfony\SymfonyStyle; use PHPStan\DependencyInjection\ContainerFactory; @@ -208,7 +209,7 @@ public static function begin( if (!isset($tmpDir)) { $tmpDir = sys_get_temp_dir() . '/phpstan'; - if (!@mkdir($tmpDir, 0777, true) && !is_dir($tmpDir)) { + if (!@mkdir($tmpDir, 0777) && !is_dir($tmpDir)) { $errorOutput->writeLineFormatted(sprintf('Cannot create a temp directory %s', $tmpDir)); throw new \PHPStan\Command\InceptionNotSuccessfulException(); } @@ -327,6 +328,11 @@ public static function begin( } } + $fileCacheStorage = $container->getService('cacheStorage')->makeRootDir(); + if ($fileCacheStorage instanceof FileCacheStorage) { + $fileCacheStorage->makeRootDir(); + } + /** @var FileFinder $fileFinder */ $fileFinder = $container->getByType(FileFinder::class); diff --git a/src/Testing/TestCase.php b/src/Testing/TestCase.php index 8cdb70bef0..57689ff809 100644 --- a/src/Testing/TestCase.php +++ b/src/Testing/TestCase.php @@ -72,7 +72,7 @@ public static function getContainer(): Container if (!isset(self::$containers[$cacheKey])) { $tmpDir = sys_get_temp_dir() . '/phpstan-tests'; - if (!@mkdir($tmpDir, 0777, true) && !is_dir($tmpDir)) { + if (!@mkdir($tmpDir, 0777) && !is_dir($tmpDir)) { self::fail(sprintf('Cannot create temp directory %s', $tmpDir)); } diff --git a/tests/bootstrap.php b/tests/bootstrap.php index a22ff1ffed..1438356f82 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -1,5 +1,6 @@ getService('cacheStorage'); +if ($fileCacheStorage instanceof FileCacheStorage) { + $fileCacheStorage->makeRootDir(); +}