From ed70c74be5f0f17169dea553b8471f81ae780301 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Mudr=C3=A1k?= Date: Thu, 2 May 2013 13:44:47 +0200 Subject: [PATCH] MDL-39442 Do not use native rename() when moving folders The native rename() function does not support moving folders cross-device. See https://bugs.php.net/bug.php?id=54097 for details. So instead of trying to move the whole tree, the new installer's method moves files recursively one by one. This is consistent with what mdeploy.php already does. --- admin/tool/installaddon/classes/installer.php | 46 +++++++++++++++++++ admin/tool/installaddon/deploy.php | 2 +- .../installaddon/tests/installer_test.php | 14 ++++++ admin/tool/installaddon/version.php | 2 +- 4 files changed, 62 insertions(+), 2 deletions(-) diff --git a/admin/tool/installaddon/classes/installer.php b/admin/tool/installaddon/classes/installer.php index fa4babb5bed..a882a038e59 100644 --- a/admin/tool/installaddon/classes/installer.php +++ b/admin/tool/installaddon/classes/installer.php @@ -395,6 +395,52 @@ class tool_installaddon_installer { } } + /** + * Moves the given source into a new location recursively + * + * This is cross-device safe implementation to be used instead of the native rename() function. + * See https://bugs.php.net/bug.php?id=54097 for more details. + * + * @param string $source full path to the existing directory + * @param string $target full path to the new location of the directory + */ + public function move_directory($source, $target) { + + if (file_exists($target)) { + throw new tool_installaddon_installer_exception('err_folder_already_exists', array('path' => $target)); + } + + if (is_dir($source)) { + $handle = opendir($source); + } else { + throw new tool_installaddon_installer_exception('err_no_such_folder', array('path' => $source)); + } + + make_writable_directory($target); + + while ($filename = readdir($handle)) { + $sourcepath = $source.'/'.$filename; + $targetpath = $target.'/'.$filename; + + if ($filename === '.' or $filename === '..') { + continue; + } + + if (is_dir($sourcepath)) { + $this->move_directory($sourcepath, $targetpath); + + } else { + rename($sourcepath, $targetpath); + } + } + + closedir($handle); + + rmdir($source); + + clearstatcache(); + } + //// End of external API /////////////////////////////////////////////////// /** diff --git a/admin/tool/installaddon/deploy.php b/admin/tool/installaddon/deploy.php index 932e9f2001f..f68ebed888b 100644 --- a/admin/tool/installaddon/deploy.php +++ b/admin/tool/installaddon/deploy.php @@ -71,6 +71,6 @@ if (file_exists($plugintypepath.'/'.$pluginname)) { get_string('invaliddata', 'core_error')); } -rename($zipcontentpath.'/'.$pluginname, $plugintypepath.'/'.$pluginname); +$installer->move_directory($zipcontentpath.'/'.$pluginname, $plugintypepath.'/'.$pluginname); fulldelete($CFG->tempdir.'/tool_installaddon/'.$jobid); redirect(new moodle_url('/admin')); diff --git a/admin/tool/installaddon/tests/installer_test.php b/admin/tool/installaddon/tests/installer_test.php index fd8d1d1c0b9..4169719cf86 100644 --- a/admin/tool/installaddon/tests/installer_test.php +++ b/admin/tool/installaddon/tests/installer_test.php @@ -125,6 +125,20 @@ class tool_installaddon_installer_test extends advanced_testcase { ))); $this->assertSame(false, $installer->testable_decode_remote_request($request)); } + + public function test_move_directory() { + $jobid = md5(rand().uniqid('test_', true)); + $jobroot = make_temp_directory('tool_installaddon/'.$jobid); + $contentsdir = make_temp_directory('tool_installaddon/'.$jobid.'/contents/sub/folder'); + file_put_contents($contentsdir.'/readme.txt', 'Hello world!'); + + $installer = tool_installaddon_installer::instance(); + $installer->move_directory($jobroot.'/contents', $jobroot.'/moved'); + + $this->assertFalse(is_dir($jobroot.'/contents')); + $this->assertTrue(is_file($jobroot.'/moved/sub/folder/readme.txt')); + $this->assertSame('Hello world!', file_get_contents($jobroot.'/moved/sub/folder/readme.txt')); + } } diff --git a/admin/tool/installaddon/version.php b/admin/tool/installaddon/version.php index 94ab2e5c22f..db5c7cd6353 100644 --- a/admin/tool/installaddon/version.php +++ b/admin/tool/installaddon/version.php @@ -26,4 +26,4 @@ defined('MOODLE_INTERNAL') || die(); $plugin->component = 'tool_installaddon'; $plugin->version = 2013031400; $plugin->requires = 2013031400; -$plugin->maturity = MATURITY_BETA; +$plugin->maturity = MATURITY_STABLE;