diff --git a/src/Symfony/Component/Filesystem/Filesystem.php b/src/Symfony/Component/Filesystem/Filesystem.php index 49c6f70d62..d620f8dde8 100644 --- a/src/Symfony/Component/Filesystem/Filesystem.php +++ b/src/Symfony/Component/Filesystem/Filesystem.php @@ -162,6 +162,12 @@ class Filesystem } elseif (!\is_array($files)) { $files = [$files]; } + + self::doRemove($files, false); + } + + private static function doRemove(array $files, bool $isRecursive): void + { $files = array_reverse($files); foreach ($files as $file) { if (is_link($file)) { @@ -170,10 +176,35 @@ class Filesystem throw new IOException(sprintf('Failed to remove symlink "%s": ', $file).self::$lastError); } } elseif (is_dir($file)) { - $this->remove(new \FilesystemIterator($file, \FilesystemIterator::CURRENT_AS_PATHNAME | \FilesystemIterator::SKIP_DOTS)); + if (!$isRecursive) { + $tmpName = \dirname(realpath($file)).'/.'.strrev(strtr(base64_encode(random_bytes(2)), '/=', '-.')); - if (!self::box('rmdir', $file) && file_exists($file)) { - throw new IOException(sprintf('Failed to remove directory "%s": ', $file).self::$lastError); + if (file_exists($tmpName)) { + try { + self::doRemove([$tmpName], true); + } catch (IOException $e) { + } + } + + if (!file_exists($tmpName) && self::box('rename', $file, $tmpName)) { + $origFile = $file; + $file = $tmpName; + } else { + $origFile = null; + } + } + + $files = new \FilesystemIterator($file, \FilesystemIterator::CURRENT_AS_PATHNAME | \FilesystemIterator::SKIP_DOTS); + self::doRemove(iterator_to_array($files, true), true); + + if (!self::box('rmdir', $file) && file_exists($file) && !$isRecursive) { + $lastError = self::$lastError; + + if (null !== $origFile && self::box('rename', $file, $origFile)) { + $file = $origFile; + } + + throw new IOException(sprintf('Failed to remove directory "%s": ', $file).$lastError); } } elseif (!self::box('unlink', $file) && (false !== strpos(self::$lastError, 'Permission denied') || file_exists($file))) { throw new IOException(sprintf('Failed to remove file "%s": ', $file).self::$lastError);