Make FileDeletePIP safe for ci file systems
authorjoshuaruesweg <ruesweg@woltlab.com>
Wed, 30 Mar 2022 12:55:03 +0000 (14:55 +0200)
committerjoshuaruesweg <ruesweg@woltlab.com>
Mon, 4 Apr 2022 12:57:34 +0000 (14:57 +0200)
wcfsetup/install/files/lib/system/package/plugin/AbstractFileDeletePackageInstallationPlugin.class.php

index 678e18ee1f73ec7ce22506e0592fbadfc3c3f38e..20cf5bdde6f283da04bd54caf2ca24a3e48d03fb 100644 (file)
@@ -109,9 +109,8 @@ abstract class AbstractFileDeletePackageInstallationPlugin extends AbstractXMLPa
                 }
 
                 $filePath = $this->getFilePath($file, $application);
-                if (\file_exists($filePath)) {
-                    \unlink($filePath);
-                }
+
+                $this->safeDeleteFile($filePath);
             }
         }
 
@@ -130,6 +129,49 @@ abstract class AbstractFileDeletePackageInstallationPlugin extends AbstractXMLPa
         WCF::getDB()->commitTransaction();
     }
 
+    private static function isFilesystemCaseSensitive(): bool
+    {
+        static $isFilesystemCaseSensitive = null;
+
+        if ($isFilesystemCaseSensitive === null) {
+            $testFilePath = __FILE__;
+
+            $invertedCase = \strstr(
+                $testFilePath,
+                "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
+                "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+            );
+
+            $isFilesystemCaseSensitive = !\file_exists($invertedCase);
+        }
+
+        return $isFilesystemCaseSensitive;
+    }
+
+    private function safeDeleteFile(string $filePath): void
+    {
+        if (!\file_exists($filePath)) {
+            return;
+        }
+
+        if (self::isFilesystemCaseSensitive()) {
+            \unlink($filePath);
+
+            return;
+        }
+
+        // If the filesystem is case insensitive, we must check, whether the casing of the file
+        // matches the casing of the file, which we want to delete. Therefore, we must iterate
+        // through the whole dir to find the potential file.
+        $pathInfo = \pathinfo($filePath);
+        foreach (\glob($pathInfo['dirname'] . '/*') as $file) {
+            if (\basename($file) === $pathInfo['basename']) {
+                \unlink($filePath);
+                break;
+            }
+        }
+    }
+
     /**
      * @inheritDoc
      */