diff -u b/includes/bootstrap.inc b/includes/bootstrap.inc --- b/includes/bootstrap.inc +++ b/includes/bootstrap.inc @@ -835,7 +835,7 @@ function drupal_get_filename($type, $name, $filename = NULL) { // The location of files will not change during the request, so do not use // drupal_static(). - static $files = array(), $dirs = array(); + static $files = array(), $dirs = array(), $files_scanned = array(); // Profiles are a special case: they have a fixed location and naming. if ($type == 'profile') { @@ -860,8 +860,13 @@ try { if (function_exists('db_query')) { $file = db_query("SELECT filename FROM {system} WHERE name = :name AND type = :type", array(':name' => $name, ':type' => $type))->fetchField(); - if ($file !== FALSE && file_exists(DRUPAL_ROOT . '/' . $file)) { - $files[$type][$name] = $file; + if ($file !== FALSE) { + if (file_exists(DRUPAL_ROOT . '/' . $file)) { + $files[$type][$name] = $file; + } + else { + $database_file_exists = FALSE; + } } } } @@ -894,9 +899,15 @@ $missing = array(); try { if (function_exists('cache_get')) { - $cache = cache_get('drupal_get_filename:missing'); + $cache = cache_get('drupal_get_filename:missing', 'cache_bootstrap'); if (!empty($cache->data)) { - $missing = $cache->data; + // Merge the changes already done in the current request (including + // the setting of missing records to NULL) into the values saved + // in persistent cache. + $missing = $cache->data + $missing; + // Set a flag so we know that we've already done a merge with values + // in cache_get(). + $missing['#cache_merge_done'] = TRUE; } } } @@ -905,6 +916,18 @@ } } + if (isset($missing[$type][$name]) && is_string($missing[$type][$name])) { + // This file has moved and the result of a file scan had been cached. + if (file_exists($missing[$type][$name])) { + $files[$type][$name] = $missing[$type][$name]; + } + else { + // File is not available anymore at its new location. Re-do file scan. + $missing[$type][$name] = NULL; + $missing['#write_cache'] = TRUE; + } + } + if (!isset($dirs[$dir][$extension]) && !isset($missing[$type][$name])) { $dirs[$dir][$extension] = TRUE; if (!function_exists('drupal_system_listing')) { @@ -916,7 +939,18 @@ // called more than once in the same page request. $matches = drupal_system_listing("/^" . DRUPAL_PHP_FUNCTION_PATTERN . "\.$extension$/", $dir, 'name', 0); foreach ($matches as $matched_name => $file) { - $files[$type][$matched_name] = $file->uri; + $files_scanned[$type][$matched_name] = $file->uri; + } + } + + if (isset($files_scanned[$type][$name])) { + $files[$type][$name] = $files_scanned[$type][$name]; + if (isset($database_file_exists) && $database_file_exists === FALSE) { + // This file has moved. Cache its new location into the missing files + // cache. + $missing[$type][$name] = $files_scanned[$type][$name]; + $missing['#write_cache'] = TRUE; + trigger_error(format_string('The following @type has moved on the file system: @name. Clearing caches may help fix this. For more information, see the documentation page.', array('@type' => $type, '@name' => $name, '@documentation' => 'https://www.drupal.org/node/2487215')), E_USER_WARNING); } } } @@ -933,14 +967,30 @@ - try { - if (function_exists('cache_set')) { - cache_set('drupal_get_filename:missing', $missing, 'cache'); - } - } - catch (Exception $e) { - // Hide the error. - } + $missing['#write_cache'] = TRUE; } trigger_error(format_string('The following @type is missing from the file system: @name. For more information, see the documentation page.', array('@type' => $type, '@name' => $name, '@documentation' => 'https://www.drupal.org/node/2487215')), E_USER_WARNING); } } /** + * Writes the missing and moved files to persistent cache. + * + * @param array $missing + * The array of missing and moved files. + */ +function drupal_missing_write_cache() { + if (drupal_get_bootstrap_phase() != DRUPAL_BOOTSTRAP_FULL) { + return; + } + $missing = &drupal_static('drupal_get_filename:missing'); + if (isset($missing['#write_cache'])) { + if (!isset($missing['#cache_merge_done'])) { + $cache = cache_get('drupal_get_filename:missing', 'cache_bootstrap'); + if (isset($cache->data)) { + $missing = $cache->data + $missing; + } + } + $missing['#write_cache'] = NULL; + cache_set('drupal_get_filename:missing', $missing, 'cache_bootstrap'); + } +} + +/** diff -u b/modules/simpletest/tests/bootstrap.test b/modules/simpletest/tests/bootstrap.test --- b/modules/simpletest/tests/bootstrap.test +++ b/modules/simpletest/tests/bootstrap.test @@ -382,7 +382,7 @@ } /** - * Whether the filename test triggered the right error. + * Whether the filename test triggered the right error. * * Used by BootstrapGetFilenameTestCase::testDrupalGetFilename(). * only in patch2: unchanged: --- a/includes/common.inc +++ b/includes/common.inc @@ -2751,6 +2751,7 @@ function drupal_page_footer() { _registry_check_code(REGISTRY_WRITE_LOOKUP_CACHE); drupal_cache_system_paths(); module_implements_write_cache(); + drupal_missing_write_cache(); system_run_automated_cron(); }