diff --git a/framework/utils/CFileHelper.php b/framework/utils/CFileHelper.php index ca07fce46..ab6e4a81e 100644 --- a/framework/utils/CFileHelper.php +++ b/framework/utils/CFileHelper.php @@ -57,7 +57,7 @@ class CFileHelper $level=-1; extract($options); if(!is_dir($dst)) - self::mkdir($dst, self::getModeFromOptions($options), true); + self::mkdir($dst, $options, true); self::copyDirectoryRecursive($src,$dst,'',$fileTypes,$exclude,$level,$options); } @@ -114,7 +114,7 @@ class CFileHelper protected static function copyDirectoryRecursive($src,$dst,$base,$fileTypes,$exclude,$level,$options) { if(!is_dir($dst)) - self::mkdir($dst, self::getModeFromOptions($options), false); + self::mkdir($dst, $options, false); $folder=opendir($src); while(($file=readdir($folder))!==false) @@ -260,32 +260,25 @@ class CFileHelper } /** - * Creates directory for $dst path with $mode and $recursive creation is allowed. - * For concurrent compatibility chmod is used instead of mkdir's $mode. + * Shared environment safe version of mkdir. Supports recursive creation. + * For avoidance of umask side-effects chmod is used. * * @static * @param string $dst path to be created - * @param integer $mode access bitmask + * @param array $options newDirMode element used, must contain access bitmask. * @param boolean $recursive * @return boolean result of mkdir * @see mkdir */ - private static function mkdir($dst, $mode, $recursive) + private static function mkdir($dst, array $options, $recursive) { - $res = mkdir($dst, $mode, $recursive); + $prevDir = dirname($dst); + if ($recursive && !is_dir($dst) && !is_dir($prevDir)) self::mkdir(dirname($dst), $options, true); + + $mode = isset($options['newDirMode']) ? $options['newDirMode'] : 0777; + $res = mkdir($dst, $mode); chmod($dst, $mode); return $res; } - /** - * Returns dir access mode from options, if set, or default value (0777). - * @static - * @param array $options - * @return integer - */ - private static function getModeFromOptions(array $options) - { - return isset($options['newDirMode']) ? $options['newDirMode'] : 0777; - } - } diff --git a/tests/framework/utils/CFileHelperTest.php b/tests/framework/utils/CFileHelperTest.php new file mode 100644 index 000000000..b055ebe46 --- /dev/null +++ b/tests/framework/utils/CFileHelperTest.php @@ -0,0 +1,88 @@ +testDir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . __CLASS__ . time(); + $this->createTestStruct($this->testDir); + } + + protected function tearDown() + { + parent::tearDown(); + if (is_dir($this->testDir)) $this->rrmdir($this->testDir); + clearstatcache(); + } + + function testCopyDirectory_subDir_modeShoudBe0775() + { + $src = $this->testDir . DIRECTORY_SEPARATOR . $this->rootDir1; + $dst = $this->testDir . DIRECTORY_SEPARATOR . $this->rootDir2; + CFileHelper::copyDirectory($src, $dst, array('newDirMode' => $this->testMode)); + + $subDir2Mode = $this->getMode($dst . DIRECTORY_SEPARATOR . $this->subDir ); + $expectedMode = sprintf('%o', $this->testMode); + $this->assertEquals($expectedMode, $subDir2Mode, "Subdir mode is not {$expectedMode}"); + } + + function testCopyDirectory_subDir_modeShoudBe0777() + { + $src = $this->testDir . DIRECTORY_SEPARATOR . $this->rootDir1; + $dst = $this->testDir . DIRECTORY_SEPARATOR . $this->rootDir2; + CFileHelper::copyDirectory($src, $dst); + + $subDir2Mode = $this->getMode($dst . DIRECTORY_SEPARATOR . $this->subDir ); + $expectedMode = sprintf('%o', 0777); + $this->assertEquals($expectedMode, $subDir2Mode, "Subdir mode is not {$expectedMode}"); + } + + private function createTestStruct($testDir) + { + if (!mkdir($testDir)) $this->fail("mkdir of '{$testDir}' failed"); + + $rootDir = $testDir . DIRECTORY_SEPARATOR . $this->rootDir1; + mkdir($rootDir); + + $subDir = $testDir . DIRECTORY_SEPARATOR . $this->rootDir1 . DIRECTORY_SEPARATOR . $this->subDir; + mkdir($subDir); + + $file = $testDir . DIRECTORY_SEPARATOR . $this->rootDir1 . DIRECTORY_SEPARATOR . $this->subDir . DIRECTORY_SEPARATOR . $this->file; + file_put_contents($file, '12321312'); + } + + private function getMode($file) + { + return substr(sprintf('%o', fileperms($file)), -4); + } + + private function rrmdir($dir) + { + if ($handle = opendir($dir)) + { + while (false !== ($entry = readdir($handle))) + { + if ($entry != "." && $entry != "..") + { + if (is_dir($dir . "/" . $entry) === true) + { + $this->rrmdir($dir . "/" . $entry); + } + else + { + unlink($dir . "/" . $entry); + } + } + } + closedir($handle); + rmdir($dir); + } + } +}