diff -urpN drupal-6.x-dev-200708231745/includes/bootstrap.inc drupal-6.x-dev-access-0.4/includes/bootstrap.inc
--- drupal-6.x-dev-200708231745/includes/bootstrap.inc	2007-08-07 16:41:24.000000000 +0800
+++ drupal-6.x-dev-access-0.4/includes/bootstrap.inc	2007-08-23 18:14:31.000000000 +0800
@@ -792,11 +792,60 @@ function drupal_get_messages($type = NUL
 }
 
 /**
+ * Initialize the access strategy.
+ */
+function _drupal_access_init() {
+  // NOTE: caching the access rules improves performance by 5% when serving cached pages.
+  $accesses = array();
+  if ($cached = cache_get('accesses', 'cache')) {
+    $accesses = $cached->data;
+  }
+  else {
+    $result = db_query('SELECT * FROM {access}');
+
+    // Classify, group and preprocess fetched access rules.
+    $array = array();
+    while ($rule = db_fetch_object($result)) {
+      $type = $rule->type;
+      $status = $rule->status ? 'allow' : 'deny';
+      $mask = $rule->mask;
+
+      // Mask is not starting with '^': in plain text format. Escape it
+      // with preg_quote().
+      if (substr($mask, 0, 1) != '^') {
+        $plain[$type][$status][] = '^' . preg_quote($mask) . '$';
+      }
+      // Mask is starting with '^': in regex expression. Use directly without
+      // additional processing.
+      else {
+        $regex[$type][$status][] = $mask;
+      }
+
+      // Record which type of rules are existing.
+      $record[$type][$status] = TRUE;
+    }
+
+    // Build regex expression for caching.
+    foreach ($record as $type => $tmp) {
+      foreach ($tmp as $status => $mask) {
+        // NOTE: non-regexp matches are always done first.
+        $rules = array_merge((array) $plain[$type][$status], (array) $regex[$type][$status]);
+        $accesses[$type][$status] = '/' . implode('|', $rules) . '/Ds';
+      }
+    }
+
+    cache_set('accesses', $accesses);
+  }
+
+  return $accesses;
+}
+
+/**
  * Perform an access check for a given mask and rule type. Rules are usually
  * created via admin/user/rules page.
  *
- * If any allow rule matches, access is allowed. Otherwise, if any deny rule
- * matches, access is denied.  If no rule matches, access is allowed.
+ * If any deny rule matches, access is denied. By the way, if any allow rule
+ * matches, access is allowed. If no rule matches, access is allowed.
  *
  * @param $type string
  *   Type of access to check: Allowed values are:
@@ -804,25 +853,33 @@ function drupal_get_messages($type = NUL
  *     - 'mail': e-mail address
  *     - 'user': username
  * @param $mask string
- *   String or mask to test: '_' matches any character, '%' matches any
- *   number of characters.
+ *   String to test.
  * @return bool
  *   TRUE if access is denied, FALSE if access is allowed.
  */
 function drupal_is_denied($type, $mask) {
-  // Because this function is called for every page request, both cached
-  // and non-cached pages, we tried to optimize it as much as possible.
-  // We deny access if the only matching records in the {access} table have
-  // status 0. If any have status 1, or if there are no matching records,
-  // we allow access. So, select matching records in decreasing order of
-  // 'status', returning NOT(status) for the first. If any have status 1,
-  // they come first, and we return NOT(status) = 0 (allowed). Otherwise,
-  // if we have some with status 0, we return 1 (denied). If no matching
-  // records, we get no return from db_result, so we return (bool)NULL = 0
-  // (allowed).
-  // The use of ORDER BY / LIMIT is more efficient than "MAX(status) = 0"
-  // in PostgreSQL <= 8.0.
-  return (bool) db_result(db_query_range("SELECT CASE WHEN status=1 THEN 0 ELSE 1 END FROM {access} WHERE type = '%s' AND LOWER(mask) LIKE LOWER('%s') ORDER BY status DESC", $type, $mask, 0, 1));
+  global $access;
+
+  // First of all, assume access is allowed.
+  $denied = FALSE;
+
+  // Check if deny rules exists.
+  if (isset($access[$type]['deny']) && $access[$type]['deny']) {
+    // If any deny rule matches, access is denied.
+    if (preg_match($access[$type]['deny'], $mask)) {
+      $denied = TRUE;
+    }
+  }
+
+  // Check if allow rules exists.
+  if (isset($access[$type]['allow']) && $access[$type]['allow']) {
+    // If any allow rule matches, access is allowed.
+    if (preg_match($access[$type]['allow'], $mask)) {
+      $denied = FALSE;
+    }
+  }
+
+  return $denied;
 }
 
 /**
@@ -878,7 +935,7 @@ function drupal_bootstrap($phase) {
 }
 
 function _drupal_bootstrap($phase) {
-  global $conf;
+  global $conf, $access;
 
   switch ($phase) {
 
@@ -899,6 +956,9 @@ function _drupal_bootstrap($phase) {
       break;
 
     case DRUPAL_BOOTSTRAP_ACCESS:
+      // Initialize the access strategy.
+      $access = _drupal_access_init();
+
       // Deny access to hosts which were banned - t() is not yet available.
       if (drupal_is_denied('host', ip_address())) {
         header('HTTP/1.1 403 Forbidden');
diff -urpN drupal-6.x-dev-200708231745/modules/user/user.module drupal-6.x-dev-access-0.4/modules/user/user.module
--- drupal-6.x-dev-200708231745/modules/user/user.module	2007-08-19 16:08:45.000000000 +0800
+++ drupal-6.x-dev-access-0.4/modules/user/user.module	2007-08-23 18:31:05.000000000 +0800
@@ -2007,6 +2007,7 @@ function user_admin_access_add($mask = N
     else {
       db_query("INSERT INTO {access} (aid, mask, type, status) VALUES ('%s', '%s', '%s', %d)", $aid, $edit['mask'], $edit['type'], $edit['status']);
       $aid = db_last_insert_id('access', 'aid');
+      cache_clear_all('accesses', 'cache');
       drupal_set_message(t('The access rule has been added.'));
       drupal_goto('admin/user/rules');
     }
@@ -2038,6 +2039,7 @@ function user_admin_access_delete_confir
 
 function user_admin_access_delete_confirm_submit($form, &$form_state) {
   db_query('DELETE FROM {access} WHERE aid = %d', $form_state['values']['aid']);
+  cache_clear_all('accesses', 'cache');
   drupal_set_message(t('The access rule has been deleted.'));
   $form_state['redirect'] = 'admin/user/rules';
   return;
@@ -2053,6 +2055,7 @@ function user_admin_access_edit($aid = 0
     }
     else {
       db_query("UPDATE {access} SET mask = '%s', type = '%s', status = '%s' WHERE aid = %d", $edit['mask'], $edit['type'], $edit['status'], $aid);
+      cache_clear_all('accesses', 'cache');
       drupal_set_message(t('The access rule has been saved.'));
       drupal_goto('admin/user/rules');
     }
@@ -2083,7 +2086,7 @@ function user_admin_access_form(&$form_s
     '#size' => 30,
     '#maxlength' => 64,
     '#default_value' => $edit['mask'],
-    '#description' => '%: '. t('Matches any number of characters, even zero characters') .'.<br />_: '. t('Matches exactly one character.'),
+    '#description' => t('Start the line with a ^ character to designate a regular expression match.') . '<br />' . t('NOTE: non-regexp matches are always done first.'),
     '#required' => TRUE,
   );
   $form['submit'] = array('#type' => 'submit', '#value' => $submit);
