diff --git a/core/includes/file.inc b/core/includes/file.inc index 133d64f..cc1604e 100644 --- a/core/includes/file.inc +++ b/core/includes/file.inc @@ -2322,12 +2322,52 @@ function drupal_mkdir($uri, $mode = NULL, $recursive = FALSE, $context = NULL) { $mode = variable_get('file_chmod_directory', 0775); } + // Determine already existing part of $uri, we must not apply chmod for that part. + // We need to do so before directories will be created recursively. + if ($recursive) { + $uri_flat = $uri; // $uri_flat - $uri without schema prefix + $uri_existing = ''; // already existing part of $uri (determine later) + + // check the case if $uri with schema + $scheme = file_uri_scheme($uri); + if ($scheme && file_stream_wrapper_valid_scheme($scheme)) { + $uri_flat = drupal_substr($uri, drupal_strlen($scheme) + 3); // +3 mean :// after scheme + $uri_existing = $scheme . '://'; + } + $uri_flat = rtrim($uri_flat, '/\\'); + + foreach (explode('/', $uri_flat) as $uri_element) { + $uri_existing .= $uri_element . '/'; + if (!is_dir($uri_existing)) { // find first absent directory and then exit + $uri_existing = drupal_substr($uri_existing, 0, - 2 - drupal_strlen($uri_element)); // -2 mean slashes + $uri_flat = -1; // set the flag + break; + } + } + } + if (!isset($context)) { - return mkdir($uri, $mode, $recursive); + $success = mkdir($uri, $mode, $recursive); } else { - return mkdir($uri, $mode, $recursive, $context); + $success = mkdir($uri, $mode, $recursive, $context); + } + + // Process directories, created recursively, with chmod. + // @see http://drupal.org/node/1068266 + if ($success && $recursive && isset($uri_flat) && $uri_flat == -1) { + $uri_flat = drupal_substr($uri, drupal_strlen($uri_existing)); + $uri_flat = trim($uri_flat, '/\\'); + foreach (explode('/', $uri_flat) as $uri_element) { + $uri_existing .= '/' . $uri_element; + // Fail if permisions can not be changed. + if (!$success = drupal_chmod($uri_existing, $mode)) { + break; + } + } } + + return $success; } /** diff --git a/core/modules/system/lib/Drupal/system/Tests/File/DirectoryTest.php b/core/modules/system/lib/Drupal/system/Tests/File/DirectoryTest.php index 5d57bdf..3edc12a 100644 --- a/core/modules/system/lib/Drupal/system/Tests/File/DirectoryTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/File/DirectoryTest.php @@ -20,11 +20,49 @@ class DirectoryTest extends FileTestBase { } /** - * Test directory handling functions. + * Tests directory handling functions. + * + * Checks valid and invalid URI variations, single and recursively. + */ + function testFileDirectoryHandling() { + $directories = array(); + + // Valid stream wrapper scheme. + $directories[] = file_default_scheme() . '://'; + + // Invalid stream wrapper scheme. + $directories[] = 'foo://'; + + // Valid absolute URI. + $directories[] = '/var/www/drupal8-core/sites/default/files/'; + + // Invalid absolute URI. + $directories[] = '%/var/www/drupal8-core/sites/default/files/'; + + // Valid relative URI. + $directories[] = '../sites/default/files/'; + + // Invalid relative URI. + $directories[] = '..%/sites/default/files/'; + + foreach ($directories as $directory) { + // Check directory handling. + $this->checkFileDirectoryHandling($directory . $this->randomName()); + // Check recursively. + $this->checkFileDirectoryHandling($directory . $this->randomName() . '/' . $this->randomName()); + } + } + + /** + * Checks directory handling functions. + * + * @param string $directory + * A file directory path to operate on. + * + * @see Drupal\system\Tests\File\DirectoryTest::testFileDirectoryHandling(). */ - function testFileCheckDirectoryHandling() { - // A directory to operate on. - $directory = file_default_scheme() . '://' . $this->randomName() . '/' . $this->randomName(); + function checkFileDirectoryHandling($directory = NULL) { + // Assert directory does not already exist. $this->assertFalse(is_dir($directory), t('Directory does not exist prior to testing.')); // Non-existent directory.