Index: modules/node/node.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/node.module,v
retrieving revision 1.1188
diff -u -r1.1188 node.module
--- modules/node/node.module	22 Dec 2009 20:38:23 -0000	1.1188
+++ modules/node/node.module	23 Dec 2009 00:20:27 -0000
@@ -1736,6 +1736,7 @@
   return $output;
 }
 
+// TODO: can node_load() be avoided here?
 function _node_revision_access($node, $op = 'view') {
   $access = &drupal_static(__FUNCTION__, array());
   if (!isset($access[$node->vid])) {
@@ -2462,15 +2463,34 @@
 function node_access($op, $node, $account = NULL) {
   global $user;
 
-  if (!$node || !in_array($op, array('view', 'update', 'delete', 'create'), TRUE)) {
-    // If there was no node to check against, or the $op was not one of the
-    // supported ones, we return access denied.
+  if (!in_array($op, array('view', 'update', 'delete', 'create'), TRUE)) {
+    // If $op was not one of the supported ones, we return access denied.
     return FALSE;
   }
-  // If no user object is supplied, the access check is for the current user.
-  if (empty($account)) {
+
+  // If no account is supplied, the access check is for the current user.
+  if (!isset($account) || (is_numeric($account) && $account == $user->uid)) {
     $account = $user;
   }
+  elseif (is_numeric($account)) {
+    // Construct a skeleton $account if only a uid is given.
+    $account = (object)array('uid' => intval($account));
+  }
+
+  if ($op == 'create') {
+    // If $op is 'create', all we have is $node->type.
+    $node = (object)array('nid' => NULL, 'type' => $node, 'uid' => NULL);
+  }
+  else {
+    // If given a nid in place of $node, construct a skeleton $node.
+    if (is_numeric($node)) {
+      $node = db_query("SELECT nid, type, uid, status FROM {node} WHERE nid = :nid", array(':nid' => $node))->fetch();
+    }
+    // If the node does not exist, the operation is not allowed.
+    if (!$node) {
+      return FALSE;
+    }
+  }
 
   if (user_access('bypass node access', $account)) {
     return TRUE;
@@ -2485,7 +2505,7 @@
   // - At least one module says to grant access.
   // If no module specified either allow or deny, we fall back to the
   // node_access table.
-  $access = module_invoke_all('node_access', $node, $op, $account);
+  $access = module_invoke_all('node_access', $op, $node->type, $account->uid, $node->nid, $node->uid);
   if (in_array(NODE_ACCESS_DENY, $access, TRUE)) {
     return FALSE;
   }
@@ -2494,7 +2514,7 @@
   }
 
   // Check if authors can view their own unpublished nodes.
-  if ($op == 'view' && !$node->status && user_access('view own unpublished content', $account) && $account->uid == $node->uid && $account->uid != 0) {
+  if ($op == 'view' && !$node->status && $account->uid != 0 && $account->uid == $node->uid && user_access('view own unpublished content', $account)) {
     return TRUE;
   }
 
@@ -2512,7 +2532,7 @@
     $query->range(0, 1);
 
     $grants = db_or();
-    foreach (node_access_grants($op, $account) as $realm => $gids) {
+    foreach (node_access_grants($op, $account->uid) as $realm => $gids) {
       foreach ($gids as $gid) {
         $grants->condition(db_and()
           ->condition('gid', $gid)
@@ -2534,22 +2554,21 @@
 /**
  * Implements hook_node_access().
  */
-function node_node_access($node, $op, $account) {
-  $type = is_string($node) ? $node : $node->type;
+function node_node_access($op, $type, $uid, $nid, $node_uid) {
 
   if (in_array($type, node_permissions_get_configured_types())) {
-    if ($op == 'create' && user_access('create ' . $type . ' content', $account)) {
+    if ($op == 'create' && user_access('create ' . $type . ' content', $uid)) {
       return NODE_ACCESS_ALLOW;
     }
 
     if ($op == 'update') {
-      if (user_access('edit any ' . $type . ' content', $account) || (user_access('edit own ' . $type . ' content', $account) && ($account->uid == $node->uid))) {
+      if (user_access('edit any ' . $type . ' content', $uid) || (user_access('edit own ' . $type . ' content', $uid) && ($uid == $node_uid))) {
         return NODE_ACCESS_ALLOW;
       }
     }
 
     if ($op == 'delete') {
-      if (user_access('delete any ' . $type . ' content', $account) || (user_access('delete own ' . $type . ' content', $account) && ($account->uid == $node->uid))) {
+      if (user_access('delete any ' . $type . ' content', $uid) || (user_access('delete own ' . $type . ' content', $uid) && ($uid == $node_uid))) {
         return NODE_ACCESS_ALLOW;
       }
     }
@@ -2640,15 +2659,19 @@
  *   arrays of grants for those realms.
  */
 function node_access_grants($op, $account = NULL) {
+  global $user;
 
-  if (!isset($account)) {
-    $account = $GLOBALS['user'];
+  if (!isset($account) || (is_numeric($account) && $account == $user->uid)) {
+    $account = $user;
+  }
+  elseif (is_numeric($account)) {
+    $account = (object)array('uid' => $account);
   }
 
   // Fetch node access grants from other modules.
-  $grants = module_invoke_all('node_grants', $account, $op);
+  $grants = module_invoke_all('node_grants', $account->uid, $op);
   // Allow modules to alter the assigned grants.
-  drupal_alter('node_grants', $grants, $account, $op);
+  drupal_alter('node_grants', $grants, $account->uid, $op);
 
   return array_merge(array('all' => array(0)), $grants);
 }
@@ -2713,6 +2736,7 @@
       $or = db_or();
       // If any grant exists for the specified user, then user has access to the
       // node for the specified operation.
+      // TODO: where does the 'account' metadata get set?
       foreach (node_access_grants($op, $query->getMetaData('account')) as $realm => $gids) {
         foreach ($gids as $gid) {
           $or->condition(db_and()
Index: includes/menu.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/menu.inc,v
retrieving revision 1.369
diff -u -r1.369 menu.inc
--- includes/menu.inc	17 Dec 2009 13:10:18 -0000	1.369
+++ includes/menu.inc	23 Dec 2009 00:20:27 -0000
@@ -419,8 +419,6 @@
       }
       if ($router_item['access']) {
         $router_item['map'] = $map;
-        $router_item['page_arguments'] = array_merge(menu_unserialize($router_item['page_arguments'], $map), array_slice($map, $router_item['number_parts']));
-        $router_item['theme_arguments'] = array_merge(menu_unserialize($router_item['theme_arguments'], $map), array_slice($map, $router_item['number_parts']));
       }
     }
     $router_items[$path] = $router_item;
@@ -456,10 +454,18 @@
       // to make alterations just for this request.
       drupal_alter('menu_active_handler', $router_item, $path);
       if ($router_item['access']) {
-        if ($router_item['file']) {
-          require_once DRUPAL_ROOT . '/' . $router_item['file'];
+        if (!empty($router_item['load_functions']) && !_menu_load_objects($router_item, $router_item['map'])) {
+          // An error occurred loading an object.
+          $page_callback_result = MENU_ACCESS_DENIED;
+        }
+        else {
+          $router_item['page_arguments'] = array_merge(menu_unserialize($router_item['page_arguments'], $router_item['map']), array_slice($router_item['map'], $router_item['number_parts']));
+          menu_set_item($path, $router_item);
+          if ($router_item['file']) {
+            require_once DRUPAL_ROOT . '/' . $router_item['file'];
+          }
+          $page_callback_result = call_user_func_array($router_item['page_callback'], $router_item['page_arguments']);
         }
-        $page_callback_result = call_user_func_array($router_item['page_callback'], $router_item['page_arguments']);
       }
       else {
         $page_callback_result = MENU_ACCESS_DENIED;
@@ -698,11 +704,6 @@
   // The $path_map saves the pieces of the path as strings, while elements in
   // $map may be replaced with loaded objects.
   $path_map = $map;
-  if (!empty($router_item['load_functions']) && !_menu_load_objects($router_item, $map)) {
-    // An error occurred loading an object.
-    $router_item['access'] = FALSE;
-    return FALSE;
-  }
 
   // Generate the link path for the page request or local tasks.
   $link_map = explode('/', $router_item['path']);
@@ -715,6 +716,9 @@
   $router_item['options'] = array();
   _menu_check_access($router_item, $map);
 
+  // Translate theme arguments now, so menu_get_custom_theme() can work.
+  $router_item['theme_arguments'] = array_merge(menu_unserialize($router_item['theme_arguments'], $map), array_slice($map, $router_item['number_parts']));
+
   // For performance, don't localize an item the user can't access.
   if ($router_item['access']) {
     _menu_item_localize($router_item, $map);
@@ -789,14 +793,10 @@
     }
     // menu_tree_check_access() may set this ahead of time for links to nodes.
     if (!isset($item['access'])) {
-      if (!empty($item['load_functions']) && !_menu_load_objects($item, $map)) {
-        // An error occurred loading an object.
-        $item['access'] = FALSE;
-        return FALSE;
-      }
       _menu_check_access($item, $map);
     }
-    // For performance, don't localize a link the user can't access.
+
+    // For performance, don't localize an item the user can't access.
     if ($item['access']) {
       _menu_item_localize($item, $map, TRUE);
     }
@@ -1048,6 +1048,8 @@
   return $tree[$cid];
 }
 
+// TODO: menu_get_item() runs first, which normally loads objects.
+
 /**
  * Get the data structure representing a named menu tree, based on the current page.
  *
@@ -1680,6 +1682,7 @@
     $root_path = $router_item['path'];
 
     foreach ($result as $item) {
+      // TODO: why isn't _menu_link_translate() used here?
       _menu_translate($item, $map, TRUE);
       if ($item['tab_parent']) {
         // All tabs, but not the root page.
@@ -1898,6 +1901,7 @@
     // Extract the actual "task" string from the path argument.
     $key = drupal_substr($item['path'], $parent_length);
 
+    // TODO: why isn't _menu_link_translate() used here?
     // Denormalize and translate the contextual link.
     _menu_translate($item, $map, TRUE);
     if (!$item['access']) {
Index: modules/user/user.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/user/user.module,v
retrieving revision 1.1094
diff -u -r1.1094 user.module
--- modules/user/user.module	22 Dec 2009 14:47:14 -0000	1.1094
+++ modules/user/user.module	23 Dec 2009 00:20:27 -0000
@@ -721,9 +721,13 @@
 function user_access($string, $account = NULL) {
   global $user;
 
-  if (!isset($account)) {
+  if (!isset($account) || (is_numeric($account) && $account == $user->uid)) {
     $account = $user;
   }
+  elseif (is_numeric($account)) {
+    // Construct a skeleton $account if only a uid is given.
+    $account = (object)array('uid' => intval($account));
+  }
 
   // User #1 has all privileges:
   if ($account->uid == 1) {
@@ -737,6 +741,11 @@
   isset($drupal_static[__FUNCTION__]) || ($drupal_static[__FUNCTION__] = &drupal_static(__FUNCTION__));
   $perm = &$drupal_static[__FUNCTION__];
   if (!isset($perm[$account->uid])) {
+    // Load roles for this user.
+    if (empty($account->roles) && $account->uid) {
+      $account->roles[DRUPAL_AUTHENTICATED_RID] = 'authenticated user';
+      $account->roles += db_query("SELECT r.rid, r.name FROM {role} r INNER JOIN {users_roles} ur ON ur.rid = r.rid WHERE ur.uid = :uid", array(':uid' => $account->uid))->fetchAllKeyed(0, 1);
+    }
     $role_permissions = user_role_permissions($account->roles);
 
     $perms = array();
@@ -2849,10 +2858,9 @@
     // the authenticated role. If so, then all users would be listed, and we can
     // skip adding it to the filter query.
     if ($key == 'permission') {
-      $account = new stdClass();
-      $account->uid = 'user_filter';
-      $account->roles = array(DRUPAL_AUTHENTICATED_RID => 1);
-      if (user_access($value, $account)) {
+      $role_permissions = user_role_permissions(array(DRUPAL_AUTHENTICATED_RID => 1));
+
+      if (isset($role_permissions[DRUPAL_AUTHENTICATED_RID]) && isset($role_permissions[DRUPAL_AUTHENTICATED_RID][$value])) {
         continue;
       }
       $query->leftJoin('role_permission', 'p', 'ur.rid = p.rid');
