summaryrefslogtreecommitdiff
path: root/modules/update
diff options
context:
space:
mode:
authorAngie Byron <webchick@24967.no-reply.drupal.org>2010-12-06 06:50:08 +0000
committerAngie Byron <webchick@24967.no-reply.drupal.org>2010-12-06 06:50:08 +0000
commit0369f3f80874c5f61f29f4af400c36f879e21ec1 (patch)
treebe3df28920e9487b5d8e393499968ef0c7593449 /modules/update
parentaa71f4abe49348762d1a7cefe1a7b7eb53fbe96f (diff)
downloadbrdo-0369f3f80874c5f61f29f4af400c36f879e21ec1.tar.gz
brdo-0369f3f80874c5f61f29f4af400c36f879e21ec1.tar.bz2
#936490 by dww, tstoeckler, haydeniv, Bojhan: Fixed Update module should verify downloaded tarballs and propagate errors correctly
Diffstat (limited to 'modules/update')
-rw-r--r--modules/update/update.api.php8
-rw-r--r--modules/update/update.manager.inc37
-rw-r--r--modules/update/update.module75
3 files changed, 101 insertions, 19 deletions
diff --git a/modules/update/update.api.php b/modules/update/update.api.php
index b02b22300..ef78cbf42 100644
--- a/modules/update/update.api.php
+++ b/modules/update/update.api.php
@@ -115,16 +115,18 @@ function hook_update_status_alter(&$projects) {
* The directory that the archive was extracted into.
*
* @return
- * If there is a problem, return any non-null value. If there is no problem,
- * don't return anything (null).
+ * If there are any problems, return an array of error messages. If there are
+ * no problems, return an empty array.
*
* @see update_manager_archive_verify()
*/
function hook_verify_update_archive($project, $archive_file, $directory) {
+ $errors = array();
if (!file_exists($directory)) {
- return TRUE;
+ $errors[] = t('The %directory does not exist.', array('%directory' => $directory));
}
// Add other checks on the archive integrity here.
+ return $errors;
}
/**
diff --git a/modules/update/update.manager.inc b/modules/update/update.manager.inc
index d149027bd..7649852bf 100644
--- a/modules/update/update.manager.inc
+++ b/modules/update/update.manager.inc
@@ -557,11 +557,16 @@ function update_manager_install_form_submit($form, &$form_state) {
// Unfortunately, we can only use the directory name for this. :(
$project = drupal_substr($files[0], 0, -1);
- try {
- update_manager_archive_verify($project, $local_cache, $directory);
- }
- catch (Exception $e) {
- form_set_error($field, $e->getMessage());
+ $archive_errors = update_manager_archive_verify($project, $local_cache, $directory);
+ if (!empty($archive_errors)) {
+ form_set_error($field, array_shift($archive_errors));
+ // @todo: Fix me in D8: We need a way to set multiple errors on the same
+ // form element and have all of them appear!
+ if (!empty($archive_errors)) {
+ foreach ($archive_errors as $error) {
+ drupal_set_message($error, 'error');
+ }
+ }
return;
}
@@ -682,15 +687,13 @@ function update_manager_archive_extract($file, $directory) {
* @param string $directory
* The directory that the archive was extracted into.
*
- * @return void
- * @throws Exception on failure.
+ * @return array
+ * An array of error messages to display if the archive was invalid. If
+ * there are no errors, it will be an empty array.
*
*/
function update_manager_archive_verify($project, $archive_file, $directory) {
- $failures = module_invoke_all('verify_update_archive', $project, $archive_file, $directory);
- if (!empty($failures)) {
- throw new Exception(t('Unable to extract %file', array('%file' => $archive_file)));
- }
+ return module_invoke_all('verify_update_archive', $project, $archive_file, $directory);
}
/**
@@ -770,11 +773,13 @@ function update_manager_batch_project_get($project, $url, &$context) {
}
// Verify it.
- try {
- update_manager_archive_verify($project, $local_cache, $extract_directory);
- }
- catch (Exception $e) {
- $context['results']['errors'][$project] = $e->getMessage();
+ $archive_errors = update_manager_archive_verify($project, $local_cache, $extract_directory);
+ if (!empty($archive_errors)) {
+ // We just need to make sure our array keys don't collide, so use the
+ // numeric keys from the $archive_errors array.
+ foreach ($archive_errors as $key => $error) {
+ $context['results']['errors']["$project-$key"] = $error;
+ }
return;
}
diff --git a/modules/update/update.module b/modules/update/update.module
index ee0e91358..9f2764c28 100644
--- a/modules/update/update.module
+++ b/modules/update/update.module
@@ -641,6 +641,81 @@ function theme_update_last_check($variables) {
}
/**
+ * Implements hook_verify_update_archive().
+ *
+ * First, we ensure that the archive isn't a copy of Drupal core, which the
+ * Update manager does not yet support. @see http://drupal.org/node/606592
+ *
+ * Then, we make sure that every module included in the archive has an info
+ * file.
+ *
+ * Finally, we check that all the .info files claim the code is compatible
+ * with the current version of Drupal core.
+ *
+ * @see drupal_system_listing()
+ * @see _system_rebuild_module_data()
+ */
+function update_verify_update_archive($project, $archive_file, $directory) {
+ $errors = array();
+
+ // Make sure this isn't a tarball of Drupal core.
+ if (
+ file_exists("$directory/$project/index.php")
+ && file_exists("$directory/$project/update.php")
+ && file_exists("$directory/$project/includes/bootstrap.inc")
+ && file_exists("$directory/$project/modules/node/node.module")
+ && file_exists("$directory/$project/modules/system/system.module")
+ ) {
+ return array(
+ 'no-core' => t('Automatic updating of Drupal core is not supported. See the <a href="@upgrade-guide">upgrade guide</a> for information on how to update Drupal core manually.', array('@upgrade-guide' => 'http://drupal.org/upgrade')),
+ );
+ }
+
+ // Look for any .module file that doesn't have a corresponding .info file.
+ $missing_info = array();
+ $files = file_scan_directory("$directory/$project", '/^' . DRUPAL_PHP_FUNCTION_PATTERN . '\.module$/', array('key' => 'name', 'min_depth' => 0));
+ foreach ($files as $key => $file) {
+ // If it has no info file, set an error.
+ $info_file = dirname($file->uri) . '/' . $file->name . '.info';
+ if (!file_exists($info_file)) {
+ $missing_info[] = $file->filename;
+ }
+ }
+ if (!empty($missing_info)) {
+ $errors[] = format_plural(
+ count($missing_info),
+ '%archive_file contains %names which is missing an info file.',
+ '%archive_file contains the following modules which are missing info files: %names',
+ array('%archive_file' => basename($archive_file), '%names' => implode(', ', $missing_info))
+ );
+ }
+
+ // Parse all the .info files and make sure they're compatible with this
+ // version of Drupal core.
+ $incompatible = array();
+ $files = file_scan_directory("$directory/$project", '/^' . DRUPAL_PHP_FUNCTION_PATTERN . '\.info/', array('key' => 'name', 'min_depth' => 0));
+ foreach ($files as $key => $file) {
+ // Get the .info file for the module or theme this file belongs to.
+ $info = drupal_parse_info_file($file->uri);
+
+ // If the module or theme is incompatible with Drupal core, set an error.
+ if (empty($info['core']) || $info['core'] != DRUPAL_CORE_COMPATIBILITY) {
+ $incompatible[] = $info['name'];
+ }
+ }
+ if (!empty($incompatible)) {
+ $errors[] = format_plural(
+ count($incompatible),
+ '%archive_file contains a version of %names that is not compatible with Drupal !version.',
+ '%archive_file contains versions of modules or themes that are not compatible with Drupal !version: %names',
+ array('!version' => DRUPAL_CORE_COMPATIBILITY, '%archive_file' => basename($archive_file), '%names' => implode(', ', $incompatible))
+ );
+ }
+
+ return $errors;
+}
+
+/**
* @defgroup update_status_cache Private update status cache system
* @{
*