From e829ff80bc7312d7fa70fbd7be441863eb6dcc61 Mon Sep 17 00:00:00 2001 From: Ilya Urvachev Date: Tue, 29 Dec 2020 23:57:29 +0300 Subject: [PATCH 1/3] feat(Cache): make cache writes more atomic Fixes #9568 --- src/Composer/Cache.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Composer/Cache.php b/src/Composer/Cache.php index c4bb4b2eb..df45e66ed 100644 --- a/src/Composer/Cache.php +++ b/src/Composer/Cache.php @@ -115,7 +115,8 @@ class Cache $this->io->writeError('Writing '.$this->root . $file.' into cache', true, IOInterface::DEBUG); try { - return file_put_contents($this->root . $file.'.tmp', $contents) !== false && rename($this->root . $file . '.tmp', $this->root . $file); + $tempFileName = $this->root . $file . uniqid('.tmp.', true); + return file_put_contents($tempFileName, $contents) !== false && rename($tempFileName, $this->root . $file); } catch (\ErrorException $e) { $this->io->writeError('Failed to write into cache: '.$e->getMessage().'', true, IOInterface::DEBUG); if (preg_match('{^file_put_contents\(\): Only ([0-9]+) of ([0-9]+) bytes written}', $e->getMessage(), $m)) { From ab6e0fa9611ddd6f25e311018b205e1c659a5717 Mon Sep 17 00:00:00 2001 From: Ilya Urvachev Date: Wed, 6 Jan 2021 02:17:34 +0300 Subject: [PATCH 2/3] use `.tmp` extension for temporary files also updated `catch` block to use temporary filename --- src/Composer/Cache.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Composer/Cache.php b/src/Composer/Cache.php index df45e66ed..fe2b97c59 100644 --- a/src/Composer/Cache.php +++ b/src/Composer/Cache.php @@ -114,21 +114,21 @@ class Cache $this->io->writeError('Writing '.$this->root . $file.' into cache', true, IOInterface::DEBUG); + $tempFileName = $this->root . $file . uniqid('.', true) . '.tmp'; try { - $tempFileName = $this->root . $file . uniqid('.tmp.', true); return file_put_contents($tempFileName, $contents) !== false && rename($tempFileName, $this->root . $file); } catch (\ErrorException $e) { $this->io->writeError('Failed to write into cache: '.$e->getMessage().'', true, IOInterface::DEBUG); if (preg_match('{^file_put_contents\(\): Only ([0-9]+) of ([0-9]+) bytes written}', $e->getMessage(), $m)) { // Remove partial file. - unlink($this->root . $file); + unlink($tempFileName); $message = sprintf( 'Writing %1$s into cache failed after %2$u of %3$u bytes written, only %4$u bytes of free space available', - $this->root . $file, + $tempFileName, $m[1], $m[2], - @disk_free_space($this->root . dirname($file)) + @disk_free_space($this->root . dirname($tempFileName)) ); $this->io->writeError($message); From cee8e3e3b7f9239d3f66b489ae10b8f73cb6b7e0 Mon Sep 17 00:00:00 2001 From: Ilya Urvachev Date: Wed, 6 Jan 2021 15:21:45 +0300 Subject: [PATCH 3/3] fix `dirname` usage --- src/Composer/Cache.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Composer/Cache.php b/src/Composer/Cache.php index fe2b97c59..9590693ff 100644 --- a/src/Composer/Cache.php +++ b/src/Composer/Cache.php @@ -128,7 +128,7 @@ class Cache $tempFileName, $m[1], $m[2], - @disk_free_space($this->root . dirname($tempFileName)) + @disk_free_space(dirname($tempFileName)) ); $this->io->writeError($message);