diff --git a/AmazonS3StreamWrapper.inc b/AmazonS3StreamWrapper.inc
index 908561c..a67dc99 100644
--- a/AmazonS3StreamWrapper.inc
+++ b/AmazonS3StreamWrapper.inc
@@ -925,7 +925,7 @@ class AmazonS3StreamWrapper implements DrupalStreamWrapperInterface {
    *
    * @see http://docs.amazonwebservices.com/AWSSDKforPHP/latest/#i=AmazonS3
    */
-  protected function getS3() {
+  public function getS3() {
     if($this->s3 == null) {
       $bucket = variable_get('amazons3_bucket', '');
 
@@ -1040,7 +1040,7 @@ class AmazonS3StreamWrapper implements DrupalStreamWrapperInterface {
    *  @return
    *    An array if the $uri exists, otherwise FALSE.
    */
-  protected function _amazons3_get_object($uri, $cache = TRUE) {
+  public function _amazons3_get_object($uri, $cache = TRUE) {
     if ($uri == 's3://' || $uri == 's3:') {
       $metadata = $this->_amazons3_format_response('/', array(), TRUE);
       return $metadata;
diff --git a/amazons3.module b/amazons3.module
index bfea030..db4cd36 100644
--- a/amazons3.module
+++ b/amazons3.module
@@ -5,6 +5,8 @@
  * Provides S3 stream wrapper
  */
 
+module_load_include('inc', 'amazons3', 'amazons3_reference');
+
 /**
  * Implements hook_stream_wrappers().
  *
@@ -34,6 +36,15 @@ function amazons3_menu() {
     'access arguments' => array('administer amazons3'),
   );
 
+  $items['amazons3/reference/%/%/%'] = array(
+    'page callback' => 'amazons3_referenced_autocomplete',
+    'page arguments' => array(2, 3, 4),
+    'access callback' => '_filefield_sources_field_access',
+    'access arguments' => array(2, 3, 4),
+    'file' => 'amazons3_reference.inc',
+    'type' => MENU_CALLBACK,
+  );
+
   return $items;
 }
 
@@ -70,10 +81,10 @@ function amazons3_admin() {
   $form = array();
 
   $form['amazons3_bucket'] = array(
-      '#type'           => 'textfield',
-      '#title'          => t('Default Bucket Name'),
-      '#default_value'  => variable_get('amazons3_bucket', ''),
-      '#required'       => TRUE,
+    '#type'           => 'textfield',
+    '#title'          => t('Default Bucket Name'),
+    '#default_value'  => variable_get('amazons3_bucket', ''),
+    '#required'       => TRUE,
   );
 
   $form['amazons3_cache'] = array(
@@ -91,15 +102,15 @@ function amazons3_admin() {
   );
 
   $form['amazons3_domain'] = array(
-      '#type'           => 'textfield',
-      '#title'          => t('CDN Domain Name'),
-      '#description'    => t('If serving files from CloudFront then the bucket name can differ from the domain name.'),
-      '#default_value'  => variable_get('amazons3_domain', ''),
-      '#states'         => array(
-        'visible' => array(
-          ':input[id=edit-amazons3-cname]' => array('checked' => TRUE),
-        )
-      ),
+    '#type'           => 'textfield',
+    '#title'          => t('CDN Domain Name'),
+    '#description'    => t('If serving files from CloudFront then the bucket name can differ from the domain name.'),
+    '#default_value'  => variable_get('amazons3_domain', ''),
+    '#states'         => array(
+      'visible' => array(
+        ':input[id=edit-amazons3-cname]' => array('checked' => TRUE),
+      )
+    ),
   );
 
   $form['amazons3_torrents'] = array(
@@ -137,6 +148,12 @@ function amazons3_admin() {
     '#submit' => array('amazons3_clear_cache_submit'),
   );
 
+  $form['amazons3_clear_cache']['rebuild'] = array(
+    '#type' => 'submit',
+    '#value' => t('Rebuild file metadata cache'),
+    '#submit' => array('amazons3_batch_rebuild_cache'),
+  );
+
   return system_settings_form($form);
 }
 
@@ -166,12 +183,12 @@ function amazons3_admin_validate($form, &$form_state) {
         form_set_error('amazons3_bucket', t('There was a problem with the SSL certificate. Try setting AWS_CERTIFICATE_AUTHORITY to true in "libraries/awssdk/config.inc.php". You may also have a curl library (e.g. the default shipped with MAMP) that does not contain trust certificates for the major authorities.'));
       }
       else {
-        form_set_error('amazons3_bucket', t('There was a problem connecting to S3'));
+        form_set_error('amazons3_bucket', t('There was a problem connecting to S3: '.$e));
       }
 
     }
     catch(Exception $e) {
-      form_set_error('amazons3_bucket', t('There was a problem using S3'));
+      form_set_error('amazons3_bucket', t('There was a problem using S3: '.$e));
     }
   }
 }
@@ -194,3 +211,140 @@ function amazons3_clear_cache_submit($form, &$form_state) {
   drupal_set_message(t('Cache cleared.'));
 }
 
+/**
+ * Submit handler to rebuild the cache via the Batch API.
+ */
+function amazons3_batch_rebuild_cache($options1, $options2) {
+
+  //@ todo: Do not truncate the table, if we can find a way to get just the newly-added files.
+  db_query('TRUNCATE TABLE {amazons3_file}');
+
+  $batch = array(
+    'operations' => array(
+      array('amazons3_rebuild_process', array($options1, $options2)),
+    ),
+    'finished' => 'amazons3_rebuild_process_finished',
+    'title' => t('Processing Amazon S3 Cache Rebuild'),
+    'init_message' => t('Starting. Connecting to S3 and fetching objects. Please wait...'),
+    'progress_message' => t('Rebuilding the cache... @current of @total'),
+    'error_message' => t('Amazon S3 Cache Rebuild has encountered an error.'),
+  );
+  batch_set($batch);
+
+}
+
+/**
+ * Batch Operation Callback
+ */
+function amazons3_rebuild_process($options1, $options2, &$context) {
+
+  $bucket = variable_get('amazons3_bucket', '');
+
+  if(!libraries_load('awssdk')) {
+    drupal_set_message(t('Unable to load the AWS SDK. Please check you have installed the library correctly and configured your S3 credentials.'), 'error');
+  }
+  else if(!class_exists('AmazonS3')) {
+    drupal_set_message(t('Cannot load AmazonS3 class. Please check the awssdk is installed correctly'), 'error');
+  }
+  else {
+    try {
+      $s3 = new AmazonS3();
+
+      $user_id = $s3->get_canonical_user_id();
+      if(!$user_id['id']) {
+        drupal_set_message('The S3 access credentials are invalid', 'error');
+      }
+      else if(!$s3->if_bucket_exists($bucket)) {
+        drupal_set_message('The bucket does not exist', 'error');
+      }
+
+      $bucket = variable_get('amazons3_bucket', '');
+
+      $limit = 100; // @todo: Make this configurable.
+
+      // Total number of objects in the bucket.
+      $total = count($s3->get_object_list($bucket));
+
+
+      // Create a new AmazonS3StreamWrapper so we can use some of its functions. (They have been made public.)
+      // @todo: Use reflection to extend the protected functions in the public class, unless this is good enough.
+      $wrapper = new AmazonS3StreamWrapper();
+
+      if (!isset($context['sandbox']['progress'])) {
+
+        $objects = $s3->get_object_list($bucket, array('max-keys' => $limit));
+
+        $context['sandbox']['last_key'] = $objects[$limit-1];
+        $context['sandbox']['progress'] = 0;
+        $context['sandbox']['current_node'] = 0;
+      }
+      else {
+        /// If we 've already started processing, remember the last URI so we can paginate from there later.
+        $objects = $s3->get_object_list($bucket,
+          array('max-keys' => $limit, 'marker' => $context['sandbox']['last_key']));
+
+        // Reset the last_key for this new batch.
+        $context['sandbox']['last_key'] = $objects[$limit-1];
+      }
+
+      $context['sandbox']['max'] = $total;
+
+      // Grab each individual object's metadata and inset it into the database.
+      foreach($objects as $object) {
+        //$metadata = $wrapper->_amazons3_get_object($object);
+
+        // Fudge the metadata for now. @todo: Uncomment above call for $metadata, but try to make it faster.
+        $metadata['filesize'] = 0;
+        $metadata['timestamp'] = time();
+        $metadata['dir'] = 0;
+        $metadata['mode'] = 33279;
+        $metadata['uid'] = 0;
+        $metadata['uri'] = $object;
+
+        if ($metadata['uri'] != ' ') {
+          $context['sandbox']['progress']++;
+          $context['results'][] += $object;
+          $context['sandbox']['current_node'] = $metadata['uri'];
+          $context['message'] = t('Now processing %current of %total',
+            array('%current' => $context['sandbox']['progress'], '%total' => $total));
+
+          db_merge('amazons3_file')
+            ->key(array('uri' => $metadata['uri']))
+            ->fields($metadata)
+            ->execute();
+
+          if ($context['sandbox']['progress'] != $context['sandbox']['max']) {
+            $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
+          }
+        }
+      }
+    }
+    catch(RequestCore_Exception $e){
+      if(strstr($e->getMessage(), 'SSL certificate problem')) {
+        drupal_set_message('There was a problem with the SSL certificate. Try setting AWS_CERTIFICATE_AUTHORITY to true in "libraries/awssdk/config.inc.php".
+        You may also have a curl library (e.g. the default shipped with MAMP) that does not contain trust certificates for the major authorities.', 'error');
+      }
+      else {
+        drupal_set_message('There was a problem connecting to S3: '.$e, 'error');
+      }
+
+    }
+    catch(Exception $e) {
+      drupal_set_message('There was a problem using S3: '.$e, 'error');
+    }
+  }
+}
+
+/**
+ * Batch 'finished' callback
+ */
+function amazons3_rebuild_process_finished($success, $results, $operations) {
+  if ($success) {
+    $message = t('Cache successfully rebuilt. !count files were added.', array('!count' => count($results)));
+  }
+  else {
+    $error_operation = reset($operations);
+    $message = t('An error occurred while processing %error_operation with arguments: @arguments', array('%error_operation' => $error_operation[0], '@arguments' => print_r($error_operation[1], TRUE)));
+  }
+  drupal_set_message($message);
+}
diff --git a/amazons3_reference.inc b/amazons3_reference.inc
new file mode 100644
index 0000000..db01929
--- /dev/null
+++ b/amazons3_reference.inc
@@ -0,0 +1,305 @@
+<?php
+/**
+ * @file
+ * A FileField extension to allow referencing of existing files.
+ *
+ * The "hooks" in this file are not true hooks, they're called individually
+ * from the main filefield_sources.module in the corresponding hook by the
+ * same name. Any of these hooks could be broken out into a separate module.
+ */
+define('AMAZONS3_REFERENCED_HINT_TEXT', 'Object.mp3');
+
+/**
+ * Implements hook_filefield_sources_info().
+ */
+function amazons3_filefield_sources_info() {
+  $source = array();
+
+  $source['amazons3_referenced'] = array(
+    'name' => t('S3 Autocomplete reference'),
+    'label' => t('S3 Reference'),
+    'description' => t('Reuse an existing file by entering its file name.'),
+    'process' => 'amazons3_referenced_process',
+    'value' => 'amazons3_referenced_value',
+    'weight' => 1,
+  );
+  return $source;
+}
+
+/**
+ * Implements hook_theme().
+ */
+function amazons3_theme() {
+  return array(
+    'amazons3_referenced_element' => array(
+      'render element' => 'element',
+      'file' => 'amazons3_reference.inc',
+    ),
+    'amazons3_referenced_autocomplete_item' => array(
+      'variables' => array('file' => NULL),
+      'file' => 'amazons3_reference.inc',
+    ),
+  );
+}
+
+/**
+ * Implements hook_filefield_sources_widgets().
+ */
+function amazons3_filefield_sources_widgets() {
+  // Add any widgets that your module supports here.
+  return array('file', 'commerce_file_generic');
+}
+
+/**
+ * Implements hook_filefield_source_settings().
+ */
+function filefield_source_amazons3_settings($op, $instance) {
+  $return = array();
+
+  if ($op == 'form') {
+    $settings = $instance['widget']['settings']['filefield_sources'];
+
+    $return['amazons3_referenced'] = array(
+      '#title' => t('S3 Autocomplete reference options'),
+      '#type' => 'fieldset',
+      '#collapsible' => TRUE,
+      '#collapsed' => TRUE,
+    );
+
+    $return['amazons3_referenced']['autocomplete'] = array(
+      '#title' => t('Match file name'),
+      '#options' => array(
+        '0' => t('Starts with string'),
+        '1' => t('Contains string'),
+      ),
+      '#type' => 'radios',
+      '#default_value' => isset($settings['amazons3_referenced']['autocomplete']) ? $settings['amazons3_referenced']['autocomplete'] : '0',
+    );
+  }
+  elseif ($op == 'save') {
+    $return['amazons3_referenced']['autocomplete'] = '0';
+  }
+
+  return $return;
+}
+
+/**
+ * A #process callback to extend the filefield_widget element type.
+ */
+function amazons3_referenced_process($element, &$form_state, $form) {
+
+  $element['amazons3_referenced'] = array(
+    '#weight' => 100.5,
+    '#theme' => 'amazons3_referenced_element',
+    '#filefield_source' => TRUE, // Required for proper theming.
+    '#filefield_sources_hint_text' => AMAZONS3_REFERENCED_HINT_TEXT,
+  );
+
+  $element['amazons3_referenced']['autocomplete'] = array(
+    '#type' => 'textfield',
+    '#autocomplete_path' => 'amazons3/reference/' . $element['#entity_type'] . '/' . $element['#bundle'] . '/' . $element['#field_name'],
+    '#description' => t('Choose a file from your S3 bucket.'),
+  );
+
+  $element['amazons3_referenced']['select'] = array(
+    '#name' => implode('_', $element['#array_parents']) . '_autocomplete_select',
+    '#type' => 'submit',
+    '#value' => t('Select'),
+    '#validate' => array(),
+    '#submit' => array('filefield_sources_field_submit'),
+    '#name' => $element['#name'] . '[amazons3_referenced][button]',
+    '#limit_validation_errors' => array($element['#parents']),
+    '#ajax' => array(
+      'path' => 'file/ajax/' . implode('/', $element['#array_parents']) . '/' . $form['form_build_id']['#value'],
+      'wrapper' => $element['#id'] . '-ajax-wrapper',
+      'effect' => 'fade',
+    ),
+  );
+
+  return $element;
+}
+
+function amazons3_referenced_field_validate(&$form, &$form_state) {
+/*
+
+  $parents = array_slice($form_state['triggering_element']['#parents'], 0, -1);
+  //drupal_array_set_nested_value($form_state['input'], $parents, NULL);
+
+  // @todo: There has to be a "Drupal Way" of doing this.
+  if (!empty($form_state['values'][$parents[0]][$parents[1]][$parents[2]][$parents[3]]['autocomplete'])) {
+    $filename = $form_state['values'][$parents[0]][$parents[1]][$parents[2]][$parents[3]]['autocomplete'];
+
+    $frecord = amazons3_reference_create_file_record($filename);
+
+    if($frecord){
+      $form_state['values'][$parents[0]][$parents[1]][$parents[2]][$parents[3]]['fid'] = $frecord["fid"];
+    }else{
+      form_set_error($form, 'Please, check the file name');
+    }
+  }
+*/
+}
+
+
+function amazons3_reference_create_file_record($filename) {
+
+  libraries_load('awssdk');
+
+  $wrapper = new AmazonS3StreamWrapper();
+  $bucket = variable_get('amazons3_bucket', '');
+
+  $response = $wrapper->_amazons3_get_object($filename);
+  $metadata = $wrapper->getS3()->get_object_metadata($bucket, $filename);
+
+  if ($response) {
+    global $user;
+    $result = db_select('file_managed', 'fm')
+      ->fields('fm')
+      ->condition('uri', "s3://" . $filename)
+      ->execute()
+      ->fetchAssoc();
+
+    if ($result){
+      return $result;
+    }
+
+    $record = array(
+      "uid" => $user->uid,
+      "filename" => $filename,
+      "uri" => "s3://" . $filename,
+      "filemime" => $wrapper->getMimeType($filename),
+      "filesize" => $metadata["Size"],
+      "status" => '1',
+      "timestamp" => time(),
+      "type" => 'video',
+      "origname" => $filename,
+    );
+    drupal_write_record('file_managed', $record);
+
+
+
+    return $record;
+  }
+  return FALSE;
+}
+
+/**
+ * A #filefield_value_callback function.
+ */
+function amazons3_referenced_value($element, &$item) {
+  if (isset($item['amazons3_referenced']['autocomplete']) && strlen($item['amazons3_referenced']['autocomplete']) > 0 && $item['amazons3_referenced']['autocomplete'] != AMAZONS3_REFERENCED_HINT_TEXT) {
+    $filename = $item['amazons3_referenced']['autocomplete'];
+    $record = amazons3_reference_create_file_record($filename);
+    $field = field_info_instance($element['#entity_type'], $element['#field_name'], $element['#bundle']);
+
+    if ($record) {
+      $fid = db_query('SELECT fid FROM {file_managed} WHERE uri = :filename', array(':filename' =>  "s3://". $filename))->fetchField();
+
+      if ($file = file_load($fid)) {
+        // Now tell Drupal that our node is using the file.
+        file_usage_add($file, 'amazons3', 'preexisting', $file->fid);
+
+        // Below is commented out because this is not a local file.
+        if (filefield_sources_element_validate($element, (object) $file)) {
+          //$filename = filefield_sources_clean_filename($filename, $field['settings']['file_extensions']);
+          //$filepath = file_create_filename($filename, 's3://');
+
+          //if ($file = filefield_sources_save_file($filepath, $element['#upload_validators'], $element['#upload_location'])) {
+            $item = array_merge($item, (array) $file);
+          //}
+        }
+      }
+      else {
+        form_error($element, t('The referenced file could not be used because the file does not exist in the database.'));
+      }
+    }
+  }
+    // No matter what happens, clear the value from the autocomplete.
+    $item['amazons3_referenced']['autocomplete'] = '';
+}
+
+/**
+ * Menu callback; autocomplete.js callback to return a list of files.
+ */
+function amazons3_referenced_autocomplete($entity_type, $bundle_name, $field_name, $filename) {
+  $field = field_info_instance($entity_type, $field_name, $bundle_name);
+
+  $items = array();
+  if (!empty($field)) {
+    $files = amazons3_referenced_get_files($filename, $field);
+    foreach ($files as $file) {
+      $items[$file] = theme('amazons3_referenced_autocomplete_item', array('file' => $file));
+    }
+  }
+
+  drupal_json_output($items);
+}
+
+/**
+ * Theme the output of a single item in the autocomplete list.
+ */
+function theme_amazons3_referenced_autocomplete_item($variables) {
+  $file = $variables['file'];
+
+  $output = '';
+  $output .= '<div class="filefield-source-amazons3-reference-item">';
+  $output .= '<span class="filename">' . $file . '</span>';
+  $output .= '</div>';
+  return $output;
+}
+
+/**
+ * Theme the output of the autocomplete field.
+ */
+function theme_amazons3_referenced_element($variables) {
+  $element = $variables['element'];
+  $element['autocomplete']['#field_suffix'] = drupal_render($element['select']);
+  return '<div class="filefield-source filefield-source-amazons3 clear-block">' . drupal_render($element['autocomplete']) . '</div>';
+}
+
+/**
+ * Get all the files used within a particular field (or all fields).
+ *
+ * @param $file_name
+ *   The partial name of the file to retrieve.
+ * @param $instance
+ *   Optional. A CCK field array for which to filter returned files.
+ */
+function amazons3_referenced_get_files($filename, $instance = NULL) {
+  $instances = array();
+  if (!isset($instance)) {
+    foreach (field_info_fields() as $instance) {
+      if ($instance['type'] == 'file' || $instance['type'] == 'image') {
+        $instances[] = $instance;
+      }
+    }
+  }
+  else {
+    $instances = array($instance);
+  }
+
+  $files = array();
+  foreach ($instances as $instance) {
+    $field = field_info_field($instance['field_name']);
+
+    if (!isset($field['storage']['details']['sql']['FIELD_LOAD_CURRENT'])) {
+      continue;
+    }
+
+    $like = empty($instance['widget']['settings']['filefield_sources']['amazons3_referenced']['autocomplete']) ? ($filename . '%') : ('%' . $filename . '%');
+
+    $table = 'amazons3_file';
+    $query = db_select($table, 'af');
+    $query->fields('af', array('uri'));
+    $query->condition('af.uri', $like, 'LIKE');
+    $result = $query->execute();
+
+    if ($result) {
+      foreach ($result as $file) {
+        $files[$file->uri] = $file->uri;
+      }
+    }
+  }
+
+  return $files;
+}
\ No newline at end of file
