From 2dbe66ad203460453c49f7011e539a806dfde9a8 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 29 Mar 2022 18:57:30 +0200 Subject: [PATCH] Fix deletion of corrupt 0-bytes zip archives from the cache, fixes #10580 (#10666) --- src/Composer/Downloader/ArchiveDownloader.php | 4 +++- src/Composer/Downloader/ZipDownloader.php | 9 ++++++++- .../Test/Downloader/ZipDownloaderTest.php | 19 ++++++++++++------- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/Composer/Downloader/ArchiveDownloader.php b/src/Composer/Downloader/ArchiveDownloader.php index 570de63d8..4f2467d71 100644 --- a/src/Composer/Downloader/ArchiveDownloader.php +++ b/src/Composer/Downloader/ArchiveDownloader.php @@ -120,7 +120,9 @@ abstract class ArchiveDownloader extends FileDownloader } return $promise->then(function () use ($self, $package, $filesystem, $fileName, $temporaryDir, $path) { - $filesystem->unlink($fileName); + if (file_exists($fileName)) { + $filesystem->unlink($fileName); + } /** * Returns the folder content, excluding .DS_Store diff --git a/src/Composer/Downloader/ZipDownloader.php b/src/Composer/Downloader/ZipDownloader.php index a86d1da6b..fe1bfdc69 100644 --- a/src/Composer/Downloader/ZipDownloader.php +++ b/src/Composer/Downloader/ZipDownloader.php @@ -184,7 +184,12 @@ class ZipDownloader extends ArchiveDownloader $zipArchive = $this->zipArchiveObject ?: new ZipArchive(); try { - if (true === ($retval = $zipArchive->open($file))) { + if (!file_exists($file) || ($filesize = filesize($file)) === false || $filesize === 0) { + $retval = -1; + } else { + $retval = $zipArchive->open($file); + } + if (true === $retval) { $extractResult = $zipArchive->extractTo($path); if (true === $extractResult) { @@ -251,6 +256,8 @@ class ZipDownloader extends ArchiveDownloader return sprintf("Zip read error (%s)", $file); case ZipArchive::ER_SEEK: return sprintf("Zip seek error (%s)", $file); + case -1: + return sprintf("'%s' is a corrupted zip archive (0 bytes), try again.", $file); default: return sprintf("'%s' is not a valid zip archive, got error code: %s", $file, $retval); } diff --git a/tests/Composer/Test/Downloader/ZipDownloaderTest.php b/tests/Composer/Test/Downloader/ZipDownloaderTest.php index b8e148f2b..0db2da237 100644 --- a/tests/Composer/Test/Downloader/ZipDownloaderTest.php +++ b/tests/Composer/Test/Downloader/ZipDownloaderTest.php @@ -31,6 +31,8 @@ class ZipDownloaderTest extends TestCase private $config; /** @var \Composer\Package\PackageInterface&\PHPUnit\Framework\MockObject\MockObject */ private $package; + /** @var string */ + private $filename; public function setUp() { @@ -40,6 +42,9 @@ class ZipDownloaderTest extends TestCase $dlConfig = $this->getMockBuilder('Composer\Config')->getMock(); $this->httpDownloader = new HttpDownloader($this->io, $dlConfig); $this->package = $this->getMockBuilder('Composer\Package\PackageInterface')->getMock(); + + $this->filename = $this->testDir.'/composer-test.zip'; + file_put_contents($this->filename, 'zip'); } public function tearDown() @@ -123,7 +128,7 @@ class ZipDownloaderTest extends TestCase ->will($this->returnValue(false)); $this->setPrivateProperty('zipArchiveObject', $zipArchive, $downloader); - $promise = $downloader->extract($this->package, 'testfile.zip', 'vendor/dir'); + $promise = $downloader->extract($this->package, $this->filename, 'vendor/dir'); $this->wait($promise); } @@ -145,7 +150,7 @@ class ZipDownloaderTest extends TestCase ->will($this->throwException(new \ErrorException('Not a directory'))); $this->setPrivateProperty('zipArchiveObject', $zipArchive, $downloader); - $promise = $downloader->extract($this->package, 'testfile.zip', 'vendor/dir'); + $promise = $downloader->extract($this->package, $this->filename, 'vendor/dir'); $this->wait($promise); } @@ -166,7 +171,7 @@ class ZipDownloaderTest extends TestCase ->will($this->returnValue(true)); $this->setPrivateProperty('zipArchiveObject', $zipArchive, $downloader); - $promise = $downloader->extract($this->package, 'testfile.zip', 'vendor/dir'); + $promise = $downloader->extract($this->package, $this->filename, 'vendor/dir'); $this->wait($promise); } @@ -194,7 +199,7 @@ class ZipDownloaderTest extends TestCase ->will($this->returnValue(\React\Promise\resolve($procMock))); $downloader = new MockedZipDownloader($this->io, $this->config, $this->httpDownloader, null, null, null, $processExecutor); - $promise = $downloader->extract($this->package, 'testfile.zip', 'vendor/dir'); + $promise = $downloader->extract($this->package, $this->filename, 'vendor/dir'); $this->wait($promise); } @@ -221,7 +226,7 @@ class ZipDownloaderTest extends TestCase ->will($this->returnValue(\React\Promise\resolve($procMock))); $downloader = new MockedZipDownloader($this->io, $this->config, $this->httpDownloader, null, null, null, $processExecutor); - $promise = $downloader->extract($this->package, 'testfile.zip', 'vendor/dir'); + $promise = $downloader->extract($this->package, $this->filename, 'vendor/dir'); $this->wait($promise); } @@ -260,7 +265,7 @@ class ZipDownloaderTest extends TestCase $downloader = new MockedZipDownloader($this->io, $this->config, $this->httpDownloader, null, null, null, $processExecutor); $this->setPrivateProperty('zipArchiveObject', $zipArchive, $downloader); - $promise = $downloader->extract($this->package, 'testfile.zip', 'vendor/dir'); + $promise = $downloader->extract($this->package, $this->filename, 'vendor/dir'); $this->wait($promise); } @@ -300,7 +305,7 @@ class ZipDownloaderTest extends TestCase $downloader = new MockedZipDownloader($this->io, $this->config, $this->httpDownloader, null, null, null, $processExecutor); $this->setPrivateProperty('zipArchiveObject', $zipArchive, $downloader); - $promise = $downloader->extract($this->package, 'testfile.zip', 'vendor/dir'); + $promise = $downloader->extract($this->package, $this->filename, 'vendor/dir'); $this->wait($promise); }