From 119c4d91f3f5ee992df27da84d047b9ff69852a3 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/+/80904
Tested-by: core-ci <typo3@b13.com>
Tested-by: Benjamin Franzke <ben@bnf.dev>
Reviewed-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 88f32614ff3c..cd7318b2f472 100644
--- a/typo3/sysext/core/Classes/Composer/PackageArtifactBuilder.php
+++ b/typo3/sysext/core/Classes/Composer/PackageArtifactBuilder.php
@@ -275,11 +275,31 @@ 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);
+        }
+    }
 }
-- 
GitLab