diff --git a/core/INSTALL.txt b/core/INSTALL.txt
index 1880473..aa80747 100644
--- a/core/INSTALL.txt
+++ b/core/INSTALL.txt
@@ -148,35 +148,33 @@ INSTALLATION
    b. Missing settings file.
 
       Drupal will try to automatically create a settings.php configuration file,
-      which is normally in the directory sites/default (to avoid problems when
-      upgrading, Drupal is not packaged with this file). If auto-creation fails,
+      which is normally in the root directory. To avoid problems when
+      upgrading, Drupal is not packaged with this file. If auto-creation fails,
       you will need to create this file yourself, using the file
-      sites/default/default.settings.php as a template.
+      core/default.settings.php as a template.
 
       For example, on a Unix/Linux command line, you can make a copy of the
       default.settings.php file with the command:
 
-        cp sites/default/default.settings.php sites/default/settings.php
+        cp core/default.settings.php settings.php
 
       Next, grant write privileges to the file to everyone (including the web
       server) with the command:
 
-        chmod a+w sites/default/settings.php
+        chmod a+w settings.php
 
       Be sure to set the permissions back after the installation is finished!
       Sample command:
 
-        chmod go-w sites/default/settings.php
+        chmod go-w settings.php
 
    c. Write permissions after install.
 
-      The install script will attempt to write-protect the settings.php file and
-      the sites/default directory after saving your configuration. If this
-      fails, you will be notified, and you can do it manually. Sample commands
-      from a Unix/Linux command line:
+      The install script will attempt to write-protect the settings.php file
+      after saving your configuration. If this fails, you will be notified, and
+      you can do it manually. Sample commands from a Unix/Linux command line:
 
-        chmod go-w sites/default/settings.php
-        chmod go-w sites/default
+        chmod go-w settings.php
 
 4. Verify that the site is working.
 
@@ -293,9 +291,9 @@ Drupal can be reinstalled without downloading and extracting the Drupal release.
 
 1. Drop all the tables in your database.
 
-2. Remove everything in sites/default/files.
+2. Remove everything in the files directory.
 
-3. Remove sites/default/settings.php.
+3. Remove settings.php.
 
 4. Follow the Installation Instructions above starting from Step 3 (Run the
    install script).
@@ -328,28 +326,28 @@ MULTISITE CONFIGURATION
 A single Drupal installation can host several Drupal-powered sites, each with
 its own individual configuration.
 
-For this to work you need the file sites/sites.php to exist. Make a copy of
-the example.sites.php file:
+For this to work you need to enable the commented out $sites variable in the
+settings.php in Drupal's root directory, like so:
 
-  $ cp sites/example.sites.php sites/sites.php
+  $sites = array();
 
 Additional site configurations are created in subdirectories within the 'sites'
 directory. Each subdirectory must have a 'settings.php' file, which specifies
 the configuration settings. The easiest way to create additional sites is to
