From 5e8eb9ad9018cb136cd4b3d843e69f214c4bc8a6 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Thu, 7 Jul 2016 15:55:59 -0400 Subject: [PATCH 1/1] Fix for Drupal issue #1899126, "Add wrappers to fix permission checks." --- includes/file.inc | 45 +++++++++++++++++++++++++++++++++++++++-- includes/updater.inc | 2 +- modules/system/system.admin.inc | 2 +- modules/system/system.install | 2 +- modules/system/system.module | 2 +- modules/user/user.test | 2 +- 6 files changed, 48 insertions(+), 7 deletions(-) diff --git a/includes/file.inc b/includes/file.inc index b15e454..eb712b3 100644 --- a/includes/file.inc +++ b/includes/file.inc @@ -443,7 +443,7 @@ function file_prepare_directory(&$directory, $options = FILE_MODIFY_PERMISSIONS) return FALSE; } // The directory exists, so check to see if it is writable. - $writable = is_writable($directory); + $writable = file_directory_is_writable($directory); if (!$writable && ($options & FILE_MODIFY_PERMISSIONS)) { return drupal_chmod($directory); } @@ -2199,6 +2199,26 @@ function file_get_mimetype($uri, $mapping = NULL) { } } + +/** + * Determines if a directory is writable by the web server. + * + * In order to be able to write files within the directory, the directory + * itself must be writable, and it must also have the executable bit set. This + * helper function checks both at the same time. + * + * @param $uri + * A URI or pathname pointing to the directory that will be checked. + * + * @return + * TRUE if the directory is writable and executable; FALSE otherwise. + */ +function file_directory_is_writable($uri) { + // By converting the URI to a normal path using drupal_realpath(), we can + // correctly handle both stream wrappers and normal paths. + return is_writable(drupal_realpath($uri)) && drupal_is_executable($uri); +} + /** * Sets the permissions on a file or directory. * @@ -2381,6 +2401,27 @@ function drupal_basename($uri, $suffix = NULL) { } /** + * Determines if a file or directory is executable. + * + * PHP's is_executable() does not fully support stream wrappers, so this + * function fills that gap. + * + * @param $uri + * A URI or pathname pointing to the file or directory that will be checked. + * + * @return + * TRUE if the file or directory is executable; FALSE otherwise. + * + * @see is_executable() + * @ingroup php_wrappers + */ +function drupal_is_executable($uri) { + // By converting the URI to a normal path using drupal_realpath(), we can + // correctly handle both stream wrappers and normal paths. + return is_executable(drupal_realpath($uri)); +} + +/** * Creates a directory using Drupal's default mode. * * PHP's mkdir() does not respect Drupal's default permissions mode. If a mode @@ -2518,7 +2559,7 @@ function file_directory_temp() { } foreach ($directories as $directory) { - if (is_dir($directory) && is_writable($directory)) { + if (is_dir($directory) && file_directory_is_writable($directory)) { $temporary_directory = $directory; break; } diff --git a/includes/updater.inc b/includes/updater.inc index d4f99e9..4b03a26 100644 --- a/includes/updater.inc +++ b/includes/updater.inc @@ -351,7 +351,7 @@ class Updater { * If the chmod should be applied recursively. */ public function makeWorldReadable(&$filetransfer, $path, $recursive = TRUE) { - if (!is_executable($path)) { + if (!drupal_is_executable($path)) { // Set it to read + execute. $new_perms = substr(sprintf('%o', fileperms($path)), -4, -1) . "5"; $filetransfer->chmod($path, intval($new_perms, 8), $recursive); diff --git a/modules/system/system.admin.inc b/modules/system/system.admin.inc index 8ef7d7c..6acb155 100644 --- a/modules/system/system.admin.inc +++ b/modules/system/system.admin.inc @@ -1729,7 +1729,7 @@ function system_performance_settings() { ); $directory = 'public://'; - $is_writable = is_dir($directory) && is_writable($directory); + $is_writable = is_dir($directory) && file_directory_is_writable($directory); $disabled = !$is_writable; $disabled_message = ''; if (!$is_writable) { diff --git a/modules/system/system.install b/modules/system/system.install index fa794eb..4233d17 100644 --- a/modules/system/system.install +++ b/modules/system/system.install @@ -365,7 +365,7 @@ function system_requirements($phase) { if ($phase == 'install') { file_prepare_directory($directory, FILE_CREATE_DIRECTORY); } - $is_writable = is_writable($directory); + $is_writable = file_directory_is_writable($directory); $is_directory = is_dir($directory); if (!$is_writable || !$is_directory) { $description = ''; diff --git a/modules/system/system.module b/modules/system/system.module index 8a080fa..3e33301 100644 --- a/modules/system/system.module +++ b/modules/system/system.module @@ -2190,7 +2190,7 @@ function system_check_directory($form_element) { watchdog('file system', 'The directory %directory does not exist and could not be created.', array('%directory' => $directory), WATCHDOG_ERROR); } - if (is_dir($directory) && !is_writable($directory) && !drupal_chmod($directory)) { + if (is_dir($directory) && !file_directory_is_writable($directory) && !drupal_chmod($directory)) { // If the directory is not writable and cannot be made so. form_set_error($form_element['#parents'][0], t('The directory %directory exists but is not writable and could not be made writable.', array('%directory' => $directory))); watchdog('file system', 'The directory %directory exists but is not writable and could not be made writable.', array('%directory' => $directory), WATCHDOG_ERROR); diff --git a/modules/user/user.test b/modules/user/user.test index 63143c3..312d7dd 100644 --- a/modules/user/user.test +++ b/modules/user/user.test @@ -1043,7 +1043,7 @@ class UserPictureTestCase extends DrupalWebTestCase { $picture_path = $file_dir . $picture_dir; $pic_check = file_prepare_directory($picture_path, FILE_CREATE_DIRECTORY); - $this->_directory_test = is_writable($picture_path); + $this->_directory_test = file_directory_is_writable($picture_path); $this->assertTrue($this->_directory_test, "The directory $picture_path doesn't exist or is not writable. Further tests won't be made."); } -- 2.7.3