diff --git a/typo3/sysext/extensionmanager/Classes/Controller/ActionController.php b/typo3/sysext/extensionmanager/Classes/Controller/ActionController.php
index 62abb871e9514d9ed219b2fe781487cfef0fd441..00b1c6a13f5d599459b4e0e72412656b3653c85e 100644
--- a/typo3/sysext/extensionmanager/Classes/Controller/ActionController.php
+++ b/typo3/sysext/extensionmanager/Classes/Controller/ActionController.php
@@ -27,7 +27,6 @@ use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
 use TYPO3\CMS\Extensionmanager\Domain\Model\Extension;
 use TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException;
 use TYPO3\CMS\Extensionmanager\Service\ExtensionManagementService;
-use TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility;
 use TYPO3\CMS\Extensionmanager\Utility\InstallUtility;
 
 /**
@@ -42,11 +41,6 @@ class ActionController extends AbstractController
      */
     protected $installUtility;
 
-    /**
-     * @var FileHandlingUtility
-     */
-    protected $fileHandlingUtility;
-
     /**
      * @var ExtensionManagementService
      */
@@ -60,14 +54,6 @@ class ActionController extends AbstractController
         $this->installUtility = $installUtility;
     }
 
-    /**
-     * @param FileHandlingUtility $fileHandlingUtility
-     */
-    public function injectFileHandlingUtility(FileHandlingUtility $fileHandlingUtility)
-    {
-        $this->fileHandlingUtility = $fileHandlingUtility;
-    }
-
     /**
      * @param ExtensionManagementService $managementService
      */
@@ -157,7 +143,7 @@ class ActionController extends AbstractController
      */
     protected function downloadExtensionZipAction($extension)
     {
-        $fileName = $this->fileHandlingUtility->createZipFileFromExtension($extension);
+        $fileName = $this->createZipFileFromExtension($extension);
         $this->sendZipFileToBrowserAndDelete($fileName);
     }
 
@@ -193,4 +179,66 @@ class ActionController extends AbstractController
 
         $this->redirect('index', 'List');
     }
+
+    /**
+     * Create a zip file from an extension
+     *
+     * @param string $extensionKey
+     * @return string Name and path of create zip file
+     */
+    protected function createZipFileFromExtension(string $extensionKey): string
+    {
+        $extensionDetails = $this->installUtility->enrichExtensionWithDetails($extensionKey);
+        $extensionPath = $extensionDetails['packagePath'];
+
+        // Add trailing slash to the extension path, getAllFilesAndFoldersInPath explicitly requires that.
+        $extensionPath = PathUtility::sanitizeTrailingSeparator($extensionPath);
+
+        $version = (string)$extensionDetails['version'];
+        if (empty($version)) {
+            $version = '0.0.0';
+        }
+
+        $temporaryPath = Environment::getVarPath() . '/transient/';
+        if (!@is_dir($temporaryPath)) {
+            GeneralUtility::mkdir($temporaryPath);
+        }
+        $fileName = $temporaryPath . $extensionKey . '_' . $version . '_' . date('YmdHi', $GLOBALS['EXEC_TIME']) . '.zip';
+
+        $zip = new \ZipArchive();
+        $zip->open($fileName, \ZipArchive::CREATE);
+
+        $excludePattern = $GLOBALS['TYPO3_CONF_VARS']['EXT']['excludeForPackaging'];
+
+        // Get all the files of the extension, but exclude the ones specified in the excludePattern
+        $files = GeneralUtility::getAllFilesAndFoldersInPath(
+            [], // No files pre-added
+            $extensionPath, // Start from here
+            '', // Do not filter files by extension
+            true, // Include subdirectories
+            PHP_INT_MAX, // Recursion level
+            $excludePattern        // Files and directories to exclude.
+        );
+
+        // Make paths relative to extension root directory.
+        $files = GeneralUtility::removePrefixPathFromList($files, $extensionPath);
+        $files = is_array($files) ? $files : [];
+
+        // Remove the one empty path that is the extension dir itself.
+        $files = array_filter($files);
+
+        foreach ($files as $file) {
+            $fullPath = $extensionPath . $file;
+            // Distinguish between files and directories, as creation of the archive
+            // fails on Windows when trying to add a directory with "addFile".
+            if (is_dir($fullPath)) {
+                $zip->addEmptyDir($file);
+            } else {
+                $zip->addFile($fullPath, $file);
+            }
+        }
+
+        $zip->close();
+        return $fileName;
+    }
 }
diff --git a/typo3/sysext/extensionmanager/Classes/Utility/FileHandlingUtility.php b/typo3/sysext/extensionmanager/Classes/Utility/FileHandlingUtility.php
index 4289c93c90775bb19ad4f266d15ae9a3cdbd0945..728ee274c18bc3f34e7c1debceaf4acaa858c060 100644
--- a/typo3/sysext/extensionmanager/Classes/Utility/FileHandlingUtility.php
+++ b/typo3/sysext/extensionmanager/Classes/Utility/FileHandlingUtility.php
@@ -272,8 +272,7 @@ class FileHandlingUtility implements SingletonInterface, LoggerAwareInterface
             $emConfFileData = $this->emConfUtility->includeEmConf(
                 $extensionData['extKey'],
                 [
-                    'packagePath' => $rootPath,
-                    'siteRelPath' => PathUtility::stripPathSitePrefix($rootPath)
+                    'packagePath' => $rootPath
                 ]
             );
             $emConfFileData = is_array($emConfFileData) ? $emConfFileData : [];
@@ -300,22 +299,6 @@ class FileHandlingUtility implements SingletonInterface, LoggerAwareInterface
         return false;
     }
 
-    /**
-     * Returns absolute path
-     *
-     * @param string $relativePath
-     * @throws ExtensionManagerException
-     * @return string
-     */
-    protected function getAbsolutePath($relativePath)
-    {
-        $absolutePath = GeneralUtility::getFileAbsFileName(GeneralUtility::resolveBackPath(Environment::getPublicPath() . '/' . $relativePath));
-        if (empty($absolutePath)) {
-            throw new ExtensionManagerException('Illegal relative path given', 1350742864);
-        }
-        return $absolutePath;
-    }
-
     /**
      * Returns relative path
      *
@@ -327,91 +310,6 @@ class FileHandlingUtility implements SingletonInterface, LoggerAwareInterface
         return PathUtility::stripPathSitePrefix($absolutePath);
     }
 
-    /**
-     * Get extension path for an available or installed extension
-     *
-     * @param string $extensionKey
-     * @return string
-     */
-    public function getAbsoluteExtensionPath(string $extensionKey): string
-    {
-        $extension = $this->installUtility->enrichExtensionWithDetails($extensionKey);
-        return $this->getAbsolutePath($extension['siteRelPath']);
-    }
-
-    /**
-     * Get version of an available or installed extension
-     *
-     * @param string $extensionKey
-     * @return string
-     */
-    protected function getExtensionVersion(string $extensionKey): string
-    {
-        $extensionData = $this->installUtility->enrichExtensionWithDetails($extensionKey);
-        return (string)$extensionData['version'];
-    }
-
-    /**
-     * Create a zip file from an extension
-     *
-     * @param string $extensionKey
-     * @return string Name and path of create zip file
-     */
-    public function createZipFileFromExtension($extensionKey): string
-    {
-        $extensionPath = $this->getAbsoluteExtensionPath($extensionKey);
-
-        // Add trailing slash to the extension path, getAllFilesAndFoldersInPath explicitly requires that.
-        $extensionPath = PathUtility::sanitizeTrailingSeparator($extensionPath);
-
-        $version = $this->getExtensionVersion($extensionKey);
-        if (empty($version)) {
-            $version = '0.0.0';
-        }
-
-        $temporaryPath = Environment::getVarPath() . '/transient/';
-        if (!@is_dir($temporaryPath)) {
-            GeneralUtility::mkdir($temporaryPath);
-        }
-        $fileName = $temporaryPath . $extensionKey . '_' . $version . '_' . date('YmdHi', $GLOBALS['EXEC_TIME']) . '.zip';
-
-        $zip = new \ZipArchive();
-        $zip->open($fileName, \ZipArchive::CREATE);
-
-        $excludePattern = $GLOBALS['TYPO3_CONF_VARS']['EXT']['excludeForPackaging'];
-
-        // Get all the files of the extension, but exclude the ones specified in the excludePattern
-        $files = GeneralUtility::getAllFilesAndFoldersInPath(
-            [], // No files pre-added
-            $extensionPath, // Start from here
-            '', // Do not filter files by extension
-            true, // Include subdirectories
-            PHP_INT_MAX, // Recursion level
-            $excludePattern        // Files and directories to exclude.
-        );
-
-        // Make paths relative to extension root directory.
-        $files = GeneralUtility::removePrefixPathFromList($files, $extensionPath);
-        $files = is_array($files) ? $files : [];
-
-        // Remove the one empty path that is the extension dir itself.
-        $files = array_filter($files);
-
-        foreach ($files as $file) {
-            $fullPath = $extensionPath . $file;
-            // Distinguish between files and directories, as creation of the archive
-            // fails on Windows when trying to add a directory with "addFile".
-            if (is_dir($fullPath)) {
-                $zip->addEmptyDir($file);
-            } else {
-                $zip->addFile($fullPath, $file);
-            }
-        }
-
-        $zip->close();
-        return $fileName;
-    }
-
     /**
      * Unzip an extension.zip.
      *
diff --git a/typo3/sysext/extensionmanager/Classes/Utility/InstallUtility.php b/typo3/sysext/extensionmanager/Classes/Utility/InstallUtility.php
index f481eff9693f78ee38a55be5783ec1fa437dd022..03fb803aea9b49b46c06fff3c1e09313fb06f285 100644
--- a/typo3/sysext/extensionmanager/Classes/Utility/InstallUtility.php
+++ b/typo3/sysext/extensionmanager/Classes/Utility/InstallUtility.php
@@ -420,7 +420,7 @@ class InstallUtility implements SingletonInterface, LoggerAwareInterface
      */
     public function removeExtension($extension)
     {
-        $absolutePath = $this->fileHandlingUtility->getAbsoluteExtensionPath($extension);
+        $absolutePath = $this->enrichExtensionWithDetails($extension)['packagePath'];
         if ($this->fileHandlingUtility->isValidExtensionPath($absolutePath)) {
             if ($this->packageManager->isPackageAvailable($extension)) {
                 // Package manager deletes the extension and removes the entry from PackageStates.php
diff --git a/typo3/sysext/extensionmanager/Classes/Utility/ListUtility.php b/typo3/sysext/extensionmanager/Classes/Utility/ListUtility.php
index 5f8561aefacbcbac1c31611237c0b1ec0ec7bc84..820725c4b785ef4458e136878935bfe6c171d5a4 100644
--- a/typo3/sysext/extensionmanager/Classes/Utility/ListUtility.php
+++ b/typo3/sysext/extensionmanager/Classes/Utility/ListUtility.php
@@ -122,6 +122,7 @@ class ListUtility implements SingletonInterface
                 if ($filter === '' || $filter === $installationType) {
                     $this->availableExtensions[$package->getPackageKey()] = [
                         'siteRelPath' => str_replace(Environment::getPublicPath() . '/', '', $package->getPackagePath()),
+                        'packagePath' => $package->getPackagePath(),
                         'type' => $installationType,
                         'key' => $package->getPackageKey(),
                         'icon' => PathUtility::getAbsoluteWebPath($package->getPackagePath() . ExtensionManagementUtility::getExtensionIcon($package->getPackagePath())),
diff --git a/typo3/sysext/extensionmanager/Tests/Unit/Controller/ActionControllerTest.php b/typo3/sysext/extensionmanager/Tests/Unit/Controller/ActionControllerTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..f3e97535208d55162dbb0546c8a8525ed8d331af
--- /dev/null
+++ b/typo3/sysext/extensionmanager/Tests/Unit/Controller/ActionControllerTest.php
@@ -0,0 +1,108 @@
+<?php
+
+declare(strict_types=1);
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+namespace TYPO3\CMS\Extensionmanager\Tests\Unit\Controller;
+
+use TYPO3\CMS\Core\Core\Environment;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Core\Utility\StringUtility;
+use TYPO3\CMS\Extensionmanager\Controller\ActionController;
+use TYPO3\CMS\Extensionmanager\Domain\Model\Extension;
+use TYPO3\CMS\Extensionmanager\Utility\InstallUtility;
+use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
+
+class ActionControllerTest extends UnitTestCase
+{
+    /**
+     * @var array List of created fake extensions to be deleted in tearDown() again
+     */
+    protected $fakedExtensions = [];
+
+    /**
+     * Creates a fake extension inside typo3temp/. No configuration is created,
+     * just the folder
+     *
+     * @return array
+     */
+    protected function createFakeExtension()
+    {
+        $extKey = strtolower(StringUtility::getUniqueId('testing'));
+        $absExtPath = Environment::getVarPath() . '/tests/ext-' . $extKey . '/';
+        GeneralUtility::mkdir($absExtPath);
+        $this->testFilesToDelete[] = Environment::getVarPath() . '/tests/ext-' . $extKey;
+        return [
+            'extensionKey' => $extKey,
+            'version' => '0.0.0',
+            'packagePath' => $absExtPath
+        ];
+    }
+
+    /**
+     * Warning: This test asserts multiple things at once to keep the setup short.
+     *
+     * @test
+     */
+    public function createZipFileFromExtensionGeneratesCorrectArchive()
+    {
+        // 42 second of first day in 1970 - used to have achieve stable file names
+        $GLOBALS['EXEC_TIME'] = 42;
+
+        // Create extension for testing:
+        $fakeExtension = $this->createFakeExtension();
+        $extKey = $fakeExtension['extensionKey'];
+        $extensionRoot = $fakeExtension['packagePath'];
+        $installUtility = $this->prophesize(InstallUtility::class);
+        $installUtility->enrichExtensionWithDetails($extKey)->willReturn($fakeExtension);
+        // Build mocked fileHandlingUtility:
+        $subject = $this->getAccessibleMock(
+            ActionController::class,
+            ['dummy']
+        );
+        $subject->injectInstallUtility($installUtility->reveal());
+
+        // Add files and directories to extension:
+        touch($extensionRoot . 'emptyFile.txt');
+        file_put_contents($extensionRoot . 'notEmptyFile.txt', 'content');
+        touch($extensionRoot . '.hiddenFile');
+        mkdir($extensionRoot . 'emptyDir');
+        mkdir($extensionRoot . 'notEmptyDir');
+        touch($extensionRoot . 'notEmptyDir/file.txt');
+
+        // Create zip-file from extension
+        $filename = $subject->_call('createZipFileFromExtension', $extKey);
+
+        $expectedFilename = Environment::getVarPath() . '/transient/' . $extKey . '_0.0.0_' . date('YmdHi', 42) . '.zip';
+        $this->testFilesToDelete[] = $filename;
+        self::assertEquals($expectedFilename, $filename, 'Archive file name differs from expectation');
+
+        // File was created
+        self::assertTrue(file_exists($filename), 'Zip file not created');
+
+        // Read archive and check its contents
+        $archive = new \ZipArchive();
+        self::assertTrue($archive->open($filename), 'Unable to open archive');
+        self::assertEquals($archive->statName('emptyFile.txt')['size'], 0, 'Empty file not in archive');
+        self::assertEquals($archive->getFromName('notEmptyFile.txt'), 'content', 'Expected content not found');
+        self::assertFalse($archive->statName('.hiddenFile'), 'Hidden file not in archive');
+        self::assertTrue(is_array($archive->statName('emptyDir/')), 'Empty directory not in archive');
+        self::assertTrue(is_array($archive->statName('notEmptyDir/')), 'Not empty directory not in archive');
+        self::assertTrue(is_array($archive->statName('notEmptyDir/file.txt')), 'File within directory not in archive');
+
+        // Check that the archive has no additional content
+        self::assertEquals($archive->numFiles, 5, 'Too many or too less files in archive');
+    }
+}
diff --git a/typo3/sysext/extensionmanager/Tests/Unit/Utility/FileHandlingUtilityTest.php b/typo3/sysext/extensionmanager/Tests/Unit/Utility/FileHandlingUtilityTest.php
index fd9af2fb7e77e278c760d2497dc03334852ee757..5b149c240bf31dc7041490e78cfd914c5dd6f3a5 100644
--- a/typo3/sysext/extensionmanager/Tests/Unit/Utility/FileHandlingUtilityTest.php
+++ b/typo3/sysext/extensionmanager/Tests/Unit/Utility/FileHandlingUtilityTest.php
@@ -76,55 +76,6 @@ class FileHandlingUtilityTest extends UnitTestCase
         $fileHandlerMock->_call('makeAndClearExtensionDir', $extKey);
     }
 
-    /**
-     * @return array
-     */
-    public function invalidRelativePathDataProvider()
-    {
-        return [
-            ['../../'],
-            ['/foo/bar'],
-            ['foo//bar'],
-            ['foo/bar' . "\0"],
-        ];
-    }
-
-    /**
-     * @param string $invalidRelativePath
-     * @test
-     * @dataProvider invalidRelativePathDataProvider
-     */
-    public function getAbsolutePathThrowsExceptionForInvalidRelativePaths($invalidRelativePath)
-    {
-        $this->expectException(ExtensionManagerException::class);
-        $this->expectExceptionCode(1350742864);
-        $fileHandlerMock = $this->getAccessibleMock(FileHandlingUtility::class, ['dummy'], []);
-        $fileHandlerMock->_call('getAbsolutePath', $invalidRelativePath);
-    }
-
-    /**
-     * @return array
-     */
-    public function validRelativePathDataProvider()
-    {
-        return [
-            ['foo/../bar', Environment::getPublicPath() . '/bar'],
-            ['bas', Environment::getPublicPath() . '/bas'],
-        ];
-    }
-
-    /**
-     * @param string $validRelativePath
-     * @param string $expectedAbsolutePath
-     * @test
-     * @dataProvider validRelativePathDataProvider
-     */
-    public function getAbsolutePathReturnsAbsolutePathForValidRelativePaths($validRelativePath, $expectedAbsolutePath)
-    {
-        $fileHandlerMock = $this->getAccessibleMock(FileHandlingUtility::class, ['dummy']);
-        self::assertSame($expectedAbsolutePath, $fileHandlerMock->_call('getAbsolutePath', $validRelativePath));
-    }
-
     /**
      * @test
      */
@@ -443,77 +394,4 @@ class FileHandlingUtilityTest extends UnitTestCase
         $fileHandlerMock->_call('writeEmConfToFile', $extensionData, $rootPath);
         self::assertTrue(file_exists($rootPath . 'ext_emconf.php'));
     }
-
-    /**
-     * @return \PHPUnit\Framework\MockObject\MockObject|FileHandlingUtility
-     */
-    protected function getPreparedFileHandlingMockForDirectoryCreationTests()
-    {
-        /** @var $fileHandlerMock FileHandlingUtility|\PHPUnit\Framework\MockObject\MockObject */
-        $fileHandlerMock = $this->getMockBuilder(FileHandlingUtility::class)
-            ->setMethods(['createNestedDirectory', 'getAbsolutePath', 'directoryExists'])
-            ->getMock();
-        $fileHandlerMock->expects(self::any())
-            ->method('getAbsolutePath')
-            ->willReturnArgument(0);
-        return $fileHandlerMock;
-    }
-
-    /**
-     * Warning: This test asserts multiple things at once to keep the setup short.
-     *
-     * @test
-     */
-    public function createZipFileFromExtensionGeneratesCorrectArchive()
-    {
-        // 42 second of first day in 1970 - used to have achieve stable file names
-        $GLOBALS['EXEC_TIME'] = 42;
-
-        // Create extension for testing:
-        $extKey = $this->createFakeExtension();
-        $extensionRoot = $this->fakedExtensions[$extKey]['siteAbsPath'];
-
-        // Build mocked fileHandlingUtility:
-        $fileHandlerMock = $this->getAccessibleMock(
-            FileHandlingUtility::class,
-            ['getAbsoluteExtensionPath', 'getExtensionVersion']
-        );
-        $fileHandlerMock->expects(self::any())
-            ->method('getAbsoluteExtensionPath')
-            ->willReturn($extensionRoot);
-        $fileHandlerMock->expects(self::any())
-            ->method('getExtensionVersion')
-            ->willReturn('0.0.0');
-
-        // Add files and directories to extension:
-        touch($extensionRoot . 'emptyFile.txt');
-        file_put_contents($extensionRoot . 'notEmptyFile.txt', 'content');
-        touch($extensionRoot . '.hiddenFile');
-        mkdir($extensionRoot . 'emptyDir');
-        mkdir($extensionRoot . 'notEmptyDir');
-        touch($extensionRoot . 'notEmptyDir/file.txt');
-
-        // Create zip-file from extension
-        $filename = $fileHandlerMock->_call('createZipFileFromExtension', $extKey);
-
-        $expectedFilename = Environment::getVarPath() . '/transient/' . $extKey . '_0.0.0_' . date('YmdHi', 42) . '.zip';
-        $this->testFilesToDelete[] = $filename;
-        self::assertEquals($expectedFilename, $filename, 'Archive file name differs from expectation');
-
-        // File was created
-        self::assertTrue(file_exists($filename), 'Zip file not created');
-
-        // Read archive and check its contents
-        $archive = new \ZipArchive();
-        self::assertTrue($archive->open($filename), 'Unable to open archive');
-        self::assertEquals($archive->statName('emptyFile.txt')['size'], 0, 'Empty file not in archive');
-        self::assertEquals($archive->getFromName('notEmptyFile.txt'), 'content', 'Expected content not found');
-        self::assertFalse($archive->statName('.hiddenFile'), 'Hidden file not in archive');
-        self::assertTrue(is_array($archive->statName('emptyDir/')), 'Empty directory not in archive');
-        self::assertTrue(is_array($archive->statName('notEmptyDir/')), 'Not empty directory not in archive');
-        self::assertTrue(is_array($archive->statName('notEmptyDir/file.txt')), 'File within directory not in archive');
-
-        // Check that the archive has no additional content
-        self::assertEquals($archive->numFiles, 5, 'Too many or too less files in archive');
-    }
 }