From cd7db1861d8ef59c7a7f76d4e53252a60c46860f Mon Sep 17 00:00:00 2001
From: Benjamin Eberlei <kontakt@beberlei.de>
Date: Mon, 19 Nov 2012 11:21:41 +0100
Subject: [PATCH] Remove reliance on proc_open in Filesystem#rename()

---
 src/Composer/Util/Filesystem.php | 40 ++++++++++++++++++++++++++++----
 1 file changed, 35 insertions(+), 5 deletions(-)

diff --git a/src/Composer/Util/Filesystem.php b/src/Composer/Util/Filesystem.php
index fd2dae21f..90736995e 100644
--- a/src/Composer/Util/Filesystem.php
+++ b/src/Composer/Util/Filesystem.php
@@ -86,14 +86,10 @@ class Filesystem
      */
     public function removeDirectoryPhp($directory)
     {
-        $it = new RecursiveDirectoryIterator($directory);
+        $it = new RecursiveDirectoryIterator($directory, RecursiveDirectoryIterator::SKIP_DOTS);
         $ri = new RecursiveIteratorIterator($it, RecursiveIteratorIterator::CHILD_FIRST);
 
         foreach ($ri as $file) {
-            if ($file->getFilename() == "." || $file->getFilename() == "..") {
-                continue;
-            }
-
             if ($file->isDir()) {
                 rmdir($file->getPathname());
             } else {
@@ -120,6 +116,36 @@ class Filesystem
         }
     }
 
+    /**
+     * Copy then delete is a non-atomic version of {@link rename}.
+     *
+     * Some systems can't rename and also dont have proc_open,
+     * which requires this solution.
+     *
+     * @param string $source
+     * @param string $target
+     */
+    public function copyThenRemove($source, $target)
+    {
+        $it = new RecursiveDirectoryIterator($source, RecursiveDirectoryIterator::SKIP_DOTS);
+        $ri = new RecursiveIteratorIterator($it, RecursiveIteratorIterator::SELF_FIRST);
+
+        if ( !file_exists($target)) {
+            mkdir($target, 0777, true);
+        }
+
+        foreach ($ri as $file) {
+            $targetPath = $target . DIRECTORY_SEPARATOR . $ri->getSubPathName();
+            if ($file->isDir()) {
+                mkdir($targetPath);
+            } else {
+                copy($file->getPathname(), $targetPath);
+            }
+        }
+
+        $this->removeDirectoryPhp($source);
+    }
+
     public function rename($source, $target)
     {
         if (true === @rename($source, $target)) {
@@ -127,6 +153,10 @@ class Filesystem
         }
 
         if (defined('PHP_WINDOWS_VERSION_BUILD')) {
+            if (!function_exists('proc_open')) {
+                return $this->copyThenRemove($source, $target);
+            }
+
             // Try to copy & delete - this is a workaround for random "Access denied" errors.
             $command = sprintf('xcopy %s %s /E /I /Q', escapeshellarg($source), escapeshellarg($target));
             if (0 === $this->processExecutor->execute($command)) {