diff --git a/core/includes/config.inc b/core/includes/config.inc
index 78d12e8..8e3a109 100644
--- a/core/includes/config.inc
+++ b/core/includes/config.inc
@@ -1,6 +1,15 @@
 <?php
 
 use Drupal\Core\Config\DatabaseStorage;
+use Drupal\Core\Config\FileStorage;
+use Drupal\Core\Config\DrupalConfig;
+use Drupal\Core\Config\ConfigException;
+
+/**
+ * The value a module should return from hook_config_sync() to indicate that
+ * it should be called again by the config system during this sync.
+ */
+const CONFIG_DEFER_SYNC = 'CONFIG_DEFER_SYNC';
 
 /**
  * @file
@@ -27,7 +36,7 @@ function config_get_config_directory() {
 }
 
 /**
- * Moves the default config supplied by a module to the live config directory.
+ * Moves the default config supplied by a module to the active store.
  *
  * @param
  *   The name of the module we are installing.
@@ -55,38 +64,7 @@ function config_install_default_config($module) {
 }
 
 /**
- * Retrieves an iterable array which lists the children under a config 'branch'.
- *
- * Given the following configuration files:
- * - core.entity.node_type.article.xml
- * - core.entity.node_type.page.xml
- *
- * You can pass a prefix 'core.entity.node_type' and get back an array of the
- * filenames that match. This allows you to iterate through all files in a
- * branch.
- *
- * @param $prefix
- *   The prefix of the files we are searching for.
- *
- * @return
- *   An array of file names under a branch.
- */
-function config_get_files_with_prefix($prefix = '') {
-  $files = glob(config_get_config_directory() . '/' . $prefix . '*.xml');
-  $clean_name = function ($value) {
-    return basename($value, '.xml');
-  };
-  return array_map($clean_name, $files);
-}
-
-/**
- * @todo
- *
- * @param $prefix
- *   @todo
- *
- * @return
- *   @todo
+ * @todo http://drupal.org/node/1552396 renames this into config_load_all().
  */
 function config_get_storage_names_with_prefix($prefix = '') {
   return DatabaseStorage::getNamesWithPrefix($prefix);
@@ -103,9 +81,9 @@ function config_get_storage_names_with_prefix($prefix = '') {
  *   The name of the configuration object to retrieve. The name corresponds to
  *   an XML configuration file. For @code config(book.admin) @endcode, the
  *   config object returned will contain the contents of book.admin.xml.
- * @param $class
- *   The class name of the config object to be returned. Defaults to
- *   DrupalConfig.
+ * @param $storage_class
+ *   (optional) A storage driver class name to use for the DrupalConfig object.
+ *   Defaults to DrupalVerifiedStorageSQL.
  *
  * @return
  *   An instance of the class specified in the $class parameter.
@@ -113,8 +91,13 @@ function config_get_storage_names_with_prefix($prefix = '') {
  * @todo Replace this with an appropriate factory / ability to inject in
  *   alternate storage engines..
  */
-function config($name, $class = 'Drupal\Core\Config\DrupalConfig') {
-  return new $class(new DatabaseStorage($name));
+function config($name, $storage_class = NULL) {
+  global $conf;
+
+  if (!isset($storage_class)) {
+    $storage_class = (isset($conf['config_default_storage']) ? $conf['config_default_storage'] : 'Drupal\Core\Config\DatabaseStorage');
+  }
+  return new DrupalConfig(new $storage_class($name));
 }
 
 /**
@@ -224,3 +207,193 @@ function config_array_to_xml($array, &$xml_object) {
     }
   }
 }
+
+/**
+ * Reload config from disk and write new settings to the active store.
+ */
+function config_sync() {
+  $config_changes = config_get_changes_from_disk();
+  if (empty($config_changes)) {
+    return;
+  }
+
+  $lock_attempts = 0;
+  $lock_acquired = FALSE;
+  do {
+    if (!$lock_acquired = lock_acquire(__FUNCTION__, 5)) {
+      lock_wait(__FUNCTION__, 5);
+      continue;
+    }
+
+    try {
+      config_sync_invoke_sync_hooks($config_changes);
+      config_sync_save_changes($config_changes);
+      // Flush all caches and reset static variables after a successful import.
+      drupal_flush_all_caches();
+    }
+    catch (ConfigException $e) {
+      watchdog_exception('config_sync', $e);
+      config_sync_invoke_sync_error_hooks($config_changes);
+      lock_release(__FUNCTION__);
+      return;
+    }
+  } while ($lock_acquired === FALSE && ++$lock_attempts < 5);
+
+  if ($lock_acquired) {
+    lock_release(__FUNCTION__);
+    return TRUE;
+  }
+  else {
+    watchdog('config_sync', 'Failed to get lock while trying to sync config.');
+    return FALSE;
+  }
+}
+
+/**
+ * Writes an array of config file changes to the active store.
+ *
+ * @param $config_changes
+ *   An array of changes to be written.
+ */
+function config_sync_save_changes($config_changes) {
+  foreach (array('new', 'changed', 'deleted') as $type) {
+    foreach ($config_changes[$type] as $name) {
+      if ($type == 'deleted') {
+        config($name)->delete();
+      }
+      else {
+        // Get the active store object, set the new data from file, then save.
+        $target_config = config($name);
+        $source_config = config($name, 'Drupal\Core\Config\FileStorage');
+        $target_config->setData($source_config->get());
+        $target_config->save();
+      }
+    }
+  }
+}
+
+/**
+ * Invokes hook_config_sync_validate() and hook_config_sync() implementations.
+ *
+ * @param $config_changes
+ *   An array of changes to be loaded.
+ */
+function config_sync_invoke_sync_hooks($config_changes) {
+  // Keep a copy of the changes so that a module can't modify the values by
+  // taking the array by reference.
+  $config_changes_copy = $config_changes;
+
+  // @todo Lock writes to ALL config storages to prevent other/unintended config
+  //   changes from happening during the import.
+
+  $target_storage = config(NULL, 'Drupal\Core\Config\DatabaseStorage');
+  $source_storage = config(NULL, 'Drupal\Core\Config\FileStorage');
+
+  foreach (config_sync_sort_dependencies(module_implements('config_sync_validate')) as $module) {
+    $config_changes = $config_changes_copy;
+    $function = $module . '_config_sync_validate';
+    $function($config_changes, $target_storage, $source_storage);
+  }
+
+  // We allow modules to signal that they would like to be rerun after all
+  // other modules by returning CONFIG_DEFER_SYNC. Loop until there are no
+  // modules left that indicate they would like to be rerun, checking that we're
+  // not stuck rerunning the same list of modules over and over at each cycle.
+  $modules = config_sync_sort_dependencies(module_implements('config_sync'));
+  do {
+    // Prevent an infinite loop. If the two variables stay the same, then all
+    // remaining modules asked to defer their import operations, which means
+    // that there is a unmet dependency.
+    $initial_module_list = $modules;
+
+    foreach ($modules as $key => $module) {
+      $config_changes = $config_changes_copy;
+      $function = $module . '_config_sync';
+      if ($function($config_changes, $target_storage, $source_storage) !== CONFIG_DEFER_SYNC) {
+        unset($modules[$key]);
+      }
+    }
+  } while ($modules && $modules != $initial_module_list);
+
+  // If there are modules left that haven't run their sync hook, then we hit
+  // an infinite loop.
+  if ($modules) {
+    throw new ConfigException("Dependency loop detected while sync configuration from disk.");
+  }
+}
+
+/**
+ * Invokes hook_config_sync_error() implementations.
+ *
+ * During a sync run, modules may make changes that cannot be rolled back.
+ * This hook allows modules to react to an error that occurs after they have
+ * made such changes, and make sure that the state of configuration in the
+ * active store is correct.
+ *
+ * @param $config_changes
+ *   An array of changes to be loaded.
+ */
+function config_sync_invoke_sync_error_hooks($config_changes) {
+  $target_storage = config(NULL, 'Drupal\Core\Config\DatabaseStorage');
+  $source_storage = config(NULL, 'Drupal\Core\Config\FileStorage');
+
+  $modules = config_sync_sort_dependencies(module_implements('config_sync_error'));
+  foreach ($modules as $module) {
+    $function = $module . '_config_sync_error';
+    try {
+      $function($config_changes, $target_storage, $source_storage);
+    }
+    catch (ConfigException $e) {
+      // Just keep going, because we need to allow all modules to react even if
+      // some of them are behaving badly.
+    }
+  }
+}
+
+/**
+ * Sort the given list of modules based on dependency.
+ *
+ * @param $modules
+ *   A list of modules.
+ * @return
+ *   The list of modules sorted by dependency.
+ */
+function config_sync_sort_dependencies($modules) {
+  // Get all module data so we can find find weights and sort.
+  $module_data = system_rebuild_module_data();
+
+  $sorted_modules = array();
+  foreach ($modules as $module) {
+    $sorted_modules[$module] = $module_data[$module]->sort;
+  }
+  arsort($sorted_modules);
+  return array_keys($sorted_modules);
+}
+
+/**
+ * Returns a list of changes on disk compared to the active store.
+ *
+ * @return
+ *   The list of files changed on disk compared to the active store.
+ */
+function config_get_changes_from_disk() {
+  $disk_config_names = FileStorage::getNamesWithPrefix();
+  $active_config_names = DatabaseStorage::getNamesWithPrefix();
+  $config_changes = array(
+    'new' => array_diff($disk_config_names, $active_config_names),
+    'changed' => array(),
+    'deleted' => array_diff($active_config_names, $disk_config_names),
+  );
+  foreach (array_intersect($disk_config_names, $active_config_names) as $name) {
+    $active_config = config($name);
+    $file_config = config($name, 'Drupal\Core\Config\FileStorage');
+    if ($active_config->get() != $file_config->get()) {
+      $config_changes['changed'][] = $name;
+    }
+  }
+  if (empty($config_changes['new']) && empty($config_changes['changed']) && empty($config_changes['deleted'])) {
+    return FALSE;
+  }
+  return $config_changes;
+}
+
diff --git a/core/includes/module.inc b/core/includes/module.inc
index 6b4604a..007a068 100644
--- a/core/includes/module.inc
+++ b/core/includes/module.inc
@@ -484,7 +484,7 @@ function module_enable($module_list, $enable_dependencies = TRUE) {
         $versions = drupal_get_schema_versions($module);
         $version = $versions ? max($versions) : SCHEMA_INSTALLED;
 
-        // Copy any default configuration data to the system config directory/
+        // Copy any default configuration data to the active store.
         config_install_default_config($module);
 
         // If the module has no current updates, but has some that were
diff --git a/core/lib/Drupal/Core/Config/DatabaseStorage.php b/core/lib/Drupal/Core/Config/DatabaseStorage.php
index 63ae7b4..31d2c8d 100644
--- a/core/lib/Drupal/Core/Config/DatabaseStorage.php
+++ b/core/lib/Drupal/Core/Config/DatabaseStorage.php
@@ -11,7 +11,7 @@ use Exception;
 class DatabaseStorage extends StorageBase {
 
   /**
-   * Overrides StorageBase::read().
+   * Implements StorageInterface::read().
    */
   public function read() {
     // There are situations, like in the installer, where we may attempt a
diff --git a/core/lib/Drupal/Core/Config/DrupalConfig.php b/core/lib/Drupal/Core/Config/DrupalConfig.php
index c405757..59cfc00 100644
--- a/core/lib/Drupal/Core/Config/DrupalConfig.php
+++ b/core/lib/Drupal/Core/Config/DrupalConfig.php
@@ -17,6 +17,18 @@ class DrupalConfig {
    */
   protected $storage;
 
+  /**
+   * The name of the current configuration object.
+   *
+   * @var string
+   */
+  protected $name;
+
+  /**
+   * The data of the configuration object.
+   *
+   * @var array
+   */
   protected $data = array();
 
   /**
@@ -29,7 +41,24 @@ class DrupalConfig {
    */
   public function __construct(StorageInterface $storage) {
     $this->storage = $storage;
+    // Retrieve the configuration object name assigned to the storage
+    // controller and automatically load it, if any.
+    $this->name = $this->storage->getName();
+    if (isset($this->name)) {
+      $this->read();
+    }
+  }
+
+  /**
+   * Loads a configuration object.
+   *
+   * @param string $name
+   *   The configuration object name to load.
+   */
+  public function load($name) {
+    $this->storage->setName($name);
     $this->read();
+    return $this;
   }
 
   /**
@@ -113,6 +142,11 @@ class DrupalConfig {
     }
   }
 
+  public function setData(array $data) {
+    $this->data = $data;
+    return $this;
+  }
+
   /**
    * Sets value in this config object.
    *
@@ -195,6 +229,7 @@ class DrupalConfig {
     else {
       drupal_array_unset_nested_value($this->data, $parts);
     }
+    return $this;
   }
 
   /**
@@ -202,6 +237,7 @@ class DrupalConfig {
    */
   public function save() {
     $this->storage->write(config_encode($this->data));
+    return $this;
   }
 
   /**
@@ -210,5 +246,6 @@ class DrupalConfig {
   public function delete() {
     $this->data = array();
     $this->storage->delete();
+    return $this;
   }
 }
diff --git a/core/lib/Drupal/Core/Config/FileStorage.php b/core/lib/Drupal/Core/Config/FileStorage.php
index e65e168..ab012a9 100644
--- a/core/lib/Drupal/Core/Config/FileStorage.php
+++ b/core/lib/Drupal/Core/Config/FileStorage.php
@@ -2,13 +2,12 @@
 
 namespace Drupal\Core\Config;
 
+use Drupal\Core\Config\StorageInterface;
+
 /**
- * Represents the file storage interface.
- *
- * Classes implementing this interface allow reading and writing configuration
- * data to and from disk.
+ * Represents the file storage controller.
  */
-class FileStorage {
+class FileStorage implements StorageInterface {
 
   /**
    * Constructs a FileStorage object.
@@ -16,81 +15,125 @@ class FileStorage {
    * @param string $name
    *   The name for the configuration data. Should be lowercase.
    */
-  public function __construct($name) {
+  public function __construct($name = NULL) {
     $this->name = $name;
   }
 
   /**
-   * Reads and returns a file.
-   *
-   * @return
-   *   The data of the file.
-   *
-   * @throws
-   *   Exception
-   */
-  protected function readData() {
-    $data = file_get_contents($this->getFilePath());
-    if ($data === FALSE) {
-      throw new FileStorageReadException('Read file is invalid.');
-    }
-    return $data;
-  }
-
-  /**
-   * Checks whether the XML configuration file already exists on disk.
+   * Returns whether the configuration file exists.
    *
-   * @return
-   *   @todo
+   * @return bool
+   *   TRUE if the configuration file exists, FALSE otherwise.
    */
   protected function exists() {
     return file_exists($this->getFilePath());
   }
 
   /**
-   * Returns the path to the XML configuration file.
+   * Returns the path to the configuration file.
    *
-   * @return
-   *   @todo
+   * @return string
+   *   The path to the configuration file.
    */
   public function getFilePath() {
+    // @todo Cache this?
     return config_get_config_directory() . '/' . $this->name  . '.xml';
   }
 
   /**
-   * Writes the contents of the configuration file to disk.
-   *
-   * @param $data
-   *   The data to be written to the file.
+   * Implements StorageInterface::read().
    *
-   * @throws
-   *   Exception
+   * @throws FileStorageReadException
    */
-  public function write($data) {
-    if (!file_put_contents($this->getFilePath(), $data)) {
-      throw new FileStorageException('Failed to write configuration file: ' . $this->getFilePath());
+  public function read() {
+    if ($this->exists()) {
+      $data = file_get_contents($this->getFilePath());
+      if ($data === FALSE) {
+        throw new FileStorageReadException('Failed to read configuration file: ' . $this->getFilePath());
+      }
+      return $data;
     }
+    return FALSE;
   }
 
   /**
-   * Returns the contents of the configuration file.
+   * Implements StorageInterface::write().
    *
-   * @return
-   *   @todo
+   * @throws FileStorageException
    */
-  public function read() {
-    if ($this->exists()) {
-      $data = $this->readData();
-      return $data;
+  public function write($data) {
+    if (!file_put_contents($this->getFilePath(), $data)) {
+      throw new FileStorageException('Failed to write configuration file: ' . $this->getFilePath());
     }
-    return FALSE;
   }
 
   /**
    * Deletes a configuration file.
    */
   public function delete() {
-    // Needs error handling and etc.
-    @drupal_unlink($this->getFilePath());
+    // @todo Error handling.
+    return @drupal_unlink($this->getFilePath());
+  }
+
+  /**
+   * Implements StorageInterface::copyToFile().
+   */
+  public function copyToFile() {
+    // @todo Untangle StorageInterface.
+  }
+
+  /**
+   * Implements StorageInterface::copyFromFile().
+   */
+  public function copyFromFile() {
+    // @todo Untangle StorageInterface.
+  }
+
+  /**
+   * Implements StorageInterface::deleteFile().
+   */
+  public function deleteFile() {
+    // @todo Untangle StorageInterface.
+    return $this->delete();
+  }
+
+  /**
+   * Implements StorageInterface::writeToActive().
+   */
+  public function writeToActive($data) {
+    // @todo Untangle StorageInterface.
+  }
+
+  /**
+   * Implements StorageInterface::writeToFile().
+   */
+  public function writeToFile($data) {
+    // @todo Untangle StorageInterface.
+    return $this->write($data);
+  }
+
+  /**
+   * Implements StorageInterface::getName().
+   */
+  public function getName() {
+    return $this->name;
+  }
+
+  /**
+   * Implements StorageInterface::setName().
+   */
+  public function setName($name) {
+    $this->name = $name;
+  }
+
+  /**
+   * Implements StorageInterface::getNamesWithPrefix().
+   */
+  public static function getNamesWithPrefix($prefix = '') {
+    $files = glob(config_get_config_directory() . '/' . $prefix . '*.xml');
+    $clean_name = function ($value) {
+      return basename($value, '.xml');
+    };
+    return array_map($clean_name, $files);
   }
 }
diff --git a/core/lib/Drupal/Core/Config/StorageBase.php b/core/lib/Drupal/Core/Config/StorageBase.php
index 7846aed..f521332 100644
--- a/core/lib/Drupal/Core/Config/StorageBase.php
+++ b/core/lib/Drupal/Core/Config/StorageBase.php
@@ -6,10 +6,15 @@ use Drupal\Core\Config\StorageInterface;
 use Drupal\Core\Config\FileStorage;
 
 /**
- * @todo
+ * Base class for configuration storage controllers.
  */
 abstract class StorageBase implements StorageInterface {
 
+  /**
+   * The name of the configuration object.
+   *
+   * @var string
+   */
   protected $name;
 
   /**
@@ -22,7 +27,7 @@ abstract class StorageBase implements StorageInterface {
   /**
    * Implements StorageInterface::__construct().
    */
-  function __construct($name) {
+  function __construct($name = NULL) {
     $this->name = $name;
   }
 
@@ -71,13 +76,6 @@ abstract class StorageBase implements StorageInterface {
   }
 
   /**
-   * Implements StorageInterface::isOutOfSync().
-   */
-  public function isOutOfSync() {
-    return $this->read() !== $this->readFromFile();
-  }
-
-  /**
    * Implements StorageInterface::write().
    */
   public function write($data) {
@@ -106,4 +104,11 @@ abstract class StorageBase implements StorageInterface {
   public function getName() {
     return $this->name;
   }
+
+  /**
+   * Implements StorageInterface::setName().
+   */
+  public function setName($name) {
+    $this->name = $name;
+  }
 }
diff --git a/core/lib/Drupal/Core/Config/StorageInterface.php b/core/lib/Drupal/Core/Config/StorageInterface.php
index f1e8a3d..0d287dd 100644
--- a/core/lib/Drupal/Core/Config/StorageInterface.php
+++ b/core/lib/Drupal/Core/Config/StorageInterface.php
@@ -5,18 +5,20 @@ namespace Drupal\Core\Config;
 /**
  * Defines an interface for configuration storage manipulation.
  *
- * This class allows reading and writing configuration data from/to the
- * storage and copying to/from the file storing the same data.
+ * Classes implementing this interface allow reading and writing configuration
+ * data from and to the storage.
+ *
+ * @todo Remove all active/file methods. They belong onto DrupalConfig only.
  */
 interface StorageInterface {
 
   /**
    * Constructs a storage manipulation class.
    *
-   * @param $name
-   *   Lowercase string, the name for the configuration data.
+   * @param string $name
+   *   (optional) The name for the configuration object to read.
    */
-  function __construct($name);
+  function __construct($name = NULL);
 
   /**
    * Reads the configuration data from the storage.
@@ -39,15 +41,6 @@ interface StorageInterface {
   function deleteFile();
 
   /**
-   * Checks whether the file and the storage is in sync.
-   *
-   * @return
-   *   TRUE if the file and the storage contains the same data, FALSE
-   *   if not.
-   */
-  function isOutOfSync();
-
-  /**
    * Writes the configuration data into the active storage and the file.
    *
    * @param $data
@@ -75,15 +68,31 @@ interface StorageInterface {
   function writeToFile($data);
 
   /**
-   * Gets names starting with this prefix.
-   *
-   * @param $prefix
-   *   @todo
+   * Gets the name of this object.
    */
-  static function getNamesWithPrefix($prefix);
+  public function getName();
 
   /**
-   * Gets the name of this object.
+   * Sets the name of this object.
    */
-  public function getName();
+  public function setName($name);
+
+  /**
+   * Gets configuration object names starting with a given prefix.
+   *
+   * Given the following configuration objects:
+   * - node.type.article
+   * - node.type.page
+   *
+   * Passing the prefix 'node.type' will return an array containing the above
+   * names.
+   *
+   * @param string $prefix
+   *   (optional) The prefix to search for. If omitted, all configuration object
+   *   names that exist are returned.
+   *
+   * @return array
+   *   An array containing matching configuration object names.
+   */
+  static function getNamesWithPrefix($prefix = '');
 }
diff --git a/core/modules/config/config.admin.inc b/core/modules/config/config.admin.inc
new file mode 100644
index 0000000..1169bc0
--- /dev/null
+++ b/core/modules/config/config.admin.inc
@@ -0,0 +1,58 @@
+<?php
+
+/**
+ * @file
+ * Admin page callbacks for the config module.
+ */
+
+/**
+ * Form constructor for configuration import form.
+ *
+ * @see config_admin_import_form_submit()
+ */
+function config_admin_import_form($form, &$form_state) {
+  $config_changes = config_get_changes_from_disk();
+
+  if (empty($config_changes)) {
+    $form['no_changes'] = array(
+      '#markup' => 'There are no changes on disk to reload.'
+    );
+    return $form;
+  }
+
+  foreach ($config_changes as $config_change_type => $config_files) {
+    if (empty($config_files)) {
+      continue;
+    }
+    $form[$config_change_type] = array(
+      '#type' => 'fieldset',
+      '#title' => $config_change_type . ' (' . count($config_files) . ')',
+      '#collapsible' => TRUE,
+    );
+    $form[$config_change_type]['config_files'] = array(
+      '#theme' => 'table',
+      '#header' => array('Name'),
+    );
+    foreach ($config_files as $config_file) {
+      $form[$config_change_type]['config_files']['#rows'][] = array($config_file);
+    }
+  }
+  $form['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Import'),
+  );
+  return $form;
+}
+
+/**
+ * Form submission handler for config_admin_import_form().
+ */
+function config_admin_import_form_submit($form, &$form_state) {
+  if (config_sync()) {
+    drupal_set_message('Configuration successfully reloaded from disk.');
+  }
+  else {
+    drupal_set_message('There was an error reloading configuration from disk.', 'error');
+  }
+}
+
diff --git a/core/modules/config/config.api.php b/core/modules/config/config.api.php
new file mode 100644
index 0000000..8564502
--- /dev/null
+++ b/core/modules/config/config.api.php
@@ -0,0 +1,35 @@
+<?php
+
+/**
+ * @file
+ * Hooks provided by the Config module.
+ */
+
+/**
+ * @defgroup config_hooks Configuration system hooks
+ * @{
+ * TODO: overall description of the configuration system.
+ * @}
+ */
+
+/**
+ * Reload config changes from disk.
+ */
+function hook_config_sync($config_changes, $target_storage, $source_storage) {
+  // TODO: working example.
+}
+
+/**
+ * Validate configuration changes before they are saved to the active store.
+ */
+function hook_config_sync_validate($config_changes, $target_storage, $source_storage) {
+  // TODO: working example.
+}
+
+/**
+ * Validate configuration changes before they are saved to the active store.
+ */
+function hook_config_sync_error($config_changes, $target_storage, $source_storage) {
+  // TODO: working example.
+}
+
diff --git a/core/modules/config/config.module b/core/modules/config/config.module
index b3d9bbc..56c3bb8 100644
--- a/core/modules/config/config.module
+++ b/core/modules/config/config.module
@@ -1 +1,34 @@
 <?php
+
+/**
+ * @file
+ * Configuration system that lets administrators modify
+ * configuration of the site.
+ */
+
+/**
+ * Implements hook_permission().
+ */
+function config_permission() {
+  $permissions['import configuration'] = array(
+    'title' => t('Import configuration'),
+    'restrict access' => TRUE,
+  );
+  return $permissions;
+}
+
+/**
+ * Implements hook_menu().
+ */
+function config_menu() {
+  $items['admin/config/development/import'] = array(
+    'title' => 'Import configuration',
+    'description' => 'Import and synchronize configuration changes.',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('config_admin_import_form'),
+    'access arguments' => array('import configuration'),
+    'file' => 'config.admin.inc',
+  );
+  return $items;
+}
+
diff --git a/core/modules/config/config.test b/core/modules/config/config.test
index f69dde9..f11d374 100644
--- a/core/modules/config/config.test
+++ b/core/modules/config/config.test
@@ -198,22 +198,22 @@ class ConfigFileContentTestCase extends WebTestBase {
 
     // Get file listing for all files starting with 'foo'. Should return
     // two elements.
-    $files = config_get_files_with_prefix('foo');
+    $files = FileStorage::getNamesWithPrefix('foo');
     $this->assertEqual(count($files), 2, 'Two files listed with the prefix \'foo\'.');
 
     // Get file listing for all files starting with 'biff'. Should return
     // one element.
-    $files = config_get_files_with_prefix('biff');
+    $files = FileStorage::getNamesWithPrefix('biff');
     $this->assertEqual(count($files), 1, 'One file listed with the prefix \'biff\'.');
 
     // Get file listing for all files starting with 'foo.bar'. Should return
     // one element.
-    $files = config_get_files_with_prefix('foo.bar');
+    $files = FileStorage::getNamesWithPrefix('foo.bar');
     $this->assertEqual(count($files), 1, 'One file listed with the prefix \'foo.bar\'.');
 
     // Get file listing for all files starting with 'bar'. Should return
     // an empty array.
-    $files = config_get_files_with_prefix('bar');
+    $files = FileStorage::getNamesWithPrefix('bar');
     $this->assertEqual($files, array(), 'No files listed with the prefix \'bar\'.');
 
     // Delete the configuration.
@@ -229,6 +229,126 @@ class ConfigFileContentTestCase extends WebTestBase {
   }
 }
 
+/**
+ * Tests config_sync() functionality.
+ */
+class ConfigReloadTestCase extends WebTestBase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Import configuration',
+      'description' => 'Tests importing configuration from files into active store.',
+      'group' => 'Configuration',
+    );
+  }
+
+  public function setUp() {
+    parent::setUp('config_test');
+  }
+
+  public function testDeletedConfigFile() {
+    // Check a value in the active store for config_test.
+    $config = config('config_test.system');
+    $this->assertTrue($config->get('foo') == 'bar', 'The config_test.system.xml file has been loaded into the active store.');
+    // Delete one of the config_test files.
+    $config_file_path = config_get_config_directory() . '/config_test.system.xml';
+    unlink($config_file_path);
+    // Run config_sync().
+    config_sync();
+    // Check that the value has disappeared.
+    $config = config('config_test.system');
+    $this->assertTrue($config->get('foo') === NULL, 'The config_test.system.xml file values has been removed from the active store.');
+  }
+
+  public function testNewConfigFile() {
+    // Create a new file.
+    $xml =<<<XML
+<?xml version="1.0"?>
+<config>
+  <add_me>new value</add_me>
+</config>
+XML;
+    $new_config_file_path = config_get_config_directory() . '/config_test.new.xml';
+    file_put_contents($new_config_file_path, $xml);
+    // Run config_sync().
+    config_sync();
+    // Check that the value has appeared.
+    $config = config('config_test.new');
+    $this->assertTrue($config->get('add_me') == 'new value', 'A new config file was loaded into the active store by config_sync().');
+  }
+
+  public function testUpdatedConfigFile() {
+    // Update a config_test config file in-place, check that the value does not
+    // appear in the active store.
+    $xml =<<<XML
+<?xml version="1.0"?>
+<config>
+  <foo>not bar</foo>
+</config>
+XML;
+    $config_file_path = config_get_config_directory() . '/config_test.system.xml';
+    file_put_contents($config_file_path, $xml);
+    $config = config('config_test.system');
+    $this->assertTrue($config->get('foo') == 'bar', 'The config_test.system:foo value has not changed.');
+    // Run config_sync().
+    config_sync();
+    // Check that the updated value has appeared.
+    $config = config('config_test.system');
+    $this->assertTrue($config->get('foo') == 'not bar', 'The config_test.system:foo value has been updated by the config_sync() run.');
+  }
+
+  public function testReloadHook() {
+    // Delete a file so that hook_config_sync() hooks are run.
+    $config_file_path = config_get_config_directory() . '/config_test.system.xml';
+    unlink($config_file_path);
+    // Run config_sync().
+    config_sync();
+    // Check that we get called when config_sync() is run.
+    $config_sync_hook_called = isset($GLOBALS['hook_config_sync']) && $GLOBALS['hook_config_sync'] == 'config_test_config_sync';
+    $this->assertTrue($config_sync_hook_called, "The config_test module's hook_config_sync() implementation was called.");
+  }
+
+  public function testReloadErrorHook() {
+    // Delete a file so that hook_config_sync() hooks are run.
+    $config_file_path = config_get_config_directory() . '/config_test.system.xml';
+    unlink($config_file_path);
+    // Enable the module that will blow up during a config_sync() or set a
+    // global or something.
+    $GLOBALS['config_sync_throw_error'] = TRUE;
+    // Run config_sync().
+    config_sync();
+    // Check that we get called when config_sync() is run and the explosion
+    // happens.
+    $config_sync_error_hook_called = isset($GLOBALS['hook_config_sync_error']) && $GLOBALS['hook_config_sync_error'] == 'config_test_config_sync_error';
+    $this->assertTrue($config_sync_error_hook_called, "The config_test module's hook_config_sync_error() implementation was called.");
+  }
+
+  public function testReloadValidateHook() {
+    // Delete a file so that hook_config_sync() hooks are run.
+    $config_file_path = config_get_config_directory() . '/config_test.system.xml';
+    unlink($config_file_path);
+    // Run config_sync().
+    config_sync();
+    // Check that we get called when config_sync() is run.
+    $config_sync_validate_hook_called = isset($GLOBALS['hook_config_sync_validate']) && $GLOBALS['hook_config_sync_validate'] == 'config_test_config_sync_validate';
+    $this->assertTrue($config_sync_validate_hook_called, "The config_test module's hook_config_sync_validate() implementation was called.");
+  }
+
+  public function testReloadValidateHookThrowsError() {
+    // Delete a file so that hook_config_sync() hooks are run.
+    $config_file_path = config_get_config_directory() . '/config_test.system.xml';
+    unlink($config_file_path);
+    // Enable the module that will blow up during a hook_config_sync_validate() or set a
+    // global or something.
+    $GLOBALS['config_sync_validate_throw_error'] = TRUE;
+    // Run config_sync().
+    config_sync();
+    // Check that the config reload run didn't update the active store.
+    $config = config('config_test.system');
+    $this->assertTrue($config->get('foo') == 'bar', 'The config_test.system:foo value has not changed.');
+  }
+}
+
   /**
    * Tests configuration overriding from settings.php.
    */
diff --git a/core/modules/config/config_test/config/config_test.delete.xml b/core/modules/config/config_test/config/config_test.delete.xml
new file mode 100644
index 0000000..4ec808f
--- /dev/null
+++ b/core/modules/config/config_test/config/config_test.delete.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0"?>
+<config>
+  <delete_me>bar</delete_me>
+</config>
diff --git a/core/modules/config/config_test/config/config_test.system.xml b/core/modules/config/config_test/config/config_test.system.xml
new file mode 100644
index 0000000..6ea745f
--- /dev/null
+++ b/core/modules/config/config_test/config/config_test.system.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0"?>
+<config>
+  <foo>bar</foo>
+</config>
diff --git a/core/modules/config/config_test/config_test.info b/core/modules/config/config_test/config_test.info
new file mode 100644
index 0000000..8735450
--- /dev/null
+++ b/core/modules/config/config_test/config_test.info
@@ -0,0 +1,6 @@
+name = Configuration test module
+package = Core
+version = VERSION
+core = 8.x
+dependencies[] = config
+hidden = TRUE
diff --git a/core/modules/config/config_test/config_test.module b/core/modules/config/config_test/config_test.module
new file mode 100644
index 0000000..cfe337a
--- /dev/null
+++ b/core/modules/config/config_test/config_test.module
@@ -0,0 +1,36 @@
+<?php
+
+use Drupal\Core\Config\ConfigException;
+
+/**
+ * Implements hook_config_sync_validate().
+ */
+function config_test_config_sync_validate($config_changes, $target_storage, $source_storage) {
+  if (!empty($GLOBALS['config_sync_validate_throw_error'])) {
+    throw new ConfigException("ZOMG these changes look wrong.");
+  }
+
+  // Set a global value we can check in test code.
+  $GLOBALS['hook_config_sync_validate'] = __FUNCTION__;
+}
+
+/**
+ * Implements hook_config_sync().
+ */
+function config_test_config_sync($config_changes, $target_storage, $source_storage) {
+  if (!empty($GLOBALS['config_sync_throw_error'])) {
+    throw new ConfigException("ZOMG I'm really bad at this game.");
+  }
+
+  // Set a global value we can check in test code.
+  $GLOBALS['hook_config_sync'] = __FUNCTION__;
+}
+
+/**
+ * Implements hook_config_sync_error().
+ */
+function config_test_config_sync_error($config_changes, $target_storage, $source_storage) {
+  // Set a global value we can check in test code.
+  $GLOBALS['hook_config_sync_error'] = __FUNCTION__;
+}
+
diff --git a/core/modules/image/image.module b/core/modules/image/image.module
index 3edf83c..c159a47 100644
--- a/core/modules/image/image.module
+++ b/core/modules/image/image.module
@@ -495,6 +495,46 @@ function image_path_flush($path) {
 }
 
 /**
+ * Implements hook_config_sync().
+ */
+function image_config_sync($config_changes, $target_storage, $source_storage) {
+  foreach ($config_changes['new'] as $file_name) {
+    if (strpos($file_name, 'image.style.') === 0) {
+      $style = $source_storage->load($file_name)->get();
+      $style['is_new'] = TRUE;
+      module_invoke_all('image_style_save', $style);
+      image_style_flush($style);
+    }
+  }
+  foreach ($config_changes['changed'] as $file_name) {
+    if (strpos($file_name, 'image.style.') === 0) {
+      $style = $source_storage->load($file_name)->get();
+      $style['is_new'] = FALSE;
+      module_invoke_all('image_style_save', $style);
+      image_style_flush($style);
+    }
+  }
+  foreach ($config_changes['deleted'] as $file_name) {
+    if (strpos($file_name, 'image.style.') === 0) {
+      // The style has been deleted, so read the previous configuration from the
+      // old storage.
+      $style = $target_storage->load($file_name)->get();
+      image_style_flush($style);
+
+      // @todo image_style_delete() supports the notion of a "replacement style"
+      //   to be used by other modules instead of the deleted style. Good idea.
+      //   But squeezing that into a "delete" operation is the worst idea ever.
+      //   Regardless of Image module insanity, add a 'replaced' stack to
+      //   config_sync()? And how can that work? If an 'old_ID' key would be a
+      //   standard, wouldn't this belong into 'changed' instead?
+      $style['old_name'] = $style['name'];
+      $style['name'] = '';
+      module_invoke_all('image_style_delete', $style);
+    }
+  }
+}
+
+/**
  * Get an array of all styles and their settings.
  *
  * @return