-copy file 'default.settings.php' from the 'sites/default' directory into the
-new site directory with file name 'settings.php' and modify as appropriate.
+copy file 'core/default.settings.php' into the new site directory with file name
+'settings.php' and modify as appropriate.
+
 The new directory name is constructed from the site's URL. The configuration
 for www.example.com could be in 'sites/example.com/settings.php' (note that
 'www.' should be omitted if users can access your site at http://example.com/).
 
-  $ cp sites/default/defaults.settings.php sites/example.com/settings.php
+  $ cp core/default.settings.php sites/example.com/settings.php
 
 Sites do not have to have a different domain. You can also use subdomains and
 subdirectories for Drupal sites. For example, example.com, sub.example.com, and
 sub.example.com/site3 can all be defined as independent Drupal sites. The setup
 for a configuration such as this would look like the following:
 
-  sites/default/settings.php
   sites/example.com/settings.php
   sites/sub.example.com/settings.php
   sites/sub.example.com.site3/settings.php
@@ -364,7 +362,7 @@ first configuration it finds:
   sites/www.sub.example.com/settings.php
   sites/sub.example.com/settings.php
   sites/example.com/settings.php
-  sites/default/settings.php
+  settings.php
 
 If you are installing on a non-standard port, the port number is treated as the
 deepest subdomain. For example: http://www.example.com:8080/ could be loaded
diff --git a/core/UPGRADE.txt b/core/UPGRADE.txt
index 420f6ad..a422639 100644
--- a/core/UPGRADE.txt
+++ b/core/UPGRADE.txt
@@ -61,8 +61,8 @@ following the instructions in the INTRODUCTION section at the top of this file:
    If you made modifications to files like .htaccess or robots.txt, you will
    need to re-apply them from your backup, after the new files are in place.
 
-   Sometimes an update includes changes to default.settings.php (this will be
-   noted in the release notes). If that's the case, follow these steps:
+   Sometimes an update includes changes to core/default.settings.php (this will
+   be noted in the release notes). If that's the case, follow these steps:
 
    - Make a backup copy of your settings.php file, with a different file name.
 
diff --git a/sites/default/default.settings.php b/core/default.settings.php
similarity index 77%
rename from sites/default/default.settings.php
rename to core/default.settings.php
index 017fe8a..b6e9144 100644
--- a/sites/default/default.settings.php
+++ b/core/default.settings.php
@@ -2,7 +2,7 @@
 
 /**
  * @file
- * Drupal site-specific configuration file.
+ * Drupal configuration file.
  *
  * IMPORTANT NOTE:
  * This file may have been set to read-only by the Drupal installation program.
@@ -10,10 +10,9 @@
  * your modifications. Failure to remove write permissions to this file is a
  * security risk.
  *
- * In order to use the selection rules below the multisite aliasing file named
- * sites/sites.php must be present. Its optional settings will be loaded, and
- * the aliases in the array $sites will override the default directory rules
- * below. See sites/example.sites.php for more information about aliases.
+ * The configuration file to be loaded is based upon the rules below. However
+ * if the multisite aliasing is enabled, the aliases in the $sites array will
+ * override the default directory rules below.
  *
  * The configuration directory will be discovered by stripping the website's
  * hostname from left to right and pathname from right to left. The first
@@ -46,15 +45,60 @@
  * hostname with that number. For example,
  * http://www.drupal.org:8080/mysite/test/ could be loaded from
  * sites/8080.www.drupal.org.mysite.test/.
+ */
+
+/**
+ * Multi-site functionality and aliases.
+ *
+ * Uncomment the $sites variable below to enable Drupal's multi-site
+ * functionality, which allows to serve multiple different sites from the same
+ * code-base.
+ *
+ * An empty $sites variable just enables the sites directory discovery process.
+ * You can additionally define aliases that map hostnames, ports, and path names
+ * to specific site directories. These aliases are applied prior to scanning for
+ * directories and exempt from the discovery rules.
+ *
+ * Aliases are useful on development servers, where the domain name may not be
+ * the same as the domain of the live server. Since Drupal stores file paths in
+ * the database (files, system table, etc.) this will ensure the paths are
+ * correct when the site is deployed to a live server.
+ *
+ * Aliases are defined in an associative array named $sites. The array is
+ * written in the format: '<port>.<domain>.<path>' => 'directory'. As an
+ * example, to map http://www.drupal.org:8080/mysite/test to the configuration
+ * directory sites/example.com, the array should be defined as:
+ * @code
+ * $sites = array(
+ *   '8080.www.drupal.org.mysite.test' => 'example.com',
+ * );
+ * @endcode
+ * The URL, http://www.drupal.org:8080/mysite/test/, could be a symbolic link or
+ * an Apache Alias directive that points to the Drupal root containing
+ * index.php. An alias could also be created for a subdomain. See the
+ * @link http://drupal.org/documentation/install online Drupal installation guide @endlink
+ * for more information on setting up domains, subdomains, and subdirectories.
+ *
+ * The following examples look for a site configuration in sites/example.com:
+ * @code
+ * URL: http://dev.drupal.org
+ * $sites['dev.drupal.org'] = 'example.com';
  *
- * @see example.sites.php
- * @see conf_path()
+ * URL: http://localhost/example
+ * $sites['localhost.example'] = 'example.com';
  *
- * In addition to customizing application settings through variables in
- * settings.php, you can create a services.yml file in the same directory to
- * register custom, site-specific service definitions and/or swap out default
- * implementations with custom ones.
+ * URL: http://localhost:8080/example
+ * $sites['8080.localhost.example'] = 'example.com';
+ *
+ * URL: http://www.drupal.org:8080/mysite/test/
+ * $sites['8080.www.drupal.org.mysite.test'] = 'example.com';
+ * @endcode
+ *
+ * @see \Drupal\Core\Site\Site::getPath()
+ * @see http://drupal.org/documentation/install/multi-site
  */
+# $sites = array();
+# $sites['localhost.example'] = 'example.com';
 
 /**
  * Database settings:
@@ -98,23 +142,22 @@
  * For each database, you may optionally specify multiple "target" databases.
  * A target database allows Drupal to try to send certain queries to a
  * different database if it can but fall back to the default connection if not.
- * That is useful for primary/replica replication, as Drupal may try to connect
- * to a replica server when appropriate and if one is not available will simply
- * fall back to the single primary server (The terms primary/replica are
- * traditionally referred to as master/slave in database server documentation).
+ * That is useful for master/slave replication, as Drupal may try to connect
+ * to a slave server when appropriate and if one is not available will simply
+ * fall back to the single master server.
  *
  * The general format for the $databases array is as follows:
  * @code
  * $databases['default']['default'] = $info_array;
- * $databases['default']['replica'][] = $info_array;
- * $databases['default']['replica'][] = $info_array;
+ * $databases['default']['slave'][] = $info_array;
+ * $databases['default']['slave'][] = $info_array;
  * $databases['extra']['default'] = $info_array;
  * @endcode
  *
  * In the above example, $info_array is an array of settings described above.
- * The first line sets a "default" database that has one primary database
+ * The first line sets a "default" database that has one master database
  * (the second level default).  The second and third lines create an array
- * of potential replica databases.  Drupal will select one at random for a given
+ * of potential slave databases.  Drupal will select one at random for a given
  * request as needed.  The fourth line creates a new database with a name of
  * "extra".
  *
@@ -222,18 +265,12 @@
 /**
  * Location of the site configuration files.
  *
- * The $config_directories array specifies the location of file system
- * directories used for configuration data. On install, "active" and "staging"
- * directories are created for configuration. The staging directory is used for
- * configuration imports; the active directory is not used by default, since the
- * default storage for active configuration is the database rather than the file
- * system (this can be changed; see "Active configuration settings" below).
+ * By default, Drupal configuration files are stored in a randomly named
+ * directory under the default public files path. On install the
+ * named directory is created in the default files directory. For enhanced
+ * security, you may set this variable to a location outside your docroot.
  *
- * The default location for the active and staging directories is inside a
- * randomly-named directory in the public files path; this setting allows you to
- * override these locations. If you use files for the active configuration, you
- * can enhance security by putting the active configuration outside your
- * document root.
+ * @todo Flesh this out, provide more details, etc.
  *
  * Example:
  * @code
@@ -252,7 +289,7 @@
  * directory and reverse proxy address, and temporary configuration, such as
  * turning on Twig debugging and security overrides.
  *
- * @see \Drupal\Core\Site\Settings::get()
+ * @see \Drupal\Component\Utility\Settings::get()
  */
 
 /**
@@ -263,9 +300,9 @@
  * site is deployed on a cluster of web servers, you must ensure that this
  * variable has the same value on each server.
  *
- * For enhanced security, you may set this variable to the contents of a file
- * outside your document root; you should also ensure that this file is not
- * stored with backups of your database.
+ * For enhanced security, you may set this variable to a value using the
+ * contents of a file outside your docroot that is never saved together
+ * with any backups of your Drupal files and database.
  *
  * Example:
  * @code
@@ -288,6 +325,59 @@
 $settings['update_free_access'] = FALSE;
 
 /**
+ * Twig debugging:
+ *
+ * When debugging is enabled:
+ * - The markup of each Twig template is surrounded by HTML comments that
+ *   contain theming information, such as template file name suggestions.
+ * - Note that this debugging markup will cause automated tests that directly
+ *   check rendered HTML to fail. When running automated tests, 'twig_debug'
+ *   should be set to FALSE.
+ * - The dump() function can be used in Twig templates to output information
+ *   about template variables.
+ * - Twig templates are automatically recompiled whenever the source code
+ *   changes (see twig_auto_reload below).
+ *
+ * Note: changes to this setting will only take effect once the cache is
+ * cleared.
+ *
+ * For more information about debugging Twig templates, see
+ * http://drupal.org/node/1906392.
+ *
+ * Not recommended in production environments (Default: FALSE).
+ */
+# $settings['twig_debug'] = TRUE;
+
+/**
+ * Twig auto-reload:
+ *
+ * Automatically recompile Twig templates whenever the source code changes. If
+ * you don't provide a value for twig_auto_reload, it will be determined based
+ * on the value of twig_debug.
+ *
+ * Note: changes to this setting will only take effect once the cache is
+ * cleared.
+ *
+ * Not recommended in production environments (Default: NULL).
+ */
+# $settings['twig_auto_reload'] = TRUE;
+
+/**
+ * Twig cache:
+ *
+ * By default, Twig templates will be compiled and stored in the filesystem to
+ * increase performance. Disabling the Twig cache will recompile the templates
+ * from source each time they are used. In most cases the twig_auto_reload
+ * setting above should be enabled rather than disabling the Twig cache.
+ *
+ * Note: changes to this setting will only take effect once the cache is
+ * cleared.
+ *
+ * Not recommended in production environments (Default: TRUE).
+ */
+# $settings['twig_cache'] = FALSE;
+
+/**
  * External access proxy settings:
  *
  * If your site must access the Internet via a web proxy then you can enter
@@ -450,7 +540,7 @@
  * Remove the leading hash signs to enable.
  *
  * The "en" part of the variable name, is dynamic and can be any langcode of
- * any added language. (eg locale_custom_strings_de for german).
+ * any enabled language. (eg locale_custom_strings_de for german).
  */
 # $settings['locale_custom_strings_en'][''] = array(
 #   'forum'      => 'Discussion board',
@@ -470,6 +560,16 @@
 # $settings['maintenance_theme'] = 'bartik';
 
 /**
+ * Enable access to rebuild.php.
+ *
+ * This setting can be enabled to allow Drupal's php and database cached
+ * storage to be cleared via the rebuild.php page. Access to this page can also
+ * be gained by generating a query string from rebuild_token_calculator.sh and
+ * using these parameters in a request to rebuild.php.
+ */
+# $settings['rebuild_access'] = TRUE;
+
+/**
  * Base URL (optional).
  *
  * If Drupal is generating incorrect URLs on your site, which could
@@ -497,8 +597,8 @@
  * To see what PHP settings are possible, including whether they can be set at
  * runtime (by using ini_set()), read the PHP documentation:
  * http://php.net/manual/ini.list.php
- * See \Drupal\Core\DrupalKernel::bootEnvironment() for required runtime
- * settings and the .htaccess file for non-runtime settings.
+ * See drupal_environment_initialize() in core/includes/bootstrap.inc for
+ * required runtime settings and the .htaccess file for non-runtime settings.
  * Settings defined there should not be duplicated here so as to avoid conflict
  * issues.
  */
@@ -553,16 +653,14 @@
  * Active configuration settings.
  *
  * By default, the active configuration is stored in the database in the
- * {config} table. To use a different storage mechanism for the active
- * configuration, do the following prior to installing:
- * - Override the 'bootstrap_config_storage' setting here. It must be set to a
- *   callable that returns an object that implements
- *   \Drupal\Core\Config\StorageInterface.
- * - Override the service definition 'config.storage.active'. Put this
- *   override in a services.yml file in the same directory as settings.php
- *   (definitions in this file will override service definition defaults).
+ * {config} table. To install Drupal with a different active configuration
+ * storage, you need to override the setting here, in addition to overriding
+ * the config.storage.active service definition in a module or profile.
+ *
+ * The 'bootstrap_config_storage' setting needs to be a callable that returns
+ * core.services.yml.
  */
-# $settings['bootstrap_config_storage'] = array('Drupal\Core\Config\BootstrapConfigStorageFactory', 'getFileStorage');
+ # $settings['bootstrap_config_storage'] = array('Drupal\Core\Config\BootstrapConfigStorageFactory', 'getFileStorage');
 
 /**
  * Configuration overrides.
@@ -625,11 +723,9 @@
  *
  * Use settings.local.php to override variables on secondary (staging,
  * development, etc) installations of this site. Typically used to disable
- * caching, JavaScript/CSS compression, re-routing of outgoing emails, and
+ * caching, JavaScript/CSS compression, re-routing of outgoing e-mails, and
  * other things that should not happen on development and testing sites.
  *
- * Keep this code block at the end of this file to take full effect.
+ * Keep this include at the end of this file to take full effect.
  */
-# if (file_exists(__DIR__ . '/settings.local.php')) {
-#   include __DIR__ . '/settings.local.php';
-# }
+# include __DIR__ . '/settings.local.php';
diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index 27494e7..2389f0f 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -13,6 +13,7 @@
 use Drupal\Core\DrupalKernel;
 use Drupal\Core\Extension\ExtensionDiscovery;
 use Drupal\Core\Site\Settings;
+use Drupal\Core\Site\Site;
 use Drupal\Core\Utility\Error;
 use Symfony\Component\ClassLoader\ApcClassLoader;
 use Symfony\Component\HttpFoundation\Request;
@@ -209,43 +210,22 @@
 /**
  * Returns the appropriate configuration directory.
  *
- * @param bool $require_settings
- *   Only configuration directories with an existing settings.php file
- *   will be recognized. Defaults to TRUE. During initial installation,
- *   this is set to FALSE so that Drupal can detect a matching directory,
- *   then create a new settings.php file in it.
- * @param bool $reset
- *   Force a full search for matching directories even if one had been
- *   found previously. Defaults to FALSE.
- * @param \Symfony\Component\HttpFoundation\Request $request
- *   (optional) The current request. Defaults to \Drupal::request() or a new
- *   request created from globals.
+ * Temporary backwards-compatibility layer for Drush.
  *
- * @return string
- *   The path of the matching directory.@see default.settings.php
+ * @deprecated 8.x-dev
+ *   Use \Drupal\Core\Site\Site::getPath() instead.
  *
- * @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
- *   Use \Drupal\Core\DrupalKernel::getSitePath() instead. If the kernel is
- *   unavailable or the site path needs to be recalculated then
- *   Drupal\Core\DrupalKernel::findSitePath() can be used.
- */
-function conf_path($require_settings = TRUE, $reset = FALSE, Request $request = NULL) {
-  if (!isset($request)) {
-    if (\Drupal::hasRequest()) {
-      $request = \Drupal::request();
-    }
-    // @todo Remove once external CLI scripts (Drush) are updated.
-    else {
-      $request = Request::createFromGlobals();
-    }
-  }
-  if (\Drupal::hasService('kernel')) {
-    $site_path = \Drupal::service('kernel')->getSitePath();
-  }
-  if (!isset($site_path) || empty($site_path)) {
-    $site_path = DrupalKernel::findSitePath($request, $require_settings);
+ * @internal
+ */
+function conf_path() {
+  if (strpos(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS)[1]['function'], 'drush') === FALSE) {
+    throw new \Exception('conf_path() is retained for Drush compatibility only.');
   }
-  return $site_path;
+  // When called from _drush_bootstrap_drupal_site_validate() on testbots, this
+  // function is supposed to return the site path of the parent site, which is
+  // '' (the document root). Ensure that the returned path is relative.
+  // @see https://github.com/drush-ops/drush/blob/master/includes/bootstrap.inc#L782
+  return '.';
 }
 /**
  * Returns the path of a configuration directory.
diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc
index 4cdc529..7ad5948 100644
--- a/core/includes/install.core.inc
+++ b/core/includes/install.core.inc
@@ -16,6 +16,7 @@
 use Drupal\Core\Language\LanguageManager;
 use Drupal\Core\Page\DefaultHtmlPageRenderer;
 use Drupal\Core\Site\Settings;
+use Drupal\Core\Site\Site;
 use Drupal\Core\StringTranslation\Translator\FileTranslation;
 use Drupal\Core\Extension\ExtensionDiscovery;
 use Drupal\Core\DependencyInjection\ContainerBuilder;
@@ -288,6 +289,12 @@ function install_begin_request(&$install_state) {
   $site_path = DrupalKernel::findSitePath($request, FALSE);
   Settings::initialize($site_path);
 
+  // Initialize the site directory.
+  // This primes the site path to be used during installation, to allow an empty
+  // site folder to be prepared in the /sites directory into which Drupal will
+  // be installed.
+  Site::initInstaller(DRUPAL_ROOT);
+
   // Ensure that procedural dependencies are loaded as early as possible,
   // since the error/exception handlers depend on them.
   require_once __DIR__ . '/../modules/system/system.install';
@@ -369,7 +376,7 @@ function install_begin_request(&$install_state) {
     $directory = $GLOBALS['config']['locale.settings']['translation.path'];
   }
   else {
-    $directory = $site_path . '/files/translations';
+    $directory = Site::getPath('files/translations');
   }
   $container->set('string_translator.file_translation', new FileTranslation($directory));
   $container->get('string_translation')
@@ -1007,8 +1014,7 @@ function install_verify_completed_task() {
 function install_verify_database_settings() {
   if ($database = Database::getConnectionInfo()) {
     $database = $database['default'];
-    $settings_file = './' . conf_path(FALSE) . '/settings.php';
-    $errors = install_database_errors($database, $settings_file);
+    $errors = install_database_errors($database);
     if (empty($errors)) {
       return TRUE;
     }
@@ -1019,14 +1025,19 @@ function install_verify_database_settings() {
 /**
  * Checks a database connection and returns any errors.
  */
-function install_database_errors($database, $settings_file) {
+
+function install_database_errors($database) {
   $errors = array();
 
   // Check database type.
   $database_types = drupal_get_database_types();
   $driver = $database['driver'];
   if (!isset($database_types[$driver])) {
-    $errors['driver'] = t("In your %settings_file file you have configured @drupal to use a %driver server, however your PHP installation currently does not support this database type.", array('%settings_file' => $settings_file, '@drupal' => drupal_install_profile_distribution_name(), '%driver' => $driver));
+    $errors['driver'] = t("In your %settings_file file you have configured @drupal to use a %driver server, however your PHP installation currently does not support this database type.", array(
+      '%settings_file' => Site::getPath('settings.php'),
+      '@drupal' => drupal_install_profile_distribution_name(),
+      '%driver' => $driver,
+    ));
   }
   else {
     // Run driver specific validation
@@ -1736,8 +1747,8 @@ function install_check_translations($install_state) {
   $readable = FALSE;
   $writable = FALSE;
   // @todo: Make this configurable.
-  $files_directory = conf_path() . '/files';
-  $translations_directory = conf_path() . '/files/translations';
+  $files_directory = Site::getPath('files');
+  $translations_directory = Site::getPath('files/translations');
   $translations_directory_exists = FALSE;
   $translation_available = FALSE;
   $online = FALSE;
@@ -1890,15 +1901,13 @@ function install_check_requirements($install_state) {
   if (!$install_state['settings_verified']) {
     $readable = FALSE;
     $writable = FALSE;
-    $conf_path = './' . conf_path(FALSE);
-    $settings_file = $conf_path . '/settings.php';
-    $default_settings_file = './sites/default/default.settings.php';
-    $file = $conf_path;
+    $settings_file = Site::getAbsolutePath('settings.php');
+    $default_settings_file = './core/default.settings.php';
+    $file = Site::getPath('settings.php');
     $exists = FALSE;
     // Verify that the directory exists.
-    if (drupal_verify_install_file($conf_path, FILE_EXIST, 'dir')) {
+    if (drupal_verify_install_file(Site::getAbsolutePath(), FILE_EXIST, 'dir')) {
       // Check if a settings.php file already exists.
-      $file = $settings_file;
       if (drupal_verify_install_file($settings_file, FILE_EXIST)) {
         // If it does, make sure it is writable.
         $readable = drupal_verify_install_file($settings_file, FILE_READABLE);
@@ -1907,20 +1916,15 @@ function install_check_requirements($install_state) {
       }
     }
 
-    // If default.settings.php does not exist, or is not readable, throw an
-    // error.
-    if (!drupal_verify_install_file($default_settings_file, FILE_EXIST|FILE_READABLE)) {
-      $requirements['default settings file exists'] = array(
-        'title'       => t('Default settings file'),
-        'value'       => t('The default settings file does not exist.'),
-        'severity'    => REQUIREMENT_ERROR,
-        'description' => t('The @drupal installer requires that the %default-file file not be modified in any way from the original download.', array('@drupal' => drupal_install_profile_distribution_name(), '%default-file' => $default_settings_file)),
-      );
-    }
-    // Otherwise, if settings.php does not exist yet, we can try to copy
-    // default.settings.php to create it.
-    elseif (!$exists) {
-      $copied = drupal_verify_install_file($conf_path, FILE_EXIST|FILE_WRITABLE, 'dir') && @copy($default_settings_file, $settings_file);
+    // If settings.php does not exist yet, try to copy default.settings.php to
+    // create it.
+    if (!$exists) {
+      // Make the site directory writable, unless it is the root directory.
+      $copied = TRUE;
+      if (Site::getPath() !== '') {
+        $copied = drupal_verify_install_file(Site::getAbsolutePath(), FILE_EXIST|FILE_WRITABLE, 'dir');
+      }
+      $copied = $copied && @copy($default_settings_file, $settings_file);
       if ($copied) {
         // If the new settings file has the same owner as default.settings.php,
         // this means default.settings.php is owned by the webserver user.
diff --git a/core/includes/install.inc b/core/includes/install.inc
index d1c1596..9bb949f 100644
--- a/core/includes/install.inc
+++ b/core/includes/install.inc
@@ -11,6 +11,7 @@
 use Drupal\Component\Utility\UrlHelper;
 use Drupal\Core\Extension\ExtensionDiscovery;
 use Drupal\Core\Site\Settings;
+use Drupal\Core\Site\Site;
 
 /**
  * Requirement severity -- Informational message only.
@@ -195,7 +196,7 @@ function drupal_get_database_types() {
  */
 function drupal_rewrite_settings($settings = array(), $settings_file = NULL) {
   if (!isset($settings_file)) {
-    $settings_file = conf_path(FALSE) . '/settings.php';
+    $settings_file = Site::getPath('settings.php');
   }
   // Build list of setting names and insert the values into the global namespace.
   $variable_names = array();
@@ -468,11 +469,11 @@ function drupal_install_config_directories() {
     $config_directories_hash = Crypt::randomBytesBase64(55);
     $settings['config_directories'] = array(
       CONFIG_ACTIVE_DIRECTORY => (object) array(
-        'value' => conf_path() . '/files/config_' . $config_directories_hash . '/active',
+        'value' => Site::getPath('files/config_' . $config_directories_hash . '/active'),
         'required' => TRUE,
       ),
       CONFIG_STAGING_DIRECTORY => (object) array(
-        'value' => conf_path() . '/files/config_' . $config_directories_hash . '/staging',
+        'value' => Site::getPath('files/config_' . $config_directories_hash . '/staging'),
         'required' => TRUE,
       ),
     );
@@ -680,6 +681,9 @@ function drupal_install_system($install_state) {
  *
  * @return
  *   TRUE on success or FALSE on failure. A message is set for the latter.
+ *
+ * @todo Do not automatically call into drupal_install_fix_file().
+ * @see https://drupal.org/node/1616266
  */
 function drupal_verify_install_file($file, $mask = NULL, $type = 'file') {
   $return = TRUE;
diff --git a/core/includes/update.inc b/core/includes/update.inc
index 945ffe7..abe75ee 100644
--- a/core/includes/update.inc
+++ b/core/includes/update.inc
@@ -14,6 +14,7 @@
 use Drupal\Core\Config\ConfigException;
 use Drupal\Core\DrupalKernel;
 use Drupal\Core\Page\DefaultHtmlPageRenderer;
+use Drupal\Core\Site\Site;
 use Drupal\Core\Utility\Error;
 use Drupal\Component\Uuid\Uuid;
 use Drupal\Component\Utility\NestedArray;
@@ -82,7 +83,7 @@ function update_settings_file_requirements() {
   $requirements = array();
 
   // Check whether settings.php needs to be rewritten.
-  $settings_file = conf_path() . '/settings.php';
+  $settings_file = Site::getPath('settings.php');
   $writable = drupal_verify_install_file($settings_file, FILE_EXIST | FILE_READABLE | FILE_WRITABLE);
   $requirements['settings file']['title'] = 'Settings file';
   if ($writable) {
diff --git a/core/lib/Drupal/Core/Database/Driver/sqlite/Install/Tasks.php b/core/lib/Drupal/Core/Database/Driver/sqlite/Install/Tasks.php
index 97eab54..995f0e6 100644
--- a/core/lib/Drupal/Core/Database/Driver/sqlite/Install/Tasks.php
+++ b/core/lib/Drupal/Core/Database/Driver/sqlite/Install/Tasks.php
@@ -11,6 +11,7 @@
 use Drupal\Core\Database\Driver\sqlite\Connection;
 use Drupal\Core\Database\DatabaseNotFoundException;
 use Drupal\Core\Database\Install\Tasks as InstallTasks;
+use Drupal\Core\Site\Site;
 
 /**
  * Specifies installation tasks for SQLite databases.
@@ -49,7 +50,7 @@ public function getFormOptions(array $database) {
     // Make the text more accurate for SQLite.
     $form['database']['#title'] = t('Database file');
     $form['database']['#description'] = t('The absolute path to the file where @drupal data will be stored. This must be writable by the web server and should exist outside of the web root.', array('@drupal' => drupal_install_profile_distribution_name()));
-    $default_database = conf_path(FALSE) . '/files/.ht.sqlite';
+    $default_database = Site::getPath('files/.ht.sqlite');
     $form['database']['#default_value'] = empty($database['database']) ? $default_database : $database['database'];
     return $form;
   }
diff --git a/core/lib/Drupal/Core/Extension/ExtensionDiscovery.php b/core/lib/Drupal/Core/Extension/ExtensionDiscovery.php
index f51cbb3..43b31ca 100644
--- a/core/lib/Drupal/Core/Extension/ExtensionDiscovery.php
+++ b/core/lib/Drupal/Core/Extension/ExtensionDiscovery.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Extension\Discovery\RecursiveExtensionFilterIterator;
 use Drupal\Core\Site\Settings;
+use Drupal\Core\Site\Site;
 
 /**
  * Discovers available extensions in the filesystem.
@@ -135,8 +136,10 @@ public function scan($type, $include_tests = NULL) {
       $searchdirs[static::ORIGIN_PARENT_SITE] = $parent_site;
     }
 
-    // Search the site-specific directory.
-    $searchdirs[static::ORIGIN_SITE] = conf_path();
+    // Search the site-specific directory, unless it is the same as ORIGIN_ROOT.
+    if ('' !== $site_path = Site::getPath()) {
+      $searchdirs[static::ORIGIN_SITE] = $site_path;
+    }
 
     // Unless an explicit value has been passed, manually check whether we are
     // in a test environment, in which case test extensions must be included.
diff --git a/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php b/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php
index c8fdd19..adbcec4 100644
--- a/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php
+++ b/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php
@@ -11,6 +11,7 @@
 use Drupal\Core\Form\FormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Locale\CountryManagerInterface;
+use Drupal\Core\Site\Site;
 use Drupal\Core\State\StateInterface;
 use Drupal\user\UserStorageInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -93,8 +94,6 @@ public function buildForm(array $form, FormStateInterface $form_state) {
     $form['#title'] = $this->t('Configure site');
 
     // Warn about settings.php permissions risk
-    $settings_dir = conf_path();
-    $settings_file = $settings_dir . '/settings.php';
     // Check that $_POST is empty so we only show this message when the form is
     // first displayed, not on the next page after it is submitted. (We do not
     // want to repeat it multiple times because it is a general warning that is
@@ -103,8 +102,12 @@ public function buildForm(array $form, FormStateInterface $form_state) {
     // distract from the message that the Drupal installation has completed
     // successfully.)
     $post_params = $this->getRequest()->request->all();
-    if (empty($post_params) && (!drupal_verify_install_file(DRUPAL_ROOT . '/' . $settings_file, FILE_EXIST|FILE_READABLE|FILE_NOT_WRITABLE) || !drupal_verify_install_file(DRUPAL_ROOT . '/' . $settings_dir, FILE_NOT_WRITABLE, 'dir'))) {
-      drupal_set_message(t('All necessary changes to %dir and %file have been made, so you should remove write permissions to them now in order to avoid security risks. If you are unsure how to do so, consult the <a href="@handbook_url">online handbook</a>.', array('%dir' => $settings_dir, '%file' => $settings_file, '@handbook_url' => 'http://drupal.org/server-permissions')), 'warning');
+    if (empty($post_params) && (!drupal_verify_install_file(Site::getAbsolutePath('settings.php'), FILE_EXIST|FILE_READABLE|FILE_NOT_WRITABLE) || is_writable(Site::getAbsolutePath()))) {
+      drupal_set_message(t('All necessary changes to %dir and %file have been made, so you should remove write permissions to them now in order to avoid security risks. If you are unsure how to do so, consult the <a href="@handbook_url">online handbook</a>.', array(
+        '%dir' => Site::getPath() ?: Site::getAbsolutePath(),
+        '%file' => Site::getPath('settings.php'),
+        '@handbook_url' => 'http://drupal.org/server-permissions',
+      )), 'warning');
     }
 
     $form['#attached']['library'][] = 'system/drupal.system';
diff --git a/core/lib/Drupal/Core/Installer/Form/SiteSettingsForm.php b/core/lib/Drupal/Core/Installer/Form/SiteSettingsForm.php
index 71c25e9..f78d099 100644
--- a/core/lib/Drupal/Core/Installer/Form/SiteSettingsForm.php
+++ b/core/lib/Drupal/Core/Installer/Form/SiteSettingsForm.php
@@ -28,9 +28,6 @@ public function getFormId() {
    * {@inheritdoc}
    */
   public function buildForm(array $form, FormStateInterface $form_state) {
-    $conf_path = './' . conf_path(FALSE);
-    $settings_file = $conf_path . '/settings.php';
-
     $form['#title'] = $this->t('Database configuration');
 
     $drivers = drupal_get_database_types();
@@ -107,7 +104,6 @@ public function buildForm(array $form, FormStateInterface $form_state) {
     );
 
     $form['errors'] = array();
-    $form['settings_file'] = array('#type' => 'value', '#value' => $settings_file);
 
     return $form;
   }
@@ -126,7 +122,7 @@ public function validateForm(array &$form, FormStateInterface $form_state) {
     $database['driver'] = $driver;
 
     $form_state['storage']['database'] = $database;
-    $errors = install_database_errors($database, $form_state->getValue('settings_file'));
+    $errors = install_database_errors($database);
     foreach ($errors as $name => $message) {
       $form_state->setErrorByName($name, $message);
     }
diff --git a/core/lib/Drupal/Core/Site/Settings.php b/core/lib/Drupal/Core/Site/Settings.php
index e2d57d2..79d437c 100644
--- a/core/lib/Drupal/Core/Site/Settings.php
+++ b/core/lib/Drupal/Core/Site/Settings.php
@@ -95,9 +95,24 @@ public static function initialize($site_path) {
     $config = array();
     $databases = array();
 
-    // Make conf_path() available as local variable in settings.php.
-    if (is_readable(DRUPAL_ROOT . '/' . $site_path . '/settings.php')) {
-      require DRUPAL_ROOT . '/' . $site_path . '/settings.php';
+		// Read the global /settings.php file.
+		// Allow it to set/override the following variables:
+		$sites = NULL;
+		$conf_path = NULL;
+		// Exclude it for test requests to prevent settings of the test runner from
+		// leaking into the test environment.
+		if (!drupal_valid_test_ua() && is_readable(DRUPAL_ROOT . '/settings.php')) {
+			require DRUPAL_ROOT . '/settings.php';
+		}
+
+		// Discover the site directory.
+		Site::init(DRUPAL_ROOT, $sites, $conf_path);
+
+		// Read settings.php of the actual site, unless it is the root/default site.
+		// Concatenation is safe here, since $conf_path is known to be not empty.
+		$conf_path = Site::getPath();
+		if ($conf_path !== '' && is_readable(DRUPAL_ROOT . '/' . $conf_path . '/settings.php')) {
+      require DRUPAL_ROOT . '/' . $conf_path . '/settings.php';
     }
 
     // Initialize Database.
diff --git a/core/lib/Drupal/Core/Site/Site.php b/core/lib/Drupal/Core/Site/Site.php
new file mode 100644
index 0000000..916abd9
--- /dev/null
+++ b/core/lib/Drupal/Core/Site/Site.php
@@ -0,0 +1,378 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Site\Site.
+ */
+
+namespace Drupal\Core\Site;
+
+/**
+ * A utility class for easy access to the site path.
+ */
+class Site {
+
+  /**
+   * The absolute path to the Drupal root directory.
+   *
+   * @var string
+   */
+  private $root;
+
+  /**
+   * The relative path to the site directory.
+   *
+   * May be an empty string, in case the site directory is the root directory.
+   *
+   * @var string
+   */
+  private $path;
+
+  /**
+   * Whether the Site singleton was instantiated by the installer.
+   *
+   * @var bool
+   */
+  private $isInstaller = FALSE;
+
+  /**
+   * The original Site instance of the test runner during test execution.
+   *
+   * @see \Drupal\Core\Site\Site::setUpTest()
+   * @see \Drupal\Core\Site\Site::tearDownTest()
+   *
+   * @var \Drupal\Core\Site\Site
+   */
+  private static $original;
+
+  /**
+   * The Site singleton instance.
+   *
+   * @var \Drupal\Core\Site\Site
+   */
+  private static $instance;
+
+  /**
+   * Initializes the Site singleton.
+   *
+   * @param string $root_directory
+   *   The root directory to use for absolute paths; i.e., DRUPAL_ROOT.
+   * @param array|null $sites
+   *   (optional) A multi-site mapping, as defined in settings.php. An empty
+   *   array is sufficient to enable discovery of a request-specific site
+   *   directory. If NULL and no $custom_path is passed, the root directory will
+   *   be the site directory.
+   * @param string|null $custom_path
+   *   (optional) An explicit site path to set; skipping site negotiation.
+   *   This can be defined as $conf_path in the root /settings.php file.
+   *
+   * @throws \BadMethodCallException
+   *   If the site path is initialized already.
+   *
+   * @see drupal_settings_initialize()
+   */
+  public static function init($root_directory, array $sites = NULL, $custom_path = NULL) {
+    if (isset(self::$instance)) {
+      // Only the installer environment is allowed to instantiate the Site
+      // singleton prior to drupal_settings_initialize().
+      // @see Site::initInstaller()
+      if (!self::$instance->isInstaller()) {
+        throw new \BadMethodCallException('Site path is initialized already.');
+      }
+    }
+    else {
+      new self($root_directory);
+    }
+    self::$instance->initializePath($sites, $custom_path);
+
+    // Prevent this method from being called more than once.
+    if (self::$instance->isInstaller()) {
+      self::$instance->isInstaller = FALSE;
+    }
+  }
+
+  /**
+   * Initializes the Site singleton in the early installer environment.
+   *
+   * Primes the Site singleton with an installer flag, which allows the
+   * application to be installed into a new and empty site directory, which does
+   * not contain a settings.php yet.
+   *
+   * @param string $root_directory
+   *   The root directory to use for absolute paths; i.e., DRUPAL_ROOT.
+   *
+   * @throws \BadMethodCallException
+   *   If the site path is initialized already.
+   *
+   * @see install_begin_request()
+   */
+  public static function initInstaller($root_directory) {
+    if (isset(self::$instance)) {
+      throw new \BadMethodCallException('Site path is initialized already.');
+    }
+    new self($root_directory);
+    // Denote that we are operating in the special installer environment.
+    self::$instance->isInstaller = TRUE;
+  }
+
+  /**
+   * Constructs the Site singleton.
+   *
+   * @throws \BadMethodCallException
+   *   If the site path is initialized already.
+   */
+  private function __construct($root_directory) {
+    if (isset(self::$instance)) {
+      throw new \BadMethodCallException('Site path is initialized already.');
+    }
+    $this->root = $root_directory;
+    self::$instance = $this;
+  }
+
+  /**
+   * Re-initializes (resets) the Site singleton for a test run.
+   *
+   * @throws \RuntimeException
+   *   If the site path of the test runner is not initialized yet.
+   *
+   * @throws \BadMethodCallException
+   *   If no test is executed currently.
+   *
+   * @see \Drupal\simpletest\TestBase::prepareEnvironment()
+   */
+  public static function setUpTest() {
+    if (!isset(self::$instance)) {
+      throw new \RuntimeException('No original Site to backup. Missing invocation of Site::init()?');
+    }
+    if (!drupal_valid_test_ua()) {
+      throw new \BadMethodCallException('Site is not executing a test.');
+    }
+    self::$original = clone self::$instance;
+    self::$instance = NULL;
+  }
+
+  /**
+   * Reverts the Site singleton to the original after a test run.
+   *
+   * @throws \RuntimeException
+   *   If there is no test runner site path to revert to.
+   *
+   * @throws \BadMethodCallException
+   *   If a test is still being executed currently.
+   *
+   * @see \Drupal\simpletest\TestBase::restoreEnvironment()
+   */
+  public static function tearDownTest() {
+    if (!isset(self::$original)) {
+      throw new \RuntimeException('No original Site to revert to. Missing invocation of Site::setUpTest()?');
+    }
+    // Do not allow to restore original Site singleton in a test environment,
+    // unless we are testing the test environment setup and teardown itself.
+    // @see \Drupal\simpletest\Tests\BrokenSetUpTest
+    if (drupal_valid_test_ua() && !DRUPAL_TEST_IN_CHILD_SITE) {
+      throw new \BadMethodCallException('Unable to revert Site: A test is still being executed.');
+    }
+    self::$instance = clone self::$original;
+    self::$original = NULL;
+  }
+
+  /**
+   * Returns whether the Site singleton was instantiated for the installer.
+   *
+   * @return bool
+   */
+  private function isInstaller() {
+    return $this->isInstaller;
+  }
+
+  /**
+   * Initializes the site path.
+   *
+   * @param array|null $sites
+   *   (optional) A multi-site mapping, as defined in settings.php.
+   * @param string|null $custom_path
+   *   (optional) An explicit site path to set; skipping site negotiation.
+   */
+  private function initializePath(array $sites = NULL, $custom_path = NULL) {
+    // Force-override the site directory in tests.
+    if ($test_prefix = drupal_valid_test_ua()) {
+      $this->path = 'sites/simpletest/' . substr($test_prefix, 10);
+    }
+    // An explicitly defined $conf_path in /settings.php takes precedence.
+    elseif (isset($custom_path)) {
+      $this->path = $custom_path;
+    }
+    // If the multi-site functionality was enabled in /settings.php, discover
+    // the path for the current site.
+    // $sites just needs to be defined; an explicit mapping is not required.
+    elseif (isset($sites)) {
+      $this->path = $this->determinePath($sites, !$this->isInstaller());
+    }
+    // Otherwise, the Drupal root directory is the site directory.
+    else {
+      $this->path = '';
+    }
+  }
+
+  /**
+   * Finds the appropriate configuration directory for a given host and path.
+   *
+   * Finds a matching configuration directory file by stripping the server
+   * hostname from left to right and pathname from right to left.
+   *
+   * By default, the site directory must contain a 'settings.php' file. If the
+   * parameter $require_settings is set to FALSE, then a site directory without
+   * a 'settings.php' file will be valid, too. The first valid site directory
+   * found will be used and less specific options will be ignored.
+   *
+   * The $sites variable can define site directory aliases as an associative
+   * array. For example, to create a directory alias for
+   * http://www.drupal.org:8080/mysite/test whose configuration file is in
+   * sites/example.com, the array should be defined as:
+   *
+   * @code
+   * $sites['8080.www.drupal.org.mysite.test'] = 'example.com';
+   * @endcode
+   *
+   * @see default.settings.php
+   *
+   * @param array $sites
+   *   A multi-site alias mapping, as defined in settings.php. May be empty.
+   * @param bool $require_settings
+   *   If TRUE, only site directories containing a settings.php file will be
+   *   recognized. During installation, this is set to FALSE, so that Drupal can
+   *   detect a site directory in which to create a new settings.php file.
+   *
+   * @return string
+   *   The relative path of the site directory. May be an empty string, in case
+   *   no site-specific directory matched, in which case the root directory is
+   *   the site directory.
+   */
+  private function determinePath(array $sites, $require_settings) {
+    // The hostname and optional port number, e.g. "www.example.com" or
+    // "www.example.com:8080".
+    $http_host = $_SERVER['HTTP_HOST'];
+    // The part of the URL following the hostname, including the leading slash.
+    $script_name = $_SERVER['SCRIPT_NAME'] ?: $_SERVER['SCRIPT_FILENAME'];
+
+    $uri = explode('/', $script_name);
+    $server = explode('.', implode('.', array_reverse(explode(':', rtrim($http_host, '.')))));
+    for ($i = count($uri) - 1; $i > 0; $i--) {
+      for ($j = count($server); $j > 0; $j--) {
+        $dir = implode('.', array_slice($server, -$j)) . implode('.', array_slice($uri, 0, $i));
+        // Check for an alias in $sites from settings.php.
+        if (isset($sites[$dir])) {
+          $dir = $sites[$dir];
+        }
+        if ($require_settings) {
+          if (file_exists($this->root . '/sites/' . $dir . '/settings.php')) {
+            return "sites/$dir";
+          }
+        }
+        elseif (file_exists($this->root . '/sites/' . $dir)) {
+          return "sites/$dir";
+        }
+      }
+    }
+    return '';
+  }
+
+  /**
+   * Prefixes a given subpathname with the site directory, if any.
+   *
+   * Site::getPath() and this helper method only exists to ensure that a given
+   * subpathname does not result in an absolute filesystem path in case of a
+   * string concatenation like the following:
+   *
+   * @code
+   * // If the sire directory path is empty (root directory), then the resulting
+   * // filesystem path would become absolute; i.e.: "/some/file"
+   * unlink($site_path . '/some/file');
+   * @endcode
+   *
+   * In case the PHP process has write access to the entire filesystem, such a
+   * file operation could succeed and potentially affect arbitrary other files
+   * and directories that happen to exist. That must not happen.
+   *
+   * @param string $subpathname
+   *   The subpathname to prefix.
+   *
+   * @return string
+   *   The prefixed subpathname.
+   *
+   * @throws \RuntimeException
+   *   If the site path is not initialized yet.
+   */
+  private function resolvePath($subpathname) {
+    // Extra safety protection in case a script somehow manages to bypass all
+    // other protections.
+    if (!isset($this->path)) {
+      throw new \RuntimeException('Site path is not initialized yet.');
+    }
+    // A faulty call to Site::getPath() might include a leading slash (/), in
+    // which case the entire site path resolution of this function would be
+    // pointless, because the resulting path would still be absolute. Therefore,
+    // guarantee that even a bogus argument is resolved correctly.
+    $subpathname = ltrim($subpathname, '/');
+
+    if ($this->path !== '') {
+      if ($subpathname !== '') {
+        return $this->path . '/' . $subpathname;
+      }
+      return $this->path;
+    }
+    return $subpathname;
+  }
+
+  /**
+   * Returns the given path relative to the site directory.
+   *
+   * Use this function instead of appending strings to the site path manually,
+   * because the site directory may be the root directory and thus a
+   * concatenated path would result in an absolute filesystem path.
+   *
+   * @param string $subpathname
+   *   (optional) A relative subpathname to append to the site path.
+   *
+   * @return string
+   *   The given $subpathname, potentially prefixed with the site path.
+   *
+   * @throws \RuntimeException
+   *   If the site path is not initialized yet.
+   *
+   * @see \Drupal\Core\Site\Site::getAbsolutePath()
+   */
+  public static function getPath($subpathname = '') {
+    return self::$instance->resolvePath($subpathname);
+  }
+
+  /**
+   * Returns the given path relative to the site directory, as an absolute path.
+   *
+   * Use this function instead of appending strings to the site path manually,
+   * because the site directory may be the root directory and thus a
+   * concatenated path would result in an absolute filesystem path.
+   *
+   * @param string $subpathname
+   *   (optional) A relative subpathname to append to the site path.
+   *
+   * @return string
+   *   The given $subpathname, potentially prefixed with the site path, as an
+   *   absolute filesystem path.
+   *
+   * @throws \RuntimeException
+   *   If the site path is not initialized yet.
+   *
+   * @see \Drupal\Core\Site\Site::getPath()
+   */
+  public static function getAbsolutePath($subpathname = '') {
+    $subpathname = self::$instance->resolvePath($subpathname);
+    if ($subpathname !== '') {
+      return self::$instance->root . '/' . $subpathname;
+    }
+    else {
+      return self::$instance->root;
+    }
+  }
+
+}
diff --git a/core/lib/Drupal/Core/StreamWrapper/PublicStream.php b/core/lib/Drupal/Core/StreamWrapper/PublicStream.php
index 637c9ef..45661a7 100644
--- a/core/lib/Drupal/Core/StreamWrapper/PublicStream.php
+++ b/core/lib/Drupal/Core/StreamWrapper/PublicStream.php
@@ -9,6 +9,7 @@
 
 use Drupal\Component\Utility\UrlHelper;
 use Drupal\Core\Site\Settings;
+use Drupal\Core\Site\Site;
 
 /**
  * Defines a Drupal public (public://) stream wrapper class.
@@ -40,7 +41,7 @@ public function getExternalUrl() {
    *   The base path for public:// typically sites/default/files.
    */
   public static function basePath() {
-    $base_path = Settings::get('file_public_path', conf_path() . '/files');
+    $base_path = Settings::get('file_public_path', Site::getPath('files'));
     return $base_path;
   }
 
diff --git a/core/modules/file/tests/file_test/src/DummyReadOnlyStreamWrapper.php b/core/modules/file/tests/file_test/src/DummyReadOnlyStreamWrapper.php
index d230bc5..8617566 100644
--- a/core/modules/file/tests/file_test/src/DummyReadOnlyStreamWrapper.php
+++ b/core/modules/file/tests/file_test/src/DummyReadOnlyStreamWrapper.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\file_test;
 
+use Drupal\Core\Site\Site;
 use Drupal\Core\StreamWrapper\LocalReadOnlyStream;
 
 /**
@@ -16,7 +17,7 @@
  */
 class DummyReadOnlyStreamWrapper extends LocalReadOnlyStream {
   function getDirectoryPath() {
-    return conf_path() . '/files';
+    return Site::getPath('files');
   }
 
   /**
diff --git a/core/modules/file/tests/file_test/src/DummyStreamWrapper.php b/core/modules/file/tests/file_test/src/DummyStreamWrapper.php
index cbea40f..dd919c8 100644
--- a/core/modules/file/tests/file_test/src/DummyStreamWrapper.php
+++ b/core/modules/file/tests/file_test/src/DummyStreamWrapper.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\file_test;
 
+use Drupal\Core\Site\Site;
 use Drupal\Core\StreamWrapper\LocalStream;
 
 /**
@@ -16,7 +17,7 @@
  */
 class DummyStreamWrapper extends LocalStream {
   function getDirectoryPath() {
-    return conf_path() . '/files';
+    return Site::getPath('files');
   }
 
   /**
diff --git a/core/modules/locale/locale.install b/core/modules/locale/locale.install
index dd00412..00de29e 100644
--- a/core/modules/locale/locale.install
+++ b/core/modules/locale/locale.install
@@ -6,6 +6,7 @@
  */
 
 use Drupal\Core\Language\Language;
+use Drupal\Core\Site\Site;
 use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationSelected;
 
 /**
@@ -14,7 +15,7 @@
 function locale_install() {
   // Create the interface translations directory and ensure it's writable.
   if (!$directory = \Drupal::config('locale.settings')->get('translation.path')) {
-    $directory = conf_path() . '/files/translations';
+    $directory = Site::getPath('files/translations');
     \Drupal::config('locale.settings')->set('translation.path', $directory)->save();
   }
   file_prepare_directory($directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
diff --git a/core/modules/simpletest/src/TestBase.php b/core/modules/simpletest/src/TestBase.php
index e57048f..dd352a6 100644
--- a/core/modules/simpletest/src/TestBase.php
+++ b/core/modules/simpletest/src/TestBase.php
@@ -20,6 +20,7 @@
 use Drupal\Core\Session\AccountProxy;
 use Drupal\Core\Session\AnonymousUserSession;
 use Drupal\Core\Site\Settings;
+use Drupal\Core\Site\Site;
 use Drupal\Core\StreamWrapper\PublicStream;
 use Drupal\Core\Utility\Error;
 use Symfony\Component\HttpFoundation\Request;
@@ -1002,7 +1003,7 @@ private function prepareEnvironment() {
     }
 
     // Backup current in-memory configuration.
-    $this->originalSite = conf_path();
+    $this->originalSite = Site::getPath();
     $this->originalSettings = Settings::getAll();
     $this->originalConfig = $GLOBALS['config'];
     // @todo Remove all remnants of $GLOBALS['conf'].
@@ -1017,7 +1018,7 @@ private function prepareEnvironment() {
     // Save further contextual information.
     // Use the original files directory to avoid nesting it within an existing
     // simpletest directory if a test is executed within a test.
-    $this->originalFileDirectory = Settings::get('file_public_path', conf_path() . '/files');
+    $this->originalFileDirectory = Settings::get('file_public_path', Site::getPath('files'));
     $this->originalProfile = drupal_get_profile();
     $this->originalUser = isset($user) ? clone $user : NULL;
 
@@ -1096,8 +1097,11 @@ private function prepareEnvironment() {
 
     // After preparing the environment and changing the database prefix, we are
     // in a valid test environment.
+    if (!is_dir(DRUPAL_ROOT . '/' . $this->siteDirectory)) {
+      throw new \RuntimeException("Test site directory '$this->siteDirectory' does not exist.");
+    }
     drupal_valid_test_ua($this->databasePrefix);
-    conf_path(FALSE, TRUE);
+    Site::setUpTest();
 
     // Reset settings.
     new Settings(array(
@@ -1209,7 +1213,7 @@ private function restoreEnvironment() {
     else {
       drupal_valid_test_ua(FALSE);
     }
-    conf_path(TRUE, TRUE);
+    Site::tearDownTest();
 
     // Restore stream wrappers of the test runner.
     file_get_stream_wrappers();
diff --git a/core/modules/simpletest/src/UnitTestBase.php b/core/modules/simpletest/src/UnitTestBase.php
index 9d93fa0..325e87b 100644
--- a/core/modules/simpletest/src/UnitTestBase.php
+++ b/core/modules/simpletest/src/UnitTestBase.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Database\Database;
 use Drupal\Core\Database\ConnectionNotDefinedException;
+use Drupal\Core\Site\Site;
 
 /**
  * Base test case class for unit tests.
@@ -37,6 +38,9 @@ function __construct($test_id = NULL) {
    * setUp() method.
    */
   protected function setUp() {
+    // Initialize the test Site singleton, so that Site::getPath() works.
+    Site::init(DRUPAL_ROOT);
+
     file_prepare_directory($this->public_files_directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
     $this->settingsSet('file_public_path', $this->public_files_directory);
   }
diff --git a/core/modules/simpletest/src/WebTestBase.php b/core/modules/simpletest/src/WebTestBase.php
index a12c310..b954996 100644
--- a/core/modules/simpletest/src/WebTestBase.php
+++ b/core/modules/simpletest/src/WebTestBase.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Serialization\Json;
 use Drupal\Component\Utility\Crypt;
 use Drupal\Component\Utility\NestedArray;
+use Drupal\Component\Utility\Settings;
 use Drupal\Component\Utility\String;
 use Drupal\Core\DrupalKernel;
 use Drupal\Core\Database\Database;
@@ -810,8 +811,7 @@ protected function setUp() {
     // Copy and prepare an actual settings.php, so as to resemble a regular
     // installation.
     // Not using File API; a potential error must trigger a PHP warning.
-    $directory = DRUPAL_ROOT . '/' . $this->siteDirectory;
-    copy(DRUPAL_ROOT . '/sites/default/default.settings.php', $directory . '/settings.php');
+    copy(DRUPAL_ROOT . '/core/default.settings.php', DRUPAL_ROOT . '/' . $this->siteDirectory . '/settings.php');
 
     // All file system paths are created by System module during installation.
     // @see system_requirements()
@@ -830,10 +830,13 @@ protected function setUp() {
     );
     // Add the parent profile's search path to the child site's search paths.
     // @see \Drupal\Core\Extension\ExtensionDiscovery::getProfileDirectories()
-    $settings['conf']['simpletest.settings']['parent_profile'] = (object) array(
+    $settings['config']['simpletest.settings']['parent_profile'] = (object) array(
       'value' => $this->originalProfile,
       'required' => TRUE,
     );
+    // Write a new settings.php for the test site environment.
+    // drupal_rewrite_settings() will reload Settings and update
+    // $GLOBALS['config'] accordingly.
     $this->writeSettings($settings);
     // Allow for test-specific overrides.
     $settings_testing_file = DRUPAL_ROOT . '/' . $this->originalSite . '/settings.testing.php';
@@ -871,7 +874,8 @@ protected function setUp() {
     // directory has to be writable.
     // TestBase::restoreEnvironment() will delete the entire site directory.
     // Not using File API; a potential error must trigger a PHP warning.
-    chmod($directory, 0777);
+    chmod(DRUPAL_ROOT . '/' . $this->siteDirectory, 0777);
+    chmod(DRUPAL_ROOT . '/' . $this->siteDirectory . '/settings.php', 0666);
 
     $request = \Drupal::request();
     $this->kernel = DrupalKernel::createFromRequest($request, drupal_classloader(), 'prod', TRUE);
diff --git a/core/modules/system/src/Tests/DrupalKernel/DrupalKernelTest.php b/core/modules/system/src/Tests/DrupalKernel/DrupalKernelTest.php
index a36adae..446f1ea 100644
--- a/core/modules/system/src/Tests/DrupalKernel/DrupalKernelTest.php
+++ b/core/modules/system/src/Tests/DrupalKernel/DrupalKernelTest.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\DrupalKernel;
 use Drupal\Core\Site\Settings;
+use Drupal\Core\Site\Site;
 use Drupal\simpletest\DrupalUnitTestBase;
 use Symfony\Component\HttpFoundation\Request;
 
@@ -25,6 +26,10 @@ class DrupalKernelTest extends DrupalUnitTestBase {
   protected $classloader;
 
   protected function setUp() {
+
+    // Initialize the test Site singleton, so that Site::getPath() works.
+    Site::init(DRUPAL_ROOT);
+
     // DrupalKernel relies on global $config_directories and requires those
     // directories to exist. Therefore, create the directories, but do not
     // invoke KernelTestBase::setUp(), since that would set up further
diff --git a/core/modules/system/src/Tests/File/DirectoryTest.php b/core/modules/system/src/Tests/File/DirectoryTest.php
index 158be71..ae36102 100644
--- a/core/modules/system/src/Tests/File/DirectoryTest.php
+++ b/core/modules/system/src/Tests/File/DirectoryTest.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\system\Tests\File;
 
+use Drupal\Core\Site\Site;
+
 /**
  * Tests operations dealing with directories.
  *
@@ -17,7 +19,7 @@ class DirectoryTest extends FileTestBase {
    * Test local directory handling functions.
    */
   function testFileCheckLocalDirectoryHandling() {
-    $directory = conf_path() . '/files';
+    $directory = Site::getPath('files');
 
     // Check a new recursively created local directory for correct file system
     // permissions.
diff --git a/core/modules/system/src/Tests/File/ReadOnlyStreamWrapperTest.php b/core/modules/system/src/Tests/File/ReadOnlyStreamWrapperTest.php
index c9cb68b..958dc3c 100644
--- a/core/modules/system/src/Tests/File/ReadOnlyStreamWrapperTest.php
+++ b/core/modules/system/src/Tests/File/ReadOnlyStreamWrapperTest.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\system\Tests\File;
 
+use Drupal\Core\Site\Site;
+
 /**
  * Tests the read-only stream wrapper write functions.
  *
@@ -34,7 +36,7 @@ class ReadOnlyStreamWrapperTest extends FileTestBase {
   function testWriteFunctions() {
     // Generate a test file
     $filename = $this->randomMachineName();
-    $filepath = conf_path() . '/files/' . $filename;
+    $filepath = Site::getPath('files/' . $filename);
     file_put_contents($filepath, $filename);
 
     // Generate a read-only stream wrapper instance
@@ -77,7 +79,9 @@ function testWriteFunctions() {
 
     // Test the mkdir() function by attempting to create a directory.
     $dirname = $this->randomMachineName();
-    $dir = conf_path() . '/files/' . $dirname;
+    $dir = Site::getPath('files/' . $dirname);
+    $dirname = $this->randomName();
+    $dir = Site::getPath('files/' . $dirname);
     $readonlydir = $this->scheme . '://' . $dirname;
     $this->assertFalse(@drupal_mkdir($readonlydir, 0775, 0), 'Unable to create directory with read-only stream wrapper.');
     // Create a temporary directory for testing purposes
diff --git a/core/modules/system/src/Tests/System/SettingsRewriteTest.php b/core/modules/system/src/Tests/System/SettingsRewriteTest.php
index 741f92c..e9aca16 100644
--- a/core/modules/system/src/Tests/System/SettingsRewriteTest.php
+++ b/core/modules/system/src/Tests/System/SettingsRewriteTest.php
@@ -7,8 +7,10 @@
 
 namespace Drupal\system\Tests\System;
 
+<<<<<<< HEAD:core/modules/system/src/Tests/System/SettingsRewriteTest.php
 use Drupal\Core\Site\Settings;
 use Drupal\simpletest\KernelTestBase;
+use Drupal\Core\Site\Site;
 
 /**
  * Tests the drupal_rewrite_settings() function.
@@ -99,7 +101,7 @@ function testDrupalRewriteSettings() {
       ),
     );
     foreach ($tests as $test) {
-      $filename = Settings::get('file_public_path', conf_path() . '/files') . '/mock_settings.php';
+      $filename = Settings::get('file_public_path', Site::getPath('files')) . '/mock_settings.php';
       file_put_contents(DRUPAL_ROOT . '/' . $filename, "<?php\n" . $test['original'] . "\n");
       drupal_rewrite_settings($test['settings'], $filename);
       $this->assertEqual(file_get_contents(DRUPAL_ROOT . '/' . $filename), "<?php\n" . $test['expected'] . "\n");
@@ -117,7 +119,7 @@ function testDrupalRewriteSettings() {
       'expected' => '$no_index = true;'
     );
     // Make an empty file.
-    $filename = Settings::get('file_public_path', conf_path() . '/files') . '/mock_settings.php';
+    $filename = Settings::get('file_public_path', Site::getPath('files')) . '/mock_settings.php';
     file_put_contents(DRUPAL_ROOT . '/' . $filename, "");
 
     // Write the setting to the file.
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index 4c94516..4a22b6a 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -11,6 +11,7 @@
 use Drupal\Core\Database\Database;
 use Drupal\Core\Language\Language;
 use Drupal\Core\Site\Settings;
+use Drupal\Core\Site\Site;
 use Drupal\Core\StreamWrapper\PublicStream;
 
 /**
@@ -215,14 +216,17 @@ function system_requirements($phase) {
   // Test configuration files and directory for writability.
   if ($phase == 'runtime') {
     $conf_errors = array();
-    $conf_path = conf_path();
-    if (!drupal_verify_install_file($conf_path, FILE_NOT_WRITABLE, 'dir')) {
-      $conf_errors[] = t("The directory %file is not protected from modifications and poses a security risk. You must change the directory's permissions to be non-writable.", array('%file' => $conf_path));
+    if (is_writable(Site::getAbsolutePath())) {
+      $conf_errors[] = t("The directory %file is not protected from modifications and poses a security risk. You must change the directory's permissions to be non-writable.", array(
+        '%file' => Site::getPath() ?: Site::getAbsolutePath(),
+      ));
     }
     foreach (array('settings.php', 'settings.local.php') as $conf_file) {
-      $full_path = $conf_path . '/' . $conf_file;
+      $full_path = Site::getAbsolutePath($conf_file);
       if (file_exists($full_path) && !drupal_verify_install_file($full_path, FILE_EXIST|FILE_READABLE|FILE_NOT_WRITABLE)) {
-        $conf_errors[] = t("The file %file is not protected from modifications and poses a security risk. You must change the file's permissions to be non-writable.", array('%file' => $full_path));
+        $conf_errors[] = t("The file %file is not protected from modifications and poses a security risk. You must change the file's permissions to be non-writable.", array(
+          '%file' => Site::getPath($conf_file),
+        ));
       }
     }
     if (!empty($conf_errors)) {
@@ -350,7 +354,7 @@ function system_requirements($phase) {
     else {
       // If we are installing Drupal, the settings.php file might not exist yet
       // in the intended site directory, so don't require it.
-      $directories[] = conf_path(FALSE) . '/files';
+      $directories[] = Site::getPath('files');
     }
     if (!empty($GLOBALS['config']['system.file']['path']['private'])) {
       $directories[] = $GLOBALS['config']['system.file']['path']['private'];
@@ -376,7 +380,7 @@ function system_requirements($phase) {
     $requirements['config directories'] = array(
       'title' => t('Configuration directories'),
       'value' => t('Not present'),
-      'description' => t('Your %file file must define the $config_directories variable as an array containing the name of a directories in which configuration files can be written.', array('%file' => conf_path() . '/settings.php')),
+      'description' => t('Your %file file must define the $config_directories variable as an array containing the name of a directories in which configuration files can be written.', array('%file' => Site::getPath('settings.php'))),
       'severity' => REQUIREMENT_ERROR,
     );
   }
diff --git a/core/modules/update/update.manager.inc b/core/modules/update/update.manager.inc
index 1faf7fd..6f29f45 100644
--- a/core/modules/update/update.manager.inc
+++ b/core/modules/update/update.manager.inc
@@ -36,6 +36,8 @@
  * root.
  */
 
+
+use Drupal\Core\Site\Site;
 use Symfony\Component\HttpFoundation\RedirectResponse;
 
 /**
@@ -304,7 +306,7 @@ function update_manager_local_transfers_allowed() {
   // the configuration directory to determine if local transfers will be
   // allowed.
   $temporary_file = drupal_tempnam('temporary://', 'update_');
-  $local_transfers_allowed = fileowner($temporary_file) === fileowner(conf_path());
+  $local_transfers_allowed = fileowner($temporary_file) === fileowner(Site::getAbsolutePath());
 
   // Clean up. If this fails, we can ignore it (since this is just a temporary
   // file anyway).
diff --git a/sites/example.sites.php b/sites/example.sites.php
deleted file mode 100644
index 2a813dd..0000000
--- a/sites/example.sites.php
+++ /dev/null
@@ -1,55 +0,0 @@
-<?php
-
-/**
- * @file
- * Configuration file for multi-site support and directory aliasing feature.
- *
- * This file is required for multi-site support and also allows you to define a
- * set of aliases that map hostnames, ports, and pathnames to configuration
- * directories in the sites directory. These aliases are loaded prior to
- * scanning for directories, and they are exempt from the normal discovery
- * rules. See default.settings.php to view how Drupal discovers the
- * configuration directory when no alias is found.
- *
- * Aliases are useful on development servers, where the domain name may not be
- * the same as the domain of the live server. Since Drupal stores file paths in
- * the database (files, system table, etc.) this will ensure the paths are
- * correct when the site is deployed to a live server.
- *
- * To activate this feature, copy and rename it such that its path plus
- * filename is 'sites/sites.php'.
- *
- * Aliases are defined in an associative array named $sites. The array is
- * written in the format: '<port>.<domain>.<path>' => 'directory'. As an
- * example, to map http://www.drupal.org:8080/mysite/test to the configuration
- * directory sites/example.com, the array should be defined as:
- * @code
- * $sites = array(
- *   '8080.www.drupal.org.mysite.test' => 'example.com',
- * );
- * @endcode
- * The URL, http://www.drupal.org:8080/mysite/test/, could be a symbolic link or
- * an Apache Alias directive that points to the Drupal root containing
- * index.php. An alias could also be created for a subdomain. See the
- * @link http://drupal.org/documentation/install online Drupal installation guide @endlink
- * for more information on setting up domains, subdomains, and subdirectories.
- *
- * The following examples look for a site configuration in sites/example.com:
- * @code
- * URL: http://dev.drupal.org
- * $sites['dev.drupal.org'] = 'example.com';
- *
- * URL: http://localhost/example
- * $sites['localhost.example'] = 'example.com';
- *
- * URL: http://localhost:8080/example
- * $sites['8080.localhost.example'] = 'example.com';
- *
- * URL: http://www.drupal.org:8080/mysite/test/
- * $sites['8080.www.drupal.org.mysite.test'] = 'example.com';
- * @endcode
- *
- * @see default.settings.php
- * @see conf_path()
- * @see http://drupal.org/documentation/install/multi-site
- */
