diff -urpN drupal-6.x-dev-200708231745/includes/bootstrap.inc drupal-6.x-dev-access-0.4.1/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.1/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.1/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.1/modules/user/user.module	2007-08-23 23:43:02.000000000 +0800
@@ -2005,8 +2005,8 @@ function user_admin_access_add($mask = N
       form_set_error('mask', t('You must enter a mask.'));
     }
     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');
+      db_query("INSERT INTO {access} (mask, type, status) VALUES ('%s', '%s', %d)", $edit['mask'], $edit['type'], $edit['status']);
+      cache_clear_all('accesses', 'cache');
       drupal_set_message(t('The access rule has been added.'));
       drupal_goto('admin/user/rules');
     }
@@ -2038,6 +2038,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 +2054,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 +2085,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);
diff -urpN drupal-6.x-dev-200708231745/sites/default/settings.php drupal-6.x-dev-access-0.4.1/sites/default/settings.php
--- drupal-6.x-dev-200708231745/sites/default/settings.php	1970-01-01 08:00:00.000000000 +0800
+++ drupal-6.x-dev-access-0.4.1/sites/default/settings.php	2007-08-23 23:43:38.000000000 +0800
@@ -0,0 +1,178 @@
+<?php
+// $Id: default.settings.php,v 1.2 2007/06/17 10:45:35 dries Exp $
+
+/**
+ * @file
+ * Drupal site-specific configuration file.
+ *
+ * IMPORTANT NOTE:
+ * This file may have been set to read-only by the Drupal installation
+ * program. If you make changes to this file, be sure to protect it again
+ * after making your modifications. Failure to remove write permissions
+ * to this file is a security risk.
+ *
+ * The configuration file to be loaded is based upon the rules below.
+ *
+ * The configuration directory will be discovered by stripping the
+ * website's hostname from left to right and pathname from right to
+ * left. The first configuration file found will be used and any
+ * others will be ignored. If no other configuration file is found
+ * then the default configuration file at 'sites/default' will be used.
+ *
+ * For example, for a fictitious site installed at
+ * http://www.drupal.org/mysite/test/, the 'settings.php'
+ * is searched in the following directories:
+ *
+ *  1. sites/www.drupal.org.mysite.test
+ *  2. sites/drupal.org.mysite.test
+ *  3. sites/org.mysite.test
+ *
+ *  4. sites/www.drupal.org.mysite
+ *  5. sites/drupal.org.mysite
+ *  6. sites/org.mysite
+ *
+ *  7. sites/www.drupal.org
+ *  8. sites/drupal.org
+ *  9. sites/org
+ *
+ * 10. sites/default
+ *
+ * If you are installing on a non-standard port number, prefix the
+ * hostname with that number. For example,
+ * http://www.drupal.org:8080/mysite/test/ could be loaded from
+ * sites/8080.www.drupal.org.mysite.test/.
+ */
+
+/**
+ * Database settings:
+ *
+ * Note that the $db_url variable gets parsed using PHP's built-in
+ * URL parser (i.e. using the "parse_url()" function) so make sure
+ * not to confuse the parser. If your username, password
+ * or database name contain characters used to delineate
+ * $db_url parts, you can escape them via URI hex encodings:
+ *
+ *   : = %3a   / = %2f   @ = %40
+ *   + = %2b   ( = %28   ) = %29
+ *   ? = %3f   = = %3d   & = %26
+ *
+ * To specify multiple connections to be used in your site (i.e. for
+ * complex custom modules) you can also specify an associative array
+ * of $db_url variables with the 'default' element used until otherwise
+ * requested.
+ *
+ * You can optionally set prefixes for some or all database table names
+ * by using the $db_prefix setting. If a prefix is specified, the table
+ * name will be prepended with its value. Be sure to use valid database
+ * characters only, usually alphanumeric and underscore. If no prefixes
+ * are desired, leave it as an empty string ''.
+ *
+ * To have all database names prefixed, set $db_prefix as a string:
+ *
+ *   $db_prefix = 'main_';
+ *
+ * To provide prefixes for specific tables, set $db_prefix as an array.
+ * The array's keys are the table names and the values are the prefixes.
+ * The 'default' element holds the prefix for any tables not specified
+ * elsewhere in the array. Example:
+ *
+ *   $db_prefix = array(
+ *     'default'   => 'main_',
+ *     'users'     => 'shared_',
+ *     'sessions'  => 'shared_',
+ *     'role'      => 'shared_',
+ *     'authmap'   => 'shared_',
+ *     'sequences' => 'shared_',
+ *   );
+ *
+ * Database URL format:
+ *   $db_url = 'mysql://username:password@localhost/databasename';
+ *   $db_url = 'mysqli://username:password@localhost/databasename';
+ *   $db_url = 'pgsql://username:password@localhost/databasename';
+ */
+$db_url = 'mysqli://DRUPAL1:passwd@localhost/AL32UTF8';
+$db_prefix = '';
+
+/**
+ * Base URL (optional).
+ *
+ * If you are experiencing issues with different site domains,
+ * uncomment the Base URL statement below (remove the leading hash sign)
+ * and fill in the URL to your Drupal installation.
+ *
+ * You might also want to force users to use a given domain.
+ * See the .htaccess file for more information.
+ *
+ * Examples:
+ *   $base_url = 'http://www.example.com';
+ *   $base_url = 'http://www.example.com:8888';
+ *   $base_url = 'http://www.example.com/drupal';
+ *   $base_url = 'https://www.example.com:8888/drupal';
+ *
+ * It is not allowed to have a trailing slash; Drupal will add it
+ * for you.
+ */
+# $base_url = 'http://www.example.com';  // NO trailing slash!
+
+/**
+ * PHP settings:
+ *
+ * To see what PHP settings are possible, including whether they can
+ * be set at runtime (ie., when ini_set() occurs), read the PHP
+ * documentation at http://www.php.net/manual/en/ini.php#ini.list
+ * and take a look at the .htaccess file to see which non-runtime
+ * settings are used there. Settings defined here should not be
+ * duplicated there so as to avoid conflict issues.
+ */
+ini_set('arg_separator.output',     '&amp;');
+ini_set('magic_quotes_runtime',     0);
+ini_set('magic_quotes_sybase',      0);
+ini_set('session.cache_expire',     200000);
+ini_set('session.cache_limiter',    'none');
+ini_set('session.cookie_lifetime',  2000000);
+ini_set('session.gc_maxlifetime',   200000);
+ini_set('session.save_handler',     'user');
+ini_set('session.use_only_cookies', 1);
+ini_set('session.use_trans_sid',    0);
+ini_set('url_rewriter.tags',        '');
+
+/**
+ * Drupal automatically generates a unique session cookie name for each site
+ * based on on its full domain name. If you have multiple domains pointing at
+ * the same Drupal site, you can either redirect them all to a single domain
+ * (see comment in .htaccess), or uncomment the line below and specify their
+ * shared base domain. Doing so assures that users remain logged in as they
+ * cross between your various domains.
+ */
+# $cookie_domain = 'example.com';
+
+/**
+ * Variable overrides:
+ *
+ * To override specific entries in the 'variable' table for this site,
+ * set them here. You usually don't need to use this feature. This is
+ * useful in a configuration file for a vhost or directory, rather than
+ * the default settings.php. Any configuration setting from the 'variable'
+ * table can be given a new value.
+ *
+ * Remove the leading hash signs to enable.
+ */
+# $conf = array(
+#   'site_name' => 'My Drupal site',
+#   'theme_default' => 'minnelli',
+#   'anonymous' => 'Visitor',
+# );
+
+/**
+ * String overrides:
+ *
+ * To override specific strings on your site with or without enabling locale
+ * module, add an entry to this list. This functionality allows you to change
+ * a small number of your site's default English language interface strings.
+ *
+ * Remove the leading hash signs to enable.
+ */
+# $conf['locale_custom_strings_en'] = array(
+#   'forum'      => 'Discussion board',
+#   '@count min' => '@count minutes',
+# );
