$t('This patch file has been moved or deleted by the administrator. Please restore it, so we can verify that the patch has been properly applied.'), 'severity' => REQUIREMENT_ERROR, 'value' => $t('Unable to check'), ); } elseif (count($unpatched_files) == 0) { $requirements[$key] += array( 'severity' => REQUIREMENT_OK, 'value' => $t('Applied'), ); } else { $requirements[$key] += array( 'description' => $t('This patch has not been properly applied to the following files (or the patch has been updated):') . '
' . theme('item_list', $unpatched_files) . '
' . t('Please consult the installation instructions in the included README.txt.'), 'severity' => REQUIREMENT_ERROR, 'value' => $t('Not/incompletely applied patch or updated patch.'), ); } } /** * Check if a patch has been applied, given a set of patterns. */ function _cdn_requirements_check_patch_applied($patterns) { $drupal_root = realpath('.'); $patched = TRUE; $unpatched_files = array(); foreach ($patterns as $kind => $details) { foreach ($details as $file_info => $patterns) { foreach ($patterns as $pattern) { if ($kind == 'core') { // Don't check core patches against Pressflow. if (!_cdn_requirements_check_pressflow()) { $filename = $file_info; $full_path = $drupal_root . '/' . $filename; } } else { list($name, $filename) = explode('|', $file_info); $full_path = $drupal_root . '/' . drupal_get_path($kind, $name) . '/' . $filename; } if ($full_path) { $match = preg_match('|' . preg_quote($pattern) . '|m', file_get_contents($full_path)); // If it didn't match, try allowing \r\n line endings and see if it // it then matches. This is of course also qualifies as a correctly // applied patch. if (!$match) { $match = preg_match('|' . preg_quote($pattern) . '|m', str_replace("\n", "\r\n", file_get_contents($full_path))); } $patched = $patched && $match; // Remember unpatched files. if (!$match && !in_array($full_path, $unpatched_files)) { $unpatched_files[] = $full_path; } } } } } return $unpatched_files; } /** * Generate patterns for a patch, given the full path to a patch. This * effectively parses the patch and stores it in a meaningful structure. */ function _cdn_requirements_generate_patterns_for_patch($full_path) { // The patch file must exist, otherwise we can't generate any patterns. if (!file_exists($full_path)) { return FALSE; } $file_kinds = array( '/cvs/drupal/drupal/modules' => 'core', '/cvs/drupal/drupal/themes' => 'core', '/cvs/drupal/drupal' => 'core', '/cvs/drupal-contrib/contributions/modules' => 'module', '/cvs/drupal-contrib/contributions/themes' => 'theme', ); $fp = fopen($full_path, 'r'); $patch_block = ''; while (!feof($fp) ) { $line = fgets($fp); // Check if the current line indicates the next file. if (drupal_substr($line, 0, 7) == 'Index: ') { $file_to_patch = drupal_substr($line, 7, drupal_strlen($line) - 7 - 1); } // Find out which kind of file this is: a core file, a module file or a // theme file. if (drupal_substr($line, 0, 10) == 'RCS file: ') { $rcs_file = drupal_substr($line, 10); foreach ($file_kinds as $patch_rcs_file => $patch_type) { if (drupal_substr($rcs_file, 0, drupal_strlen($patch_rcs_file)) == $patch_rcs_file) { $kind = $patch_type; // For files of the module or theme kind, also store the exact name. if ($kind == 'module' || $kind == 'theme') { $start = drupal_strlen($patch_rcs_file) + 1; $module_or_theme = drupal_substr($rcs_file, $start, strpos($rcs_file, '/', $start) - $start); } break; } } } // Finally, store the lines that have been added (+): concatenate them in // a "patch block". if ($line[0] == '+' && ($line[1] == ' ' | $line[1] == "\n")) { $patch_block .= drupal_substr($line, 1); } // When we encounter a line that has not been added (+), the current patch // block has ended and we should store it as a pattern. else { if ($patch_block != '') { if ($kind == 'core') { $patterns[$patch_type][$file_to_patch][] = $patch_block; } else { $patterns[$patch_type][$module_or_theme . '|' . $file_to_patch][] = $patch_block; } } $patch_block = ''; } } fclose($fp); return $patterns; } /** * Generates the patterns for the core patch. */ function _cdn_requirements_core_patch_patterns() { return _cdn_requirements_generate_patterns_for_patch(drupal_get_path('module', 'cdn') . '/patches/drupal6.patch'); } /** * Generates the patterns for the ImageCache patch. */ function _cdn_requirements_imagecache_patch_patterns() { return _cdn_requirements_generate_patterns_for_patch(drupal_get_path('module', 'cdn') . '/patches/imagecache.patch'); } /** * Checks if the environment is Pressflow or not. */ function _cdn_requirements_check_pressflow() { $profile = realpath('.') . '/profiles/default/default.profile'; if (!file_exists($profile)) { return FALSE; } include_once $profile; $default = default_profile_details(); return $default['name'] == 'Pressflow'; }