### Eclipse Workspace Patch 1.0
#P Test Drupal 6
Index: includes/module.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/module.inc,v
retrieving revision 1.104
diff -u -r1.104 module.inc
--- includes/module.inc	27 Jun 2007 21:59:33 -0000	1.104
+++ includes/module.inc	11 Jul 2007 00:55:31 -0000
@@ -260,6 +260,10 @@
 
   foreach ($invoke_modules as $module) {
     module_invoke($module, 'enable');
+    // Check if node_access table needs rebuilding.
+    if (!node_access_needs_rebuild() && module_hook($module, 'node_grants')) {
+      node_access_needs_rebuild(TRUE);
+    }
   }
 }
 
@@ -273,6 +277,11 @@
   $invoke_modules = array();
   foreach ($module_list as $module) {
     if (module_exists($module)) {
+      // Check if node_access table needs rebuilding.
+      if (!node_access_needs_rebuild() && module_hook($module, 'node_grants')) {
+        node_access_needs_rebuild(TRUE);
+      }
+
       module_load_install($module);
       module_invoke($module, 'disable');
       db_query("UPDATE {system} SET status = 0, throttle = 0 WHERE type = 'module' AND name = '%s'", $module);
@@ -286,6 +295,11 @@
     // Force to regenerate the stored list of hook implementations.
     module_implements('', FALSE, TRUE);
   }
+
+  // If there remains no more node_access module, we can 'rebuild' right now.
+  if (node_access_needs_rebuild() && count(module_implements('node_grants')) == 0) {
+    node_access_rebuild();
+  }
 }
 
 /**
Index: modules/node/node.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/node.module,v
retrieving revision 1.853
diff -u -r1.853 node.module
--- modules/node/node.module	5 Jul 2007 08:48:57 -0000	1.853
+++ modules/node/node.module	11 Jul 2007 00:55:33 -0000
@@ -19,6 +19,17 @@
  * Implementation of hook_help().
  */
 function node_help($path, $arg) {
+  if ($arg[0] == 'admin' && $path != 'admin/content/node-settings/rebuild' && strpos($path, '#') === FALSE
+      && user_access('administer nodes') && node_access_needs_rebuild()) {
+    if ($path == 'admin/content/node-settings') {
+      $message = t('The content access permissions need to be rebuild.');
+    }
+    else {
+      $message = t('The content access permissions need to be rebuild. Please visit <a href="@node_access_rebuild">this page</a>.', array('@node_access_rebuild' => url('admin/content/node-settings/rebuild')));
+    }
+    drupal_set_message($message, 'error');
+  }
+
   switch ($path) {
     case 'admin/help#node':
       $output = '<p>'. t('All content in a website is stored and treated as <b>nodes</b>. Therefore nodes are any postings such as blogs, stories, polls and forums. The node module manages these content types and is one of the strengths of Drupal over other content management systems.') .'</p>';
@@ -1076,7 +1087,8 @@
  * Menu callback; presents general node configuration options.
  */
 function node_configure() {
-  // Only show rebuild button if there is 0 or more than 2 rows in node_access table, or if there are modules that implement node_grant.
+  // Only show rebuild button if there is 0 or more than 2 rows in node_access table,
+  // or if there are modules that implement node_grant.
   if (db_result(db_query('SELECT COUNT(*) FROM {node_access}')) != 1 || count(module_implements('node_grants')) > 0) {
     $status = '<p>'. t('If the site is experiencing problems with permissions to content, you may have to rebuild the permissions cache. Possible causes for permission problems are disabling modules or configuration changes to permissions. Rebuilding will remove all privileges to posts, and replace them with permissions based on the current modules and settings.') .'</p>';
     $status .= '<p>'. t('Rebuilding may take some time if there is a lot of content or complex permission settings. After rebuilding has completed posts will automatically use the new permissions.') .'</p>';
@@ -1129,9 +1141,8 @@
 /**
  * Handler for wipe confirmation
  */
-function node_configure_rebuild_confirm_submit(&$form, $form, &$form_state) {
-  node_access_rebuild();
-  drupal_set_message(t('The node access table has been rebuilt.'));
+function node_configure_rebuild_confirm_submit($form, &$form_state) {
+  node_access_rebuild(TRUE);
   $form_state['redirect'] = 'admin/content/node-settings';
   return;
 }
@@ -3021,7 +3032,7 @@
  */
 function node_access_acquire_grants($node) {
   $grants = module_invoke_all('node_access_records', $node);
-  if (!$grants) {
+  if (empty($grants)) {
     $grants[] = array('realm' => 'all', 'gid' => 0, 'grant_view' => 1, 'grant_update' => 0, 'grant_delete' => 0);
   }
   else {
@@ -3082,29 +3093,109 @@
   }
 }
 
+function node_access_needs_rebuild($rebuild = NULL) {
+  if (!isset($rebuild)) {
+    return variable_get('node_access_needs_rebuild', FALSE);
+  }
+  elseif ($rebuild) {
+    variable_set('node_access_needs_rebuild', TRUE);
+  }
+  else {
+    variable_del('node_access_needs_rebuild');
+  }
+}
+
 /**
  * Rebuild the node access database. This is occasionally needed by modules
  * that make system-wide changes to access levels.
+ *
+ * @param $batch_mode
+ *   Set to TRUE process in 'batch' mode, spawning processing over several
+ *   HTTP requests (and thus avoiding the risk of PHP timeout if the site
+ *   has a large number of nodes)
+ *
+ *   hook_update_N and any form submit handler are safe places to use this.
+ *   Other cases might consider using the non-batch mode.
+ *   TODO : note that it's not needed in hook_enable/disable anymore... 
  */
-function node_access_rebuild() {
+function node_access_rebuild($batch_mode = FALSE) {
   db_query("DELETE FROM {node_access}");
-  // only recalculate if site is using a node_access module
+  // Only recalculate if the site is using a node_access module.
   if (count(module_implements('node_grants'))) {
-    // If not in 'safe mode', increase the maximum execution time:
-    if (!ini_get('safe_mode')) {
-      set_time_limit(240);
+    if ($batch_mode) {
+      $batch = array(
+        'title' => t('Rebuilding content access permissions'),
+        'operations' => array(
+          array('node_access_rebuild_batch_operation', array()),
+        ),
+        'finished' => 'node_access_rebuild_batch_finished'
+      );
+      batch_set($batch);
     }
-    $result = db_query("SELECT nid FROM {node}");
-    while ($node = db_fetch_object($result)) {
-      node_access_acquire_grants(node_load($node->nid, NULL, TRUE));
+    else {
+      // If not in 'safe mode', increase the maximum execution time:
+      if (!ini_get('safe_mode')) {
+        set_time_limit(240);
+      }
+      $result = db_query("SELECT nid FROM {node}");
+      while ($node = db_fetch_object($result)) {
+        node_access_acquire_grants(node_load($node->nid, NULL, TRUE));
+      }
     }
   }
   else {
-    // not using any node_access modules. add the default grant.
+    // Not using any node_access modules. Add the default grant.
     db_query("INSERT INTO {node_access} VALUES (0, 0, 'all', 1, 0, 0)");
   }
+
+  if (!isset($batch)) {
+    drupal_set_message(t('The node access table has been rebuilt.'));
+    node_access_needs_rebuild(FALSE);
+    cache_clear_all();
+  }
+}
+
+/**
+ * Batch operation for node_access_rebuild_batch.
+ *
+ * This is a mutlistep operation : we go through all nodes by packs of 5.
+ * The batch engine interrupts processing and sends progress feedback
+ * after 1 second execution time.
+ */
+function node_access_rebuild_batch_operation(&$context) {
+  if (empty($context['sandbox'])) {
+    $context['sandbox']['progress'] = 0;
+    $context['sandbox']['current_node'] = 0;
+    $context['sandbox']['max'] = db_result(db_query('SELECT COUNT(DISTINCT nid) FROM {node}'));
+  }
+  $limit = 5;
+  $result = db_query_range("SELECT nid FROM {node} WHERE nid > %d ORDER BY nid ASC", $context['sandbox']['current_node'], 0, $limit);
+  while ($row = db_fetch_array($result)) {
+    $node = node_load($row['nid'], NULL, TRUE);
+    node_access_acquire_grants($node, FALSE);
+    $context['sandbox']['progress']++;
+    $context['sandbox']['current_node'] = $node->nid;
+    $context['message'] = $node->title;
+  }
+  if ($context['sandbox']['progress'] != $context['sandbox']['max']) {
+    $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
+  }
+}
+
+/**
+ * Post-processing for node_access_rebuild_batch
+ */
+function node_access_rebuild_batch_finished($success, $results, $operations) {
+  if ($success) {
+    drupal_set_message(t('The content access permissions have been rebuilt.'));
+    node_access_needs_rebuild(FALSE);
+  }
+  else {
+    drupal_set_message(t('The content access permissions have not been properly rebuilt.'), 'error');
+  }
   cache_clear_all();
 }
+
 /**
  * @} End of "defgroup node_access".
  */
