diff --git a/includes/menu.inc b/includes/menu.inc
index f1b375f52a6f355110ed5beb9e1c54af2c0edd6d..50352dbcbec8c4d0fcc75bfe97969d506336021e 100644
--- a/includes/menu.inc
+++ b/includes/menu.inc
@@ -360,9 +360,12 @@ function menu_execute_active_handler($path = NULL) {
  * @return
  *   Returns TRUE for success, FALSE if an object cannot be loaded
  */
-function _menu_load_objects($item, &$map) {
-  if ($item['load_functions']) {
-    $load_functions = unserialize($item['load_functions']);
+function _menu_load_objects(&$item, &$map) {
+  if ($load_functions = $item['load_functions']) {
+    // If someone calls this function twice, then unserialize will fail.
+    if ($load_functions_unserialized = unserialize($load_functions)) {
+      $load_functions = $load_functions_unserialized;
+    }
     $path_map = $map;
     foreach ($load_functions as $index => $function) {
       if ($function) {
@@ -373,6 +376,7 @@ function _menu_load_objects($item, &$map) {
           // some processing. In this case the $function is the key to the
           // load_function array, and the value is the list of arguments.
           list($function, $args) = each($function);
+          $load_functions[$index] = $function;
 
           // Some arguments are placeholders for dynamic items to process.
           foreach ($args as $i => $arg) {
@@ -387,6 +391,9 @@ function _menu_load_objects($item, &$map) {
               // the map.
               $args[$i] = &$map;
             }
+            if (is_int($arg)) {
+              $args[$i] = isset($path_map[$arg]) ? $path_map[$arg] : '';
+            }
           }
           array_unshift($args, $value);
           $return = call_user_func_array($function, $args);
@@ -403,6 +410,7 @@ function _menu_load_objects($item, &$map) {
         $map[$index] = $return;
       }
     }
+    $item['load_functions'] = $load_functions;
   }
   return TRUE;
 }
@@ -609,6 +617,31 @@ function _menu_link_translate(&$item) {
   return $map;
 }
 
+/**
+ * Get a loaded object from a router item.
+ *
+ * menu_get_object() will provide you the current node on paths like node/5,
+ * node/5/revisions/48 etc. menu_get_object('user') will give you the user
+ * account on user/5 etc.
+ *
+ * @param $type
+ *   Type of the object. These appear in hook_menu definitons as %type. Core
+ *   provides aggregator_feed, aggregator_category, contact, filter_format,
+ *   forum_term, menu, menu_link, node, taxonomy_vocabulary, user. See the
+ *   relevant {$type}_load function for more on each. Defaults to node.
+ * @param $position
+ *   The expected position for $type object. For node/%node this is 1, for
+ *   comment/reply/%node this is 2. Defaults to 1.
+ * @param $path
+ *   See @menu_get_item for more on this. Defaults to the current path.
+ */
+function menu_get_object($type = 'node', $position = 1, $path = NULL) {
+  $router_item = menu_get_item($path);
+  if (isset($router_item['load_functions'][$position]) && !empty($router_item['map'][$position]) && $router_item['load_functions'][$position] == $type .'_load') {
+    return $router_item['map'][$position];
+  }
+}
+
 /**
  * Render a menu tree based on the current path.
  *
diff --git a/includes/theme.inc b/includes/theme.inc
index 45655c58ade00b3c9f9a0d609577d69bfd03be5c..42c54783f1f51dd294062b23b99c502b62e68cba 100644
--- a/includes/theme.inc
+++ b/includes/theme.inc
@@ -1736,8 +1736,8 @@ function template_preprocess_page(&$variables) {
   // Closure should be filled last.
   $variables['closure']           = theme('closure');
 
-  if ((arg(0) == 'node') && is_numeric(arg(1))) {
-    $variables['node'] = node_load(arg(1));
+  if ($node = menu_get_object()) {
+    $variables['node'] = $node;
   }
 
   // Compile a list of classes that are going to be applied to the body element.
diff --git a/modules/node/node.module b/modules/node/node.module
index 76c000a5014d5d903cc1c93105cd39a194b538f5..5839b5889085f5303a833296b56db15f083af216 100644
--- a/modules/node/node.module
+++ b/modules/node/node.module
@@ -1043,7 +1043,10 @@ function node_build_content($node, $teaser = FALSE, $page = FALSE) {
 /**
  * Generate a page displaying a single node, along with its comments.
  */
-function node_show($node, $cid) {
+function node_show($node, $cid, $message = FALSE) {
+  if ($message) {
+    drupal_set_title(t('Revision of %title from %date', array('%title' => $node->title, '%date' => format_date($node->revision_timestamp))));
+  }
   $output = node_view($node, FALSE, TRUE);
 
   if (function_exists('comment_render') && $node->comment) {
@@ -1069,7 +1072,7 @@ function theme_node_log_message($log) {
  * Implementation of hook_perm().
  */
 function node_perm() {
-  $perms = array('administer content types', 'administer nodes', 'access content', 'view revisions', 'revert revisions');
+  $perms = array('administer content types', 'administer nodes', 'access content', 'view revisions', 'revert revisions', 'delete revisions');
 
   foreach (node_get_types() as $type) {
     if ($type->module == 'node') {
@@ -1304,8 +1307,31 @@ function node_link($type, $node = NULL, $teaser = FALSE) {
   return $links;
 }
 
-function _node_revision_access($node) {
-  return (user_access('view revisions') || user_access('administer nodes')) && node_access('view', $node) && db_result(db_query('SELECT COUNT(vid) FROM {node_revisions} WHERE nid = %d', $node->nid)) > 1;
+function _node_revision_access($node, $op = 'view') {
+  static $access = array();
+  if (!isset($access[$node->vid])) {
+    $node_current_revision = node_load($node->nid);
+    $is_current_revision = $node_current_revision->vid == $node->vid;
+    // There should be at least two revisions. If the vid of the given node
+    // and the vid of the current revision differs, then we already have two
+    // different revisions so there is no need for a separate database check.
+    // Also, if you try to revert to or delete the current revision, that's
+    // not good.
+    if ($is_current_revision && (db_result(db_query('SELECT COUNT(vid) FROM {node_revisions} WHERE nid = %d', $node->nid)) == 1 || $op == 'update' || $op == 'delete')) {
+      $access[$node->vid] = FALSE;
+    }
+    elseif (user_access('administer nodes')) {
+      $access[$node->vid] = TRUE;
+    }
+    else {
+      $map = array('view' => 'view revisions', 'update' => 'revert revisions', 'delete' => 'delete revisions');
+      // First check the user permission, second check the access to the
+      // current revision and finally, if the node passed in is not the current
+      // revision then access to that, too.
+      $access[$node->vid] = isset($map[$op]) && user_access($map[$op]) && node_access($op, $node_current_revision) && ($is_current_revision || node_access($op, $node));
+    }
+  }
+  return $access[$node->vid];
 }
 
 function _node_add_access() {
@@ -1450,28 +1476,37 @@ function node_menu() {
     'type' => MENU_CALLBACK);
   $items['node/%node/revisions'] = array(
     'title' => 'Revisions',
-    'page callback' => 'node_revisions',
+    'page callback' => 'node_revision_overview',
+    'page arguments' => array(1),
     'access callback' => '_node_revision_access',
     'access arguments' => array(1),
     'weight' => 2,
     'file' => 'node.pages.inc',
     'type' => MENU_LOCAL_TASK,
   );
+  $items['node/%node/revisions/%/view'] = array(
+    'title' => 'Revisions',
+    'page callback' => 'node_show',
+    'page arguments' => array(1, NULL, TRUE),
+    'type' => MENU_CALLBACK,
+  );
   $items['node/%node/revisions/%/revert'] = array(
     'title' => 'Revert to earlier revision',
-    'page callback' => 'node_revision_revert',
-    'page arguments' => array(1, 3),
+    'load arguments' => array(3),
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('node_revision_revert_confirm', 1),
     'access callback' => '_node_revision_access',
-    'access arguments' => array(1, 3),
+    'access arguments' => array(1, 'update'),
     'file' => 'node.pages.inc',
     'type' => MENU_CALLBACK,
   );
   $items['node/%node/revisions/%/delete'] = array(
     'title' => 'Delete earlier revision',
-    'page callback' => 'node_revision_delete',
-    'page arguments' => array(1, 3),
+    'load arguments' => array(3),
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('node_revision_delete_confirm', 1),
     'access callback' => '_node_revision_access',
-    'access arguments' => array(1, 3),
+    'access arguments' => array(1, 'delete'),
     'file' => 'node.pages.inc',
     'type' => MENU_CALLBACK,
   );
diff --git a/modules/node/node.pages.inc b/modules/node/node.pages.inc
index 1092240f13aa31d91391b6cc949617a650ddfb51..6861626c6308a69a445e7e7813196dbcb813c409 100644
--- a/modules/node/node.pages.inc
+++ b/modules/node/node.pages.inc
@@ -505,38 +505,6 @@ function node_delete_confirm_submit($form, &$form_state) {
   return;
 }
 
-/**
- * Menu callback for revisions related activities.
- */
-function node_revisions() {
-  if (is_numeric(arg(1)) && arg(2) == 'revisions') {
-    $op = arg(4) ? arg(4) : 'overview';
-    switch ($op) {
-      case 'overview':
-        $node = node_load(arg(1));
-        if ((user_access('view revisions') || user_access('administer nodes')) && node_access('view', $node)) {
-          return node_revision_overview($node);
-        }
-        drupal_access_denied();
-        return;
-      case 'view':
-        if (is_numeric(arg(3))) {
-          $node = node_load(arg(1), arg(3));
-          if ($node->nid) {
-            if ((user_access('view revisions') || user_access('administer nodes')) && node_access('view', $node)) {
-              drupal_set_title(t('Revision of %title from %date', array('%title' => $node->title, '%date' => format_date($node->revision_timestamp))));
-              return node_show($node, arg(2));
-            }
-            drupal_access_denied();
-            return;
-          }
-        }
-        break;
-    }
-  }
-  drupal_not_found();
-}
-
 /**
  * Generate an overview table of older revisions of a node.
  */
@@ -553,7 +521,7 @@ function node_revision_overview($node) {
     $revert_permission = TRUE;
   }
   $delete_permission = FALSE;
-  if (user_access('administer nodes')) {
+  if ((user_access('delete revisions') || user_access('administer nodes')) && node_access('delete', $node)) {
     $delete_permission = TRUE;
   }
   foreach ($revisions as $revision) {
@@ -582,25 +550,6 @@ function node_revision_overview($node) {
   return theme('table', $header, $rows);
 }
 
-/**
- * Revert to the revision with the specified revision number. A node and nodeapi "update" event is triggered
- * (via the node_save() call) when a revision is reverted.
- */
-function node_revision_revert($node, $revision) {
-  global $user;
-
-  if ((user_access('revert revisions') || user_access('administer nodes')) && node_access('update', $node)) {
-    $node_revision = node_load($node->nid, $revision);
-    if ($node_revision->vid) {
-      return drupal_get_form('node_revision_revert_confirm', $node_revision);
-    }
-    else {
-      drupal_set_message(t('You tried to revert to an invalid revision.'), 'error');
-      drupal_goto('node/'. $node->nid .'/revisions');
-    }
-  }
-  drupal_access_denied();
-}
 /**
  * Ask for confirmation of the reversion to prevent against CSRF attacks.
  */
@@ -624,28 +573,6 @@ function node_revision_revert_confirm_submit($form, &$form_state) {
   $form_state['redirect'] = 'node/'. $node_revision->nid .'/revisions';
 }
 
-/**
- * Delete the revision with specified revision number. A "delete revision" nodeapi event is invoked when a
- * revision is deleted.
- */
-function node_revision_delete($node, $revision) {
-  if (user_access('administer nodes')) {
-    if (node_access('delete', $node)) {
-      // Don't allow deleting the current revision.
-      if ($revision != $node->vid) {
-        // Load the specific revision instead of the current one.
-        $node_revision = node_load($node->nid, $revision);
-        return drupal_get_form('node_revision_delete_confirm', $node_revision);
-      }
-      else {
-        drupal_set_message(t('Deletion failed. You tried to delete the current revision.'));
-        drupal_goto('node/'. $node->nid .'/revisions');
-      }
-    }
-  }
-  drupal_access_denied();
-}
-
 function node_revision_delete_confirm($form_state, $node_revision) {
   $form['#node_revision'] = $node_revision;
   return confirm_form($form, t('Are you sure you want to delete the revision from %revision-date?', array('%revision-date' =>  format_date($node_revision->revision_timestamp))), 'node/'. $node_revision->nid .'/revisions', t('This action cannot be undone.'), t('Delete'), t('Cancel'));