From 739664fa025ee2b155eba97557e4258d2bf0ff1a Mon Sep 17 00:00:00 2001
From: Helmut Hummel <typo3@helhum.io>
Date: Thu, 7 Sep 2023 11:51:52 +0200
Subject: [PATCH] [BUGFIX] Do not try to create symlinks on Windows

When a junction already exists on Windows, it is tried
to create a symlink, because of a missing OS check.

While this works as errors are ignored, it is
an unnecessary filesystem call.

Therefore the code is changed to only emit
the appropriate filesystem operations per OS.

Resolves: #101871
Related: #98434
Related: #98447
Releases: main, 12.4, 11.5
Change-Id: Ifafadceae3742da23fd1a40e5aab50074e60313c
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/80924
Reviewed-by: Benjamin Franzke <ben@bnf.dev>
Tested-by: core-ci <typo3@b13.com>
Tested-by: Benjamin Franzke <ben@bnf.dev>
---
 .../Composer/PackageArtifactBuilder.php       | 28 ++++++++++++++++---
 1 file changed, 24 insertions(+), 4 deletions(-)

diff --git a/typo3/sysext/core/Classes/Composer/PackageArtifactBuilder.php b/typo3/sysext/core/Classes/Composer/PackageArtifactBuilder.php
index 21ae3e895c80..a457143d1d97 100644
--- a/typo3/sysext/core/Classes/Composer/PackageArtifactBuilder.php
+++ b/typo3/sysext/core/Classes/Composer/PackageArtifactBuilder.php
@@ -284,14 +284,34 @@ class PackageArtifactBuilder extends PackageManager implements InstallerScript
             [$relativePrefix] = explode('Resources/Public', $relativePath);
             $publicResourcesPath = $this->fileSystem->normalizePath($this->config->get('web-dir') . '/_assets/' . md5($relativePrefix));
             $this->fileSystem->ensureDirectoryExists(dirname($publicResourcesPath));
-            if (Platform::isWindows() && !$this->fileSystem->isJunction($publicResourcesPath)) {
-                $this->fileSystem->junction($fileSystemResourcesPath, $publicResourcesPath);
-            } elseif (!$this->fileSystem->isSymlinkedDirectory($publicResourcesPath)) {
-                $this->fileSystem->relativeSymlink($fileSystemResourcesPath, $publicResourcesPath);
+            if (Platform::isWindows()) {
+                $this->ensureJunctionExists($fileSystemResourcesPath, $publicResourcesPath);
+            } else {
+                $this->ensureSymlinkExists($fileSystemResourcesPath, $publicResourcesPath);
             }
         }
     }
 
+    private function ensureJunctionExists(string $target, string $junction): void
+    {
+        if (!$this->fileSystem->isJunction($junction)) {
+            // Cleanup a possible symlink that might have been installed by ourselves prior to #98434
+            // Note: Unprivileged deletion of symlinks is allowed, even if they were created by a
+            // privileged user
+            if (is_link($junction)) {
+                $this->fileSystem->unlink($junction);
+            }
+            $this->fileSystem->junction($target, $junction);
+        }
+    }
+
+    private function ensureSymlinkExists(string $target, string $link): void
+    {
+        if (!$this->fileSystem->isSymlinkedDirectory($link)) {
+            $this->fileSystem->relativeSymlink($target, $link);
+        }
+    }
+
     /**
      * Add extensions, that are located in typo3conf/ext, but are not installed by Composer
      * to the list of known packages. This is now deprecated and will be removed with TYPO3 12.
-- 
GitLab