diff --git a/core/lib/Drupal/Component/PhpLoader/NativeLoader.php b/core/lib/Drupal/Component/PhpLoader/NativeLoader.php new file mode 100644 index 0000000..7355a2d --- /dev/null +++ b/core/lib/Drupal/Component/PhpLoader/NativeLoader.php @@ -0,0 +1,19 @@ +prefix = $config['prefix']; + } + function read($filename) { + include_once $this->prefix . '/' . $filename; + } + function write($filename, $data) { + return file_put_contents($this->prefix . '/' . $filename, $data); + } + function delete($filename) { + unlink($filename); + } +} diff --git a/core/lib/Drupal/Component/PhpLoader/PhpLoaderInterface.php b/core/lib/Drupal/Component/PhpLoader/PhpLoaderInterface.php new file mode 100644 index 0000000..a2acf96 --- /dev/null +++ b/core/lib/Drupal/Component/PhpLoader/PhpLoaderInterface.php @@ -0,0 +1,11 @@ +prefix = $config['prefix']; + $this->salt = $config['salt']; + $this->hmac = $config['hmac']; + } + + function read($filename) { + $filename = str_replace('/', '#', $filename); + $dir = $this->prefix . '/' . $filename; + if (file_exists($dir)) { + $dir_mtime = filemtime($dir); + $filename = $dir . '/' . call_user_func($this->hmac, $filename, $this->salt . $dir_mtime); + // First, we know that if any file has been created or deleted in the + // directory then the directory mtime changes and so it invalidates the + // hash. Therefore, if the filename exists then the directory mtime is + // still the same as it was in drupal_php_write(). As + // _drupal_php_write_sleep() sleeps until the current time is larger than + // that, if another process would write the file then it would make the + // file mtime strictly larger than the directory mtime. + if (file_exists($filename) && filemtime($filename) <= $dir_mtime) { + include_once $filename; + } + } + } + + function write($filename, $data) { + $filename = str_replace('/', '#', $filename); + $original_path = "$this->prefix/.$filename"; + if (!@file_put_contents($original_path, $data)) { + return FALSE; + } + chmod($original_path, 0400); + $full_dir = $this->prefix . '/' . $filename; + if (file_exists($full_dir)) { + // Garbage collection. + foreach (new DirectoryIterator($full_dir) as $entry) { + if ($entry->isFile()) { + unlink($entry->isFile()); + } + } + touch($full_dir); + } + else { + mkdir($full_dir); + } + $this->mtime = 0; + $loop = 0; + // Now move the file to its final place. The mtime of a directory is the + // time of the last file create or delete in the directory. So the moving + // will update the directory mtime. This update will very likely not show up + // in filemtime, however, because it has a coarse, one second granularity + // and typical moves takes significantly less than that. In the unlucky case + // it does, we need to redo the rename to a new filename. So renaming needs + // to happen in a loop. Also note that clearstatcache() returns NULL so it + // does not affect the loop condition. + while (clearstatcache() || $this->mtime != filemtime($full_dir)) { + // Reset the file back in the original place if this is not the first + // iteration. + if ($loop) { + rename($full_path, $original_path); + } + if ($loop > 10) { + // Hopelessly slow filesystem? + unlink($original_path); + return FALSE; + } + $full_path = $full_dir . '/' . call_user_func($this->hmac, $filename, $this->salt . $dir_mtime); + rename($original_path, $full_path); + $loop++; + } + } + + function delete($filename) { + $filename = str_replace('/', '#', $filename); + $dir = $this->prefix . '/' . $filename; + $iterator = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS), + RecursiveIteratorIterator::CHILD_FIRST + ); + foreach ($iterator as $file) { + if ($file->isDir()) { + rmdir($file->getPathname()); + } + else { + unlink($file->getPathname()); + } + } + rmdir($dir); + } + + function __destruct() { + $time = $this->mtime + 1; + // time_sleep_until() throws a warning if the time given is in the past. + if (time() < $time) { + time_sleep_until($time); + } + } +}