diff -urp --strip-trailing-cr ../cacherouter/cacherouter.inc ./cacherouter.inc
--- ../cacherouter/cacherouter.inc	2009-09-05 15:03:25.000000000 +0200
+++ ./cacherouter.inc	2009-09-17 00:26:50.000000000 +0200
@@ -135,16 +135,16 @@ function cache_clear_all($key = NULL, $t
       // cached data that was cached before the timestamp.
       $user->cache = time();
 
-      $cache_flush = variable_get('cache_flush', 0);
+      $cache_flush = variable_get('cache_flush_'. $table, 0);
       if ($cache_flush == 0) {
         // This is the first request to clear the cache, start a timer.
-        variable_set('cache_flush', time());
+        variable_set('cache_flush_'. $table, time());
       }
       else if (time() > ($cache_flush + variable_get('cache_lifetime', 0))) {
         // Clear the cache for everyone, cache_flush_delay seconds have
         // passed since the first request to clear the cache.
         $cache->flush($table);
-        variable_set('cache_flush', 0);
+        variable_set('cache_flush_'. $table, 0);
       }
     }
     else {
@@ -185,7 +185,7 @@ if (!function_exists('page_cache_fastpat
         if (!empty($page)) {
           drupal_page_header();
         
-           //checking if first chars are compressed (always the same pattern for every header)
+          //checking if first chars are compressed (always the same pattern for every header)
           if (substr($page->data, 0,3) == "\x1f\x8b\x08") {
           
             // Determine if the browser accepts gzipped data.
@@ -207,4 +207,4 @@ if (!function_exists('page_cache_fastpat
     }
     return FALSE;
   }
-}
\ Chybí znak konce řádku na konci souboru
+}
diff -urp --strip-trailing-cr ../cacherouter/engines/file.php ./engines/file.php
--- ../cacherouter/engines/file.php	2009-09-05 15:03:25.000000000 +0200
+++ ./engines/file.php	2009-09-17 01:09:47.000000000 +0200
@@ -8,11 +8,11 @@
 class fileCache extends Cache {
   var $content = array();
   var $fspath = '/tmp/filecache';
-  
+
   function page_fast_cache() {
     return TRUE;
   }
-  
+
   function __construct($bin, $options, $default_options) {
     // Assign the path on the following order: bin specific -> default specific -> /tmp/filepath
     if (isset($options['path'])) {
@@ -26,24 +26,18 @@ class fileCache extends Cache {
     }
     parent::__construct($bin, $options, $default_options);
   }
-  
+
   function get($key) {
     global $user, $conf;
-    
-    if (isset($this->content[$key])) {
-      return $this->content[$key];
-    }
-    
-    $cache_lifetime = variable_get('cache_lifetime', 0);
 
     //make sure fast cache is enabled (see CacheRouter function page_fast_cache)
     if ($this->page_fast_cache()) {
       $cache = NULL;
-      $cache_file = $this->key($key);
-      if (file_exists($cache_file)) {    
-        if ($fp = fopen($cache_file, 'r')) {
+      $cache_file = glob($this->key($key) .'.*', GLOB_NOSORT);
+      if (isset($cache_file[0])) {    
+        if ($fp = @fopen($cache_file[0], 'r')) {
           if (flock($fp, LOCK_SH)) {
-            $data = @fread($fp, filesize($cache_file));
+            $data = @fread($fp, filesize($cache_file[0]));
             flock($fp, LOCK_UN);
             $cache = unserialize($data);
           }
@@ -51,31 +45,9 @@ class fileCache extends Cache {
         }
       }
       return $cache;
-
     }
-    else {
-      // garbage collection necessary when enforcing a minimum cache lifetime
-      $cache_flush = variable_get('cache_flush', 0);
-      if ($cache_flush && ($cache_flush + $cache_lifetime <= time())) {
-        variable_set('cache_flush', 0);
-      }
-    }
-
-    if (isset($cache->data)) {
-      // If enforcing a minimum cache lifetime, validate that the data is
-      // currently valid for this user before we return it by making sure the
-      // cache entry was created before the timestamp in the current session's
-      // cache timer. The cache variable is loaded into the $user object by
-      // sess_read() in session.inc.
-      if ($user->cache > $cache->created) {
-        // This cache data is too old and thus not valid for us, ignore it.
-        return FALSE;
-      }
-      return $cache;
-    }
-    return FALSE;
   }
-  
+
   function set($key, $value, $expire = CACHE_PERMANENT, $headers = NULL) {
     static $subdirectories;
     //make sure fast cache is enabled (see CacheRouter function page_fast_cache)
@@ -88,20 +60,49 @@ class fileCache extends Cache {
       $cache->expire = $expire;
       $cache->headers = $headers;
       $cache->data = $value;
-      
+
       $data = serialize($cache);
-      
+
+      // Filename: cache_key-hash.expiration
+      if ($expire == CACHE_PERMANENT) {
+        $extension = '.perm';
+      }
+      else {
+        $extension = '.0'. ($expire == CACHE_TEMPORARY ? '' : $expire);
+      }
       $file = $this->key($key);
-      if ($fp = @fopen($file, 'w')) {
-        // only write to the cache file if we can obtain an exclusive lock
-        if (flock($fp, LOCK_EX)) {
-          fwrite($fp, $data);
-          flock($fp, LOCK_UN);
+
+      // Grab a lock. Since we're going to (potentially) rename files, we need
+      // an additional per-directory lock for writes, to avoid insertion of
+      // duplicate entries with different expiration timestamps in concurrent
+      // requests. This extra lock is kept on a dummy file, which is outside
+      // the actual directory to simplify mass deletion of data files.
+      $success = FALSE;
+      if ($lockfile = @fopen(dirname($file) .'.lock', 'w')) {
+        if (flock($lockfile, LOCK_EX)) {
+          // Remove any old entries
+          $this->_delete($file .'.*');
+
+          // Write fresh entry
+          $file .= $extension;
+          if ($fp = @fopen($file, 'w')) {
+            // only write to the cache file if we can obtain an exclusive lock.
+            // This lock defends against concurrent reading of this one file.
+            if (flock($fp, LOCK_EX)) {
+              fwrite($fp, $data);
+              flock($fp, LOCK_UN);
+            }
+            fclose($fp);
+            $success = TRUE;
+          }
+
+          flock($lockfile, LOCK_UN);
+          @chmod(0664, $file); // Necessary for non-webserver users.
         }
-        fclose($fp);
-        @chmod(0664, $file); // Necessary for non-webserver users.
+        fclose($lockfile);
       }
-      else {
+
+      if (!$success) {
         // t() may not be loaded
         if (function_exists('watchdog')) {
           watchdog('cache', strtr('Cache write error, failed to open file "%file"', array('%file' => $file)), WATCHDOG_ERROR);
@@ -114,94 +115,76 @@ class fileCache extends Cache {
       }
     }
   }
-  
+
   function delete($key) {
     // when using wildcard: $key is part-of-key + '*'
-    
+
     $filename = $this->key($key);
     if (is_dir($filename)) {
-      $fspath = $filename;
-      // Filename: abcdef12345verylongmd5code--content:123456:987654
-      $files = file_scan_directory($fspath, ".--.", array('.', '..', 'CVS'));
-      foreach ($files as $file) {
-        if(is_file($file->filename)){
-          if ($fp = fopen($file->filename, 'w')) {
-            // only delete the cache file once we obtain an exclusive lock to prevent
-            // deleting a cache file that is currently being read.
-            if (flock($fp, LOCK_EX)) {
-              unlink($file->filename);
-            }
-          }
-        }
-      }
+      // '*' => Delete all
+      $this->_delete($filename .'*/*.*');
     } 
     else if (strrpos($key, '*') !== FALSE) {
+      // 'part-of-key*' => Delete all matching entries
       $look_for = explode('*', $key);
-      $fspath = $this->fspath;
-      // Filename: abcdef12345verylongmd5code--content:123456:987654
-      $files = file_scan_directory($fspath, ".--{$look_for[0]}.*", array('.', '..', 'CVS'));
-      foreach ($files as $file) {
-        if (is_file($file->filename)){
-          if ($fp = @fopen($file->filename, 'w')) {
-            // only delete the cache file once we obtain an exclusive lock to prevent
-            // deleting a cache file that is currently being read.
-            if (flock($fp, LOCK_EX)) {
-              unlink($file->filename);
-            }
-          }
-        }
-      }
+      $this->_delete($this->key('*') .'*/'. $look_for[0] .'*.*');
     } 
     else {
-      if ($fp = @fopen($filename, 'w')) {
-        // only delete the cache file once we obtain an exclusive lock to prevent
-        // deleting a cache file that is currently being read.
-        if (flock($fp, LOCK_EX)) {
-          unlink($filename);
+      // 'full-key' => Delete single entry
+      $this->_delete($filename .'.*');
+    }
+  }
+
+  // Helper function to delete a set of files
+  function _delete($file_pattern) {
+    if ($files = glob($file_pattern, GLOB_NOSORT)) {
+      foreach ($files as $file) {
+        if ($fp = @fopen($file, 'w')) {
+          // only delete the cache file once we obtain an exclusive lock to prevent
+          // deleting a cache file that is currently being read.
+          if (flock($fp, LOCK_EX)) {
+            unlink($file);
+          }
         }
       }
     }
   }
 
-  
   function flush() {
-    global $user;
-    
-    $table = $this->name;
-    $cache_lifetime = variable_get('cache_lifetime', 0);
-    $fspath = $this->fspath;
-    
-    $ivalfrom = ord("a");
-    $ivalto = ord("f");
-    
-    for ($i = $ivalfrom; $i <= $ivalto; $i++) {
-      $this->purge("$fspath/$table/". chr($i));
-    }
-
-    for ($i = 0; $i<10; $i++) {
-      $this->purge("$fspath/$table/". $i);
-    }
+    $this->purge($this->key('*'));
   }
-  
+
   function key($key) {
     $table = $this->name;
     $fspath = $this->fspath;
     if ($key != '*') {
-      // Make sure we have a good filename when we concatentate $hash with $appendix:
+      // Make sure we have a good filename, by custom-escaping the cache key.
+      // Add md5 hash to ensure uniqueness on case-insensitive filesystems, and
+      // trim to maximum length, keeping space for 9 characters of an extension.
       // * Can't be over 255 bytes (ext2, 3, 4) or 255 characters (NTFS, FAT) as per 
       //  http://en.wikipedia.org/wiki/Comparison_of_file_systems#Limits
       // * Can't include "? * / \ : ; < >" in NTFS and FAT as per 
       //  http://technet.microsoft.com/en-us/library/cc722482.aspx
+      // * Can't inlude dots, due to our handling of filename extensions.
       $hash = md5($key);
-      $appendix = str_replace(array('?','*','/','\\',':',';','<','>'), '-', $key);
-      $filename = $hash . '--' . $appendix;
-      
+      $filename = strtr($key, array('!' => '!!', '.' => '!,',
+        '\x00' => '!0', '\x01' => '!1', '\x02' => '!2', '\x03' => '!3', '\x04' => '!4',
+        '\x05' => '!5', '\x06' => '!6', '\x07' => '!7', '\x08' => '!8', '\x09' => '!9',
+        '\x0A' => '!A', '\x0B' => '!B', '\x0C' => '!C', '\x0D' => '!D', '\x0E' => '!E',
+        '\x0F' => '!F', '\x10' => '!G', '\x11' => '!H', '\x12' => '!I', '\x13' => '!J',
+        '\x14' => '!K', '\x15' => '!L', '\x16' => '!M', '\x17' => '!N', '\x18' => '!O',
+        '\x19' => '!P', '\x1A' => '!Q', '\x1B' => '!R', '\x1C' => '!S', '\x1D' => '!T',
+        '\x1E' => '!U', '\x1F' => '!V',
+        '?' => '!W', '*' => '!X', '<' => '!Y', '>' => '!Z', ' ' => '!_', '/' => '!=',
+        '\\' => '!-', ':' => '!+', ';' => '!#'));
+      $filename .= '-'. $hash;
+
       if (function_exists('mb_substr')) {
-        $filename = mb_substr($filename, 0, 255, '8bit');
+        $filename = mb_substr($filename, 0, 246, '8bit');
       }
       else {
         // We'll have to assume we're working with ASCII if mb_ extension isn't installed.
-        $filename = substr($filename, 0, 255);
+        $filename = substr($filename, 0, 246);
       }
 
       $this->create_directory($fspath, $hash{0});
@@ -212,7 +195,7 @@ class fileCache extends Cache {
     }
 
   }
-  
+
   /**
    * Create the necessary $table directory and/or letter/number subdirectory if
    * it doesn't exist.  We store the directories we've created in a static 
@@ -221,7 +204,7 @@ class fileCache extends Cache {
   function create_directory($fspath, $hash) {
     static $dirs = array();
     $table = $this->name;
-    
+
     $create = array($fspath, "$fspath/$table", "$fspath/$table/$hash");
 
     foreach ($create as $dir) {
@@ -245,36 +228,24 @@ class fileCache extends Cache {
   }
 
   function purge($dir) {
-    $cache_lifetime = variable_get('cache_lifetime', 0);
-    $files = file_scan_directory($dir, '.', array('.', '..', 'CVS'));
-    foreach ($files as $file) {
-      if ((filemtime($file->filename) < (time() - $cache_lifetime)) && $cache_lifetime > 0) {
-        if ($fp = fopen($file->filename, 'r')) {
-          // We need an exclusive lock, but don't block if we can't get it as
-          // we can simply try again next time cron is run.
-          if (flock($fp, LOCK_EX|LOCK_NB)) {
-            unlink($file->filename);
-          }
-        }
-      }
-      else {
-        if (file_exists($file->filename)) {    
-          if ($fp = @fopen($file->filename, 'r')) {
-            if (flock($fp, LOCK_SH)) {
-              $data = @fread($fp, filesize($file->filename));
-              flock($fp, LOCK_UN);
-              $cache = unserialize($data);
-            }
-            fclose($fp);
-            if ($cache->expire != CACHE_PERMANENT && $cache->expire <= time()) {
-              unlink($file->filename);
+    // Get list of all files for this table, except permanent entries.
+    if ($files = glob($dir .'*/*.0*', GLOB_NOSORT)) {
+      foreach ($files as $file) {
+        // We have expiration timestamp in filename extension (0 for CACHE_TEMPORARY)
+        $expire = substr($file, strrpos($file, '.') + 1);
+        if ($expire <= time()) {
+          if ($fp = fopen($file, 'r')) {
+            // We need an exclusive lock, but don't block if we can't get it as
+            // we can simply try again next time cron is run.
+            if (flock($fp, LOCK_EX|LOCK_NB)) {
+              unlink($file);
             }
           }
         }
       }
     }
   }
-  
+
   function stats() {
     $stats = array(
       'uptime' => time(),
