From a17096f5ba3efa6334cf9cfffae53ef1a2242969 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 22 Aug 2024 12:44:48 +0200 Subject: [PATCH] Fix copy() sometimes failing on virtualbox shared folders, fixes #12057 --- src/Composer/Cache.php | 4 ++-- src/Composer/Util/Filesystem.php | 25 ++++++++++++++++++++++++- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/Composer/Cache.php b/src/Composer/Cache.php index 2e6f2edad..e18715f47 100644 --- a/src/Composer/Cache.php +++ b/src/Composer/Cache.php @@ -198,7 +198,7 @@ class Cache $this->io->writeError('Writing '.$this->root . $file.' into cache from '.$source); } - return copy($source, $this->root . $file); + return $this->filesystem->copy($source, $this->root . $file); } return false; @@ -224,7 +224,7 @@ class Cache $this->io->writeError('Reading '.$this->root . $file.' from cache', true, IOInterface::DEBUG); - return copy($this->root . $file, $target); + return $this->filesystem->copy($this->root . $file, $target); } } diff --git a/src/Composer/Util/Filesystem.php b/src/Composer/Util/Filesystem.php index 8aa743c71..099747add 100644 --- a/src/Composer/Util/Filesystem.php +++ b/src/Composer/Util/Filesystem.php @@ -13,6 +13,7 @@ namespace Composer\Util; use Composer\Pcre\Preg; +use ErrorException; use React\Promise\PromiseInterface; use RecursiveDirectoryIterator; use RecursiveIteratorIterator; @@ -367,7 +368,29 @@ class Filesystem $target = $this->normalizePath($target); if (!is_dir($source)) { - return copy($source, $target); + try { + return copy($source, $target); + } catch (ErrorException $e) { + // if copy fails we attempt to copy it manually as this can help bypass issues with VirtualBox shared folders + // see https://github.com/composer/composer/issues/12057 + if (str_contains($e->getMessage(), 'Bad address')) { + $sourceHandle = fopen($source, 'r'); + $targetHandle = fopen($target, 'w'); + if (false === $sourceHandle || false === $targetHandle) { + throw $e; + } + while (!feof($sourceHandle)) { + if (false === fwrite($targetHandle, (string) fread($sourceHandle, 1024 * 1024))) { + throw $e; + } + } + fclose($sourceHandle); + fclose($targetHandle); + + return true; + } + throw $e; + } } $it = new RecursiveDirectoryIterator($source, RecursiveDirectoryIterator::SKIP_DOTS);