diff --git file_example/file_example.info file_example/file_example.info
new file mode 100644
index 0000000..3bec1b8
--- /dev/null
+++ file_example/file_example.info
@@ -0,0 +1,6 @@
+; $Id$
+name = File example
+description = Examples of using the Drupal File API and Stream Wrappers.
+package = Example modules
+core = 7.x
+files[] = form_example.module
diff --git file_example/file_example.module file_example/file_example.module
new file mode 100644
index 0000000..2e69d17
--- /dev/null
+++ file_example/file_example.module
@@ -0,0 +1,948 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Examples demonstrating the Drupal File API (and Stream Wrappers).
+ *
+ */
+
+/**
+ * The File Example module is a part of the Examples for Developers Project
+ * and provides various Drupal File API Examples. You can download and
+ * experiment with this code at the
+ * @link http://drupal.org/project/examples Examples for Developers project page. @endlink
+ *
+ * See @link http://drupal.org/node/555118 Drupal File API @endlink for handbook
+ * documentation on the File API and
+ * @link file File summary on api.drupal.org @endlink for the function summary.
+ *
+ * @defgroup file_example Examples: File Examples
+ */
+
+/**
+ * Implements hook_menu() to set up the URLs (menu entries) for the
+ * file examples.
+ */
+function file_example_menu() {
+  $items = array();
+  $items['examples/file_example'] = array(
+    'title' => 'File Example',
+    'page callback' => 'file_example_intro',
+    'access callback' => TRUE,
+    'expanded' => TRUE,
+  );
+  $items['examples/file_example/fileapi'] = array(
+    'title' => 'Use File API to read/write a file',
+    'page callback' => 'drupal_get_form',
+    'access arguments' => array('use file example'),
+    'page arguments' => array('file_example_readwrite'),
+  );
+  $items['examples/file_example/access_session'] = array(
+    'page callback' => 'file_example_session_contents',
+    'access arguments' => array('use file example'),
+    'type' => MENU_CALLBACK,
+  );
+  return $items;
+}
+
+
+/**
+ * Implements hook_permission().
+ */
+function file_example_permission() {
+  return array(
+    'use file example' =>  array(
+      'title' => t('Use the examples in the File Example module'),
+    ),
+  );
+}
+
+
+/**
+ * Form builder function for the file example readwrite and directory creation
+ * example.
+ *
+ * A simple form that allows creation of a file, managed or unmanaged. It
+ * also allows creation of a directory.
+ * @ingroup file_example
+ */
+function file_example_readwrite($form, &$form_state) {
+  $form['write_file'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Write to a file'),
+  );
+  $form['write_file']['write_contents'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Enter something you would like to write to a file'),
+    '#default_value' => t('Some text here to put into the file (or leave this here)'),
+  );
+
+  $form['write_file']['destination'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Optional: Enter the streamwrapper saying where it should be written'),
+    '#description' => t('This may be public://some_dir/test_file.txt or private://another_dir/some_file.txt, for example. If you include a directory, it must already exist. The default is "public://". Since this example supports session://, you can also use something like session://somefile.txt.'),
+  );
+
+  $form['write_file']['managed_submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Write managed file'),
+    '#submit' => array('file_example_managed_write_submit'),
+  );
+  $form['write_file']['unmanaged_submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Write unmanaged file'),
+    '#submit' => array('file_example_unmanaged_write_submit'),
+  );
+  $form['write_file']['unmanaged_php'] = array(
+    '#type' => 'submit',
+    '#value' => t('Unmanaged using PHP'),
+    '#submit' => array('file_example_unmanaged_php_submit'),
+  );
+
+  $form['read_file'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Read from a file'),
+  );
+  $form['read_file']['read_location'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Enter the location of a file you want to read'),
+    '#description' => t('This can be a stream-type description like public://some_file.txt or http://drupal.org or private://another_file.txt or (for this example) session://yet_another_file.txt.'),
+  );
+  $form['read_file']['read_submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Read the file and store it locally'),
+    '#submit' => array('file_example_read_submit'),
+  );
+
+  $form['directory'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Create or prepare a directory'),
+  );
+
+  $form['directory']['create_directory'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Directory to create/prepare'),
+    '#description' => t('This is a directory as in public://some/directory or private://another/dir.'),
+  );
+  $form['directory']['directory_submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Create directory'),
+    '#submit' => array('file_example_create_directory_submit'),
+  );
+  return $form;
+}
+
+/**
+ * Submit handler to write a managed file.
+ *
+ * The key functions used here are:
+ * - file_save_data(), which takes a buffer and saves it to a named file and
+ *   also creates a tracking record in the database and returns a file object.
+ *   In this function we use FILE_EXISTS_RENAME (the default) as the argument,
+ *   which means that if there's an existing file, create a new non-colliding
+ *   filename and use it.
+ * - file_create_url(), which converts a URI in the form public://junk.txt or
+ *   private://something/test.txt into a URL like
+ *   http://example.com/sites/default/files/junk.txt.
+ * @ingroup file_example
+ */
+function file_example_managed_write_submit($form, &$form_state) {
+  $data = $form_state['values']['write_contents'];
+  $destination = !empty($form_state['values']['destination']) ? $form_state['values']['destination'] : NULL;
+
+  // Managed operations work with a file object.
+  $file = file_save_data($data, $destination, FILE_EXISTS_RENAME);
+  if (!empty($file)) {
+    $url = file_create_url($file->uri);
+    drupal_set_message(t('Saved managed file: %file to destination %destination (accessible as !url)', array('%file' => print_r($file, TRUE), '%destination' => $destination, '!url' => l($url, $url))));
+  }
+  else {
+    drupal_set_message(t('Failed to save the managed file'), 'error');
+  }
+}
+
+/**
+ * Submit handler to write an unmanaged file.
+ *
+ * The key functions used here are:
+ * - file_unmanaged_save_data(), which takes a buffer and saves it to a named
+ *   file, but does not create any kind of tracking record in the database.
+ *   This example uses FILE_EXISTS_REPLACE for the third argument, meaning
+ *   that if there's an existing file at this location, it should be replaced.
+ * - file_create_url(), which converts a URI in the form public://junk.txt or
+ *   private://something/test.txt into a URL like
+ *   http://example.com/sites/default/files/junk.txt.
+ * @ingroup file_example
+ */
+
+function file_example_unmanaged_write_submit($form, &$form_state) {
+  $data = $form_state['values']['write_contents'];
+  $destination = !empty($form_state['values']['destination']) ? $form_state['values']['destination'] : NULL;
+
+  // With the unmanaged file we just get a filename back.
+  $filename = file_unmanaged_save_data($data, $destination, FILE_EXISTS_REPLACE);
+  if ($filename) {
+    $url = file_create_url($filename);
+    drupal_set_message(t('Saved file as %filename (accessible as !url)', array('%filename' => $filename, '!url' => l($url, $url))));
+  }
+  else {
+    drupal_set_message(t('Failed to save the file'), 'error');
+  }
+}
+
+
+
+/**
+ * Submit handler to write an unmanaged file using plain PHP functions.
+ *
+ * The key functions used here are:
+ * - file_unmanaged_save_data(), which takes a buffer and saves it to a named
+ *   file, but does not create any kind of tracking record in the database.
+ * - file_create_url(), which converts a URI in the form public://junk.txt or
+ *   private://something/test.txt into a URL like
+ *   http://example.com/sites/default/files/junk.txt.
+ * - drupal_tempnam() generates a temporary filename for use.
+ * @ingroup file_example
+ */
+
+function file_example_unmanaged_php_submit($form, &$form_state) {
+  $data = $form_state['values']['write_contents'];
+  $destination = !empty($form_state['values']['destination']) ? $form_state['values']['destination'] : NULL;
+
+  if (empty($destination)) {
+    // If no destination has been provided, use a generated name.
+    $destination = drupal_tempnam('public://', 'file');
+  }
+
+  // With all traditional PHP functions we can use the stream wrapper notation
+  // for a file as well.
+  $fp = fopen($destination, 'w');
+
+  // To demonstrate the fact that everything is based on streams, we'll do
+  // multiple 5-character writes to put this to the file. We could easily
+  // (and far more conveniently) write it in a single statement with
+  // fwrite($fp, $data).
+  $length = strlen($data);
+  $write_size = 5;
+  for ($i=0; $i < $length; $i += $write_size) {
+    $result = fwrite($fp, substr($data, $i, $write_size));
+    if ($result === FALSE) {
+      drupal_set_message(t('Failed writing to the file; '), 'error');
+      fclose($fp);
+      return;
+    }
+  }
+  $url = file_create_url($destination);
+  drupal_set_message(t('Saved file as %filename (accessible as !url)', array('%filename' => $destination, '!url' => l($url, $url))));
+}
+/**
+ * Submit handler for reading a stream wrapper.
+ *
+ * Drupal now has full support for PHP's stream wrappers, which means that
+ * instead of the traditional use of all the file functions
+ * ($fp = fopen("/tmp/some_file.txt");) far more sophisticated and generalized
+ * (and extensible) things can be opened as if they were files. Drupal itself
+ * provides the public:// and private:// schemes for handling public and
+ * private files. PHP provides file:// (the default) and http://, so that a
+ * URL can be read or written (as in a POST) as if it were a file. In addition,
+ * new schemes can be provided for custom applications, as will be demonstrated
+ * below.
+ *
+ * Here we take the "file" stream wrapper provided in the form. We grab the
+ * contents with file_get_contents(). Notice that's it's as simple as that:
+ * file_get_contents("http://example.com") or
+ * file_get_contents("public://somefile.txt") just works. Although it's
+ * not necessary, we use file_unmanaged_save_data() to save this file locally
+ * and then find a local URL for it by using file_create_url().
+ * @ingroup file_example
+ */
+function file_example_read_submit($form, &$form_state) {
+  $source = $form_state['values']['read_location'];
+
+  // Make a working filename to save this by stripping off the (possible)
+  // file portion of the streamwrapper. If it's an evil file extension,
+  // file_munge_filename() will neuter it.
+  $filename = file_munge_filename(preg_replace('@^.*/@', '', $source), '', TRUE);
+  $buffer = file_get_contents($source);
+
+  if ($buffer) {
+    $sourcename = file_unmanaged_save_data($buffer, 'public://' . $filename);
+    if ($sourcename) {
+      $url = file_create_url($sourcename);
+      drupal_set_message(t('The file was read and copied to %filename which is accessible at !url', array('%filename' => $sourcename, '!url' => l($url, $url))));
+    }
+    else {
+      drupal_set_message(t('Failed to save the file'));
+    }
+  }
+  else { // We failed to get the contents of the requested file
+    drupal_set_message(t('Failed to retrieve the file %file', array('%file' => $source)));
+  }
+}
+
+/**
+ * Submit handler for directory creation.
+ * Here we create a directory and set proper permissions on it using
+ * file_prepare_directory().
+ * @ingroup file_example
+ */
+function file_example_create_directory_submit($form, &$form_state) {
+  $directory = $form_state['values']['create_directory'];
+
+  // The options passed to file_prepare_directory are a bitmask, so we can
+  // specify either FILE_MODIFY_PERMISSIONS (set permissions on the directory),
+  // FILE_CREATE_DIRECTORY, or both together:
+  // FILE_MODIFY_PERMISSIONS | FILE_CREATE_DIRECTORY.
+  // FILE_MODIFY_PERMISSIONS will set the permissions of the directory by
+  // by default to 0755, or to the value of the variable 'file_chmod_directory'.
+  if (!file_prepare_directory($directory, FILE_MODIFY_PERMISSIONS | FILE_CREATE_DIRECTORY)) {
+    drupal_set_message(t('Failed to create %directory.', array('%directory' => $directory)), 'error');
+  }
+  else {
+    drupal_set_message(t('Directory %directory is ready for use.', array('%directory' => $directory)));
+  }
+}
+
+
+///// Stream Wrapper implementation of session:// scheme. The entire rest of
+///// this file is devoted to the implementation of a sample stream wrapper
+///// implementation.
+
+/**
+ * Implements hook_stream_wrappers().
+ * hook_stream_wrappers() is Drupal's way of exposing the class that PHP will
+ * use to provide a new stream wrapper class. In this case, we'll expose the
+ * 'session' scheme, so a file reference like "session://example/example.txt"
+ * is readable and writable as a location in the $_SESSION variable.
+ *
+ * @see FileExampleSessionStreamWrapper
+ *
+ * defgroup streamwrapper_example Stream Wrapper Example
+ */
+function file_example_stream_wrappers() {
+  $wrappers = array(
+    'session' => array(
+      'name' => t('Session variable storage'),
+      'class' => 'FileExampleSessionStreamWrapper',
+      'description' => t('Store files in the $_SESSION variable as an example.'),
+    ),
+  );
+  return $wrappers;
+}
+
+/**
+ * A utility function to allow us to see what is in a session "file".
+ *
+ * @param $session_path
+ *   The path, as in 'example/some/thing.txt'. This actually is a $_SESSION
+ *   key. example/some/thing.txt would be
+ *   $_SESSION['file_example']['some']['thing.txt']
+ */
+function file_example_session_contents($session_path) {
+  if (module_exists('devel')) {
+    dsm($_SESSION['file_example'], t('Entire $_SESSION["file_example"]'));
+  }
+  $content = file_get_contents('session://' . $session_path);
+  return t('Contents of ') . check_plain($session_path) . ': ' . print_r($content, TRUE);
+}
+
+/**
+ * Example stream wrapper class to handle session:// streams.
+ * This is just an example, as it could have horrible results if much
+ * information were placed in the $_SESSION variable. However, it does
+ * demonstrate both the read and write implementation of a stream wrapper.
+ *
+ * A "stream" is an important Unix concept for the reading and writing of
+ * files and other devices. Reading or writing a "stream" just means that you
+ * open some device, file, internet site, or whatever, and you don't have to
+ * know at all what it is. All the functions that deal with it are the same.
+ * You can read/write more from/to the stream, seek a position in the stream,
+ * or anything else without the code that does it even knowing what kind
+ * of device it is talking to. This Unix idea is extended into PHP's
+ * mindset.
+ *
+ * The idea of "stream wrapper" is that this can be extended indefinitely.
+ * The classic example is HTTP: With PHP you can do a
+ * file_get_contents("http://drupal.org/projects") as if it were a file,
+ * because the scheme "http" is supported natively in PHP. So Drupal adds
+ * the public:// and private:// schemes, and contrib modules can add any
+ * scheme they want to. This example adds the session:// scheme, which allows
+ * reading and writing the $_SESSION['file_example'] key as if it were a file.
+ */
+class FileExampleSessionStreamWrapper implements DrupalStreamWrapperInterface {
+  /**
+   * Stream context resource.
+   *
+   * @var Resource
+   */
+  public $context;
+
+
+  /**
+   * Instance URI (stream).
+   *
+   * These streams will be references as 'session://example_target'
+   *
+   * @var String
+   */
+  protected $uri;
+
+  /**
+   * The content of the stream.
+   * Since this trivial example just uses the $_SESSION variable, this is
+   * simply a reference to the contents of the related part of
+   * $_SESSION['file_example'].
+   */
+  protected $session_content;
+
+  /**
+   * The pointer to the next read or write within the session variable.
+   */
+  protected $stream_pointer;
+
+  /**
+   * Implements setUri().
+   */
+  function setUri($uri) {
+    $this->uri = $uri;
+  }
+
+  /**
+   * Implements getUri().
+   */
+  function getUri() {
+    return $this->uri;
+  }
+
+  /**
+   *  Implements getTarget().
+   *  The "target" is the portion of the URI to the right of the scheme.
+   *  So in session://example/test.txt, the target is 'example/test.txt'.
+   */
+  function getTarget($uri = NULL) {
+    if (!isset($uri)) {
+      $uri = $this->uri;
+    }
+
+    list($scheme, $target) = explode('://', $uri, 2);
+
+    // Remove erroneous leading or trailing, forward-slashes and backslashes.
+    // In the session:// scheme, there is never a leading slash on the target.
+    return trim($target, '\/');
+  }
+
+  /**
+   * Implements getMimeType().
+   */
+  static function getMimeType($uri, $mapping = NULL) {
+    if (!isset($mapping)) {
+      // The default file map, defined in file.mimetypes.inc is quite big.
+      // We only load it when necessary.
+      include_once DRUPAL_ROOT . '/includes/file.mimetypes.inc';
+      $mapping = file_mimetype_mapping();
+    }
+
+    $extension = '';
+    $file_parts = explode('.', basename($uri));
+
+    // Remove the first part: a full filename should not match an extension.
+    array_shift($file_parts);
+
+    // Iterate over the file parts, trying to find a match.
+    // For my.awesome.image.jpeg, we try:
+    //   - jpeg
+    //   - image.jpeg, and
+    //   - awesome.image.jpeg
+    while ($additional_part = array_pop($file_parts)) {
+      $extension = strtolower($additional_part . ($extension ? '.' . $extension : ''));
+      if (isset($mapping['extensions'][$extension])) {
+        return $mapping['mimetypes'][$mapping['extensions'][$extension]];
+      }
+    }
+
+    return 'application/octet-stream';
+  }
+
+  /**
+   * Implements getDirectoryPath().
+   * In this case there is no directory string, so return an empty string.
+   */
+  public function getDirectoryPath() {
+    return '';
+  }
+
+  /**
+   * Overrides getExternalUrl().
+   * We have set up a helper function and menu entry to provide access to this
+   * key via HTTP; normally it would be accessible some other way.
+   */
+  function getExternalUrl() {
+    $path = $this->getLocalPath();
+    $path = preg_replace('/^file_example\//', '', $path);
+    $url = url('examples/file_example/access_session/' . $path, array('absolute' => TRUE));
+    return $url;
+  }
+
+  /**
+   * We have no concept of chmod, so just return TRUE.
+   */
+  function chmod($mode) {
+    return TRUE;
+  }
+
+  /**
+   * Implements realpath().
+   */
+  function realpath() {
+    return $this->getLocalPath();
+  }
+
+  /**
+   * Returns the local path.
+   * Here we aren't doing anything but stashing the "file" in a key in the
+   * $_SESSION variable, so there's not much to do but to create a "path"
+   * which is really just a key in the $_SESSION variable. So something
+   * like 'session://one/two/three.txt' becomes
+   * $_SESSION['file_example']['one']['two']['three.txt'] and the actual path
+   * is "['file_example']['one']['two']['three.txt']".
+   *
+   * @param $uri
+   *   Optional URI, supplied when doing a move or rename.
+   */
+  protected function getLocalPath($uri = NULL) {
+    if (!isset($uri)) {
+      $uri = $this->uri;
+    }
+
+    $raw_path  = str_replace('session://', '', $uri);
+    $raw_path = trim($raw_path, '/');
+    $path = 'file_example/' . $raw_path;
+    return $path;
+  }
+
+  /**
+   * Opens a stream, as for fopen(), file_get_contents(), file_put_contents()
+   *
+   * @param $uri
+   *   A string containing the URI to the file to open.
+   * @param $mode
+   *   The file mode ("r", "wb" etc.).
+   * @param $options
+   *   A bit mask of STREAM_USE_PATH and STREAM_REPORT_ERRORS.
+   * @param &$opened_path
+   *   A string containing the path actually opened.
+   *
+   * @return
+   *   Returns TRUE if file was opened successfully. (Always returns TRUE).
+   *
+   * @see http://php.net/manual/en/streamwrapper.stream-open.php
+   */
+  public function stream_open($uri, $mode, $options, &$opened_path) {
+    $this->uri = $uri;
+
+    // The "local path" will be the path representing where the item is in the
+    // $_SESSION variable. So for session://example/test.txt it would be
+    // 'file_example/example/test.txt'.
+    $path = $this->getLocalPath();
+
+    // We make $session_content a reference to the appropriate key in the
+    // $_SESSION variable. So if the local path were
+    // file_example/example/test.txt it $session_content would now be a
+    // reference to $_SESSION['files_example']['example']['test.txt'].
+    $this->session_content = &$this->uri_to_session_key($uri);
+
+    // Reset the stream pointer since this is an open.
+    $this->stream_pointer = 0;
+    return TRUE;
+  }
+
+  /**
+   * Return a reference to the correct $_SESSION key.
+   * @param $uri
+   *   The uri: session://something
+   * @param $create
+   *   If TRUE, create the key
+   *
+   * @return
+   *   TRUE if the key exists (which it will if $create was set)
+   */
+  protected function &uri_to_session_key($uri, $create = TRUE) {
+    $path = $this->getLocalPath($uri);
+    $path_components = preg_split('/\//', $path);
+    $fail = FALSE;
+    $var = &$_SESSION;
+    foreach ($path_components as $component) {
+      if ($create || isset($var[$component])) {
+        $var = &$var[$component];
+      }
+      else {
+        return $fail;
+      }
+    }
+    return $var;
+  }
+  /**
+   * Support for flock().
+   * The $_SESSION variable has no locking capability, so return TRUE.
+   *
+   * @param $operation
+   *   One of the following:
+   *   - LOCK_SH to acquire a shared lock (reader).
+   *   - LOCK_EX to acquire an exclusive lock (writer).
+   *   - LOCK_UN to release a lock (shared or exclusive).
+   *   - LOCK_NB if you don't want flock() to block while locking (not
+   *     supported on Windows).
+   *
+   * @return
+   *   Always returns TRUE at the present time. (no support)
+   *
+   * @see http://php.net/manual/en/streamwrapper.stream-lock.php
+   */
+  public function stream_lock($operation) {
+    return TRUE;
+  }
+
+  /**
+   * Support for fread(), file_get_contents() etc.
+   *
+   * @param $count
+   *   Maximum number of bytes to be read.
+   *
+   * @return
+   *   The string that was read, or FALSE in case of an error.
+   *
+   * @see http://php.net/manual/en/streamwrapper.stream-read.php
+   */
+  public function stream_read($count) {
+    $remaining_chars = strlen($this->session_content) - $this->stream_pointer;
+    $number_to_read = min($count, $remaining_chars);
+    $buffer = substr($this->session_content, $this->stream_pointer, $number_to_read);
+    $this->stream_pointer += $number_to_read;
+    return $buffer;
+  }
+
+  /**
+   * Support for fwrite(), file_put_contents() etc.
+   *
+   * @param $data
+   *   The string to be written.
+   *
+   * @return
+   *   The number of bytes written (integer).
+   *
+   * @see http://php.net/manual/en/streamwrapper.stream-write.php
+   */
+  public function stream_write($data) {
+    // Sanitize the data in a simple way since we're putting it into the
+    // session variable.
+    $data = check_plain($data);
+    $this->session_content = substr_replace($this->session_content, $data, $this->stream_pointer);
+    $this->stream_pointer += strlen($data);
+    return strlen($data);
+  }
+
+  /**
+   * Support for feof().
+   *
+   * @return
+   *   TRUE if end-of-file has been reached.
+   *
+   * @see http://php.net/manual/en/streamwrapper.stream-eof.php
+   */
+  public function stream_eof() {
+    return FALSE;
+  }
+
+  /**
+   * Support for fseek().
+   *
+   * @param $offset
+   *   The byte offset to got to.
+   * @param $whence
+   *   SEEK_SET, SEEK_CUR, or SEEK_END.
+   *
+   * @return
+   *   TRUE on success.
+   *
+   * @see http://php.net/manual/en/streamwrapper.stream-seek.php
+   */
+  public function stream_seek($offset, $whence) {
+    if (strlen($this->session_content) >= $offset) {
+      $this->stream_pointer = $offset;
+      return TRUE;
+    }
+    return FALSE;
+  }
+
+  /**
+   * Support for fflush().
+   *
+   * @return
+   *   TRUE if data was successfully stored (or there was no data to store).
+   *   This always returns TRUE, as this example provides and needs no
+   *   flush support.
+   *
+   * @see http://php.net/manual/en/streamwrapper.stream-flush.php
+   */
+  public function stream_flush() {
+    return TRUE;
+  }
+
+  /**
+   * Support for ftell().
+   *
+   * @return
+   *   The current offset in bytes from the beginning of file.
+   *
+   * @see http://php.net/manual/en/streamwrapper.stream-tell.php
+   */
+  public function stream_tell() {
+    return $this->stream_pointer;
+  }
+
+  /**
+   * Support for fstat().
+   *
+   * @return
+   *   An array with file status, or FALSE in case of an error - see fstat()
+   *   for a description of this array.
+   *
+   * @see http://php.net/manual/en/streamwrapper.stream-stat.php
+   */
+  public function stream_stat() {
+    return array();
+  }
+
+  /**
+   * Support for fclose().
+   *
+   * @return
+   *   TRUE if stream was successfully closed.
+   *
+   * @see http://php.net/manual/en/streamwrapper.stream-close.php
+   */
+  public function stream_close() {
+    $this->stream_pointer = 0;
+    return TRUE;
+  }
+
+  /**
+   * Support for unlink().
+   *
+   * @param $uri
+   *   A string containing the uri to the resource to delete.
+   *
+   * @return
+   *   TRUE if resource was successfully deleted.
+   *
+   * @see http://php.net/manual/en/streamwrapper.unlink.php
+   */
+  public function unlink($uri) {
+    unset($this->session_data);
+    $this->stream_pointer = 0;
+    return TRUE;
+  }
+
+  /**
+   * Support for rename().
+   *
+   * @param $from_uri,
+   *   The uri to the file to rename.
+   * @param $to_uri
+   *   The new uri for file.
+   *
+   * @return
+   *   TRUE if file was successfully renamed.
+   *
+   * @see http://php.net/manual/en/streamwrapper.rename.php
+   */
+  public function rename($from_uri, $to_uri) {
+    $from_key = &$this->uri_to_session_key($from_uri);
+    $to_key = &$this->uri_to_session_key($to_uri);
+    if (is_dir($to_key) || is_file($to_key)) {
+      return FALSE;
+    }
+    $to_key = $from_key;
+    unset($from_key);
+    return TRUE;
+  }
+
+  /**
+   * Gets the name of the directory from a given path.
+   *
+   * @param $uri
+   *   A URI.
+   *
+   * @return
+   *   A string containing the directory name.
+   *
+   * @see drupal_dirname()
+   */
+  public function dirname($uri = NULL) {
+    list($scheme, $target) = explode('://', $uri, 2);
+    $target  = $this->getTarget($uri);
+    if (strpos($target, '/')) {
+      $dirname = preg_replace('@/[^/]*$@', '', $target);
+    }
+    else
+    {
+      $dirname = '';
+    }
+    return $scheme . '://' . $dirname;
+  }
+
+  /**
+   * Support for mkdir().
+   *
+   * @param $uri
+   *   A string containing the URI to the directory to create.
+   * @param $mode
+   *   Permission flags - see mkdir().
+   * @param $options
+   *   A bit mask of STREAM_REPORT_ERRORS and STREAM_MKDIR_RECURSIVE.
+   *
+   * @return
+   *   TRUE if directory was successfully created.
+   *
+   * @see http://php.net/manual/en/streamwrapper.mkdir.php
+   */
+  public function mkdir($uri, $mode, $options) {
+    // If this already exists, then we can't mkdir.
+    if (is_dir($uri) || is_file($uri)) {
+      return FALSE;
+    }
+
+    // Since array keys are magically created, we don't need to do anything.
+    return TRUE;
+  }
+
+  /**
+   * Support for rmdir().
+   *
+   * @param $uri
+   *   A string containing the URI to the directory to delete.
+   * @param $options
+   *   A bit mask of STREAM_REPORT_ERRORS.
+   *
+   * @return
+   *   TRUE if directory was successfully removed.
+   *
+   * @see http://php.net/manual/en/streamwrapper.rmdir.php
+   */
+  public function rmdir($uri, $options) {
+    // TODO: Implement rmdir();
+    return TRUE;
+  }
+
+  /**
+   * Support for stat().
+   * This important function goes back to the Unix way of doing things.
+   * In this example almost the entire stat array is irrelevant, but the
+   * mode is very important. It tells PHP whether we have a file or a
+   * directory and what the permissions are. All that is packed up in a
+   * bitmask. This is not normal PHP fodder.
+   *
+   * @param $uri
+   *   A string containing the URI to get information about.
+   * @param $flags
+   *   A bit mask of STREAM_URL_STAT_LINK and STREAM_URL_STAT_QUIET.
+   *
+   * @return
+   *   An array with file status, or FALSE in case of an error - see fstat()
+   *   for a description of this array.
+   *
+   * @see http://php.net/manual/en/streamwrapper.url-stat.php
+   */
+  public function url_stat($uri, $flags) {
+
+    $key = $this->uri_to_session_key($uri, FALSE);
+    $return = FALSE; // Default to fail.
+    $mode = 0;
+
+    // We will call an array a directory and the root is always an array.
+    if (is_array($key) || $uri == 'session://') {
+      $mode = 0040000; // S_IFDIR means it's a directory.
+    }
+    else if ($key !== FALSE) {
+      $mode = 0100000; // S_IFREG, means it's a file.
+    }
+
+    if ($mode) {
+      $mode |= 0777;  // There are no protections on this, so all writable.
+      $return = array(
+        'dev' => 0,
+        'ino' => 0,
+        'mode' => $mode,
+        'nlink' => 0,
+        'uid' => 0,
+        'gid' => 0,
+        'rdev' => 0,
+        'size' => 0,
+        'atime' => 0,
+        'mtime' => 0,
+        'ctime' => 0,
+        'blksize' => 0,
+        'blocks' => 0,
+      );
+    }
+    return $return;
+  }
+
+  /**
+   * Support for opendir().
+   *
+   * @param $uri
+   *   A string containing the URI to the directory to open.
+   * @param $options
+   *   Unknown (parameter is not documented in PHP Manual).
+   *
+   * @return
+   *   TRUE on success.
+   *
+   * @see http://php.net/manual/en/streamwrapper.dir-opendir.php
+   */
+  public function dir_opendir($uri, $options) {
+    // TODO: Implement dir_opendir().
+    return FALSE;
+  }
+
+  /**
+   * Support for readdir().
+   *
+   * @return
+   *   The next filename, or FALSE if there are no more files in the directory.
+   *
+   * @see http://php.net/manual/en/streamwrapper.dir-readdir.php
+   */
+  public function dir_readdir() {
+    // TODO: Implement dir_readdir().
+    return FALSE;
+  }
+
+  /**
+   * Support for rewinddir().
+   *
+   * @return
+   *   TRUE on success.
+   *
+   * @see http://php.net/manual/en/streamwrapper.dir-rewinddir.php
+   */
+  public function dir_rewinddir() {
+    // TODO: implement rewinddir();
+    return FALSE;
+  }
+
+  /**
+   * Support for closedir().
+   *
+   * @return
+   *   TRUE on success.
+   *
+   * @see http://php.net/manual/en/streamwrapper.dir-closedir.php
+   */
+  public function dir_closedir() {
+    // TODO: implement dir_closedir().
+    return FALSE;
+  }
+}
