diff --git a/core/includes/file.inc b/core/includes/file.inc index 133d64f..d6247f4 100644 --- a/core/includes/file.inc +++ b/core/includes/file.inc @@ -2322,12 +2322,97 @@ function drupal_mkdir($uri, $mode = NULL, $recursive = FALSE, $context = NULL) { $mode = variable_get('file_chmod_directory', 0775); } - if (!isset($context)) { - return mkdir($uri, $mode, $recursive); + if (file_uri_scheme($uri)) { + if (!isset($context)) { + $success = mkdir($uri, $mode, $recursive); + } + else { + $success = mkdir($uri, $mode, $recursive, $context); + } } else { - return mkdir($uri, $mode, $recursive, $context); + $success = drupal_mkdir_local($uri, $mode, $recursive, $context); } + + return $success; +} + +/** + * Creates a local directory. + * + * @param string $localpath + * A local pathname. + * @param integer $mode + * The mode will be passed only to new directories in the path. Defaults to + * Drupal mode. + * @param boolean $recursive + * Whether or not directories should be created recursively. + * @param array $context + * Refer to http://php.net/manual/ref.stream.php + * + * @return boolean + * TRUE on success, or FALSE on failure. + */ +function drupal_mkdir_local($localpath, $mode = NULL, $recursive = FALSE, $context = NULL) { + $mode = isset($mode) ? $mode : variable_get('file_chmod_directory', 0775); + + // Note this does not literally recurse because we must create directories + // first, then change mode in reverse, to fix a PHP mkdir() bug. + // See http://drupal.org/node/1068266 for reasoning. + if ($recursive) { + // Get an array of path directories from from local directory path. + $directories = explode(DIRECTORY_SEPARATOR, $localpath); + $new = array(); + if (is_array($directories)) { + // Create directories in order, ignoring mode for the moment. + $directory_path = ''; + foreach ($directories as $directory) { + // Add to the current directory path, since we are descending. + $directory_path .= DIRECTORY_SEPARATOR . $directory; + + // Check if the directory already exists. If so, skip it. + if (file_exists($directory_path)) { + continue; + } + + // Set mkdir() $mode and $recursive defaults explicitly only so that we + // can also set $context (otherwise we would not bother passing them, + // since the defaults happen to be exactly what we want here). + if (!$success = mkdir($directory_path, 0777, FALSE, $context)) { + break; + } + + // Flag new directories so we know to change them mode below. + $new[] = $directory_path; + } + + // Now change mode in reverse. + $directories = array_reverse($directories); + foreach($directories as $directory) { + // Get the current directory path from part of the entire path, up to + // and including the current directory. Since we are in reverse now, use + // the position and length of the last directory with this name (since + // there may be multiple directories by the same name in the path). + $length = strrpos($localpath, $directory) + strlen($directory); + $directory_path = substr($localpath, 0, $length); + + // Check if the directory already existed. If so, leave the mode alone. + if (!in_array($directory_path, $new)) { + continue; + } + + if (!$success = drupal_chmod($directory_path, $mode)) { + break; + } + } + } + } + else { + // If this is not recursive, PHP's mkdir() needs no adjustment. + $success = mkdir($localpath, $mode, $recursive, $context); + } + + return $success; } /** diff --git a/core/lib/Drupal/Core/StreamWrapper/LocalStream.php b/core/lib/Drupal/Core/StreamWrapper/LocalStream.php index b6e1dd1..1f5d574 100644 --- a/core/lib/Drupal/Core/StreamWrapper/LocalStream.php +++ b/core/lib/Drupal/Core/StreamWrapper/LocalStream.php @@ -425,10 +425,10 @@ abstract class LocalStream implements StreamWrapperInterface { $localpath = $this->getLocalPath($uri); } if ($options & STREAM_REPORT_ERRORS) { - return mkdir($localpath, $mode, $recursive); + return drupal_mkdir_local($localpath, $mode, $recursive); } else { - return @mkdir($localpath, $mode, $recursive); + return @drupal_mkdir_local($localpath, $mode, $recursive); } }