diff --git a/apps/files/ajax/rename.php b/apps/files/ajax/rename.php
index 45448279fa161d46137c2bddee952060eaa6a584..cb0bec399d108fb094f0faccda8b897588d9a564 100644
--- a/apps/files/ajax/rename.php
+++ b/apps/files/ajax/rename.php
@@ -12,7 +12,7 @@ $file = stripslashes($_GET["file"]);
 $newname = stripslashes($_GET["newname"]);
 
 // Delete
-if( OC_Files::move( $dir, $file, $dir, $newname )) {
+if( $newname !== '.' and OC_Files::move( $dir, $file, $dir, $newname )) {
 	OCP\JSON::success(array("data" => array( "dir" => $dir, "file" => $file, "newname" => $newname )));
 }
 else{
diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js
index 96dd0323d29a4b463ca96d2f6c789fc63a0deb91..22d701d8ff919c464c7e2a982134a22cc0a884bf 100644
--- a/apps/files/js/filelist.js
+++ b/apps/files/js/filelist.js
@@ -149,7 +149,7 @@ var FileList={
 			event.stopPropagation();
 			event.preventDefault();
 			var newname=input.val();
-			if (Files.containsInvalidCharacters(newname)) {
+			if (!Files.isFileNameValid(newname)) {
 				return false;
 			}
 			if (newname != name) {
diff --git a/apps/files/js/files.js b/apps/files/js/files.js
index 6a37d9e7f538fdebcb0760d81b80da01019e2ee9..ba2495eb7280ce4b571fca0f0694b8ce0ae9ea3c 100644
--- a/apps/files/js/files.js
+++ b/apps/files/js/files.js
@@ -26,17 +26,29 @@ Files={
 		});
 		procesSelection();
 	},
-	containsInvalidCharacters:function (name) {
+    isFileNameValid:function (name) {
+        if (name === '.') {
+            $('#notification').text(t('files', "'.' is an invalid file name."));
+            $('#notification').fadeIn();
+            return false;
+        }
+        if (name.length == 0) {
+            $('#notification').text(t('files', "File name cannot be empty."));
+            $('#notification').fadeIn();
+            return false;
+        }
+
+        // check for invalid characters
 		var invalid_characters = ['\\', '/', '<', '>', ':', '"', '|', '?', '*'];
 		for (var i = 0; i < invalid_characters.length; i++) {
 			if (name.indexOf(invalid_characters[i]) != -1) {
 				$('#notification').text(t('files', "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed."));
 				$('#notification').fadeIn();
-				return true;
+				return false;
 			}
 		}
 		$('#notification').fadeOut();
-		return false;
+		return true;
 	}
 };
 $(document).ready(function() {
@@ -509,7 +521,7 @@ $(document).ready(function() {
 		$(this).append(input);
 		input.focus();
 		input.change(function(){
-			if (type != 'web' && Files.containsInvalidCharacters($(this).val())) {
+			if (type != 'web' && !Files.isFileNameValid($(this).val())) {
 				return;
 			} else if( type == 'folder' && $('#dir').val() == '/' && $(this).val() == 'Shared') {
 				$('#notification').text(t('files','Invalid folder name. Usage of "Shared" is reserved by Owncloud'));
diff --git a/config/config.sample.php b/config/config.sample.php
index 2eec7847f9ce45fd5cb9993e93e1e70979a3beff..b1655d028305c1f09672cf0128ac53749a7389ac 100644
--- a/config/config.sample.php
+++ b/config/config.sample.php
@@ -115,6 +115,9 @@ $CONFIG = array(
  */
 // "datadirectory" => "",
 
+/* Enable maintenance mode to disable ownCloud */
+"maintenance" => false,
+
 "apps_paths" => array(
 
 /* Set an array of path for your apps directories
diff --git a/core/ajax/update.php b/core/ajax/update.php
new file mode 100644
index 0000000000000000000000000000000000000000..20ab045c89243b09f433dac2900caba7acb57b17
--- /dev/null
+++ b/core/ajax/update.php
@@ -0,0 +1,67 @@
+<?php
+set_time_limit(0);
+$RUNTIME_NOAPPS = true;
+require_once '../../lib/base.php';
+
+if (OC::checkUpgrade(false)) {
+	$updateEventSource = new OC_EventSource();
+	$watcher = new UpdateWatcher($updateEventSource);
+	OC_Hook::connect('update', 'success', $watcher, 'success');
+	OC_Hook::connect('update', 'error', $watcher, 'error');
+	OC_Hook::connect('update', 'error', $watcher, 'failure');
+	$watcher->success('Turned on maintenance mode');
+	try {
+		$result = OC_DB::updateDbFromStructure(OC::$SERVERROOT.'/db_structure.xml');
+		$watcher->success('Updated database');
+	} catch (Exception $exception) {
+		$watcher->failure($exception->getMessage());
+	}
+	$minimizerCSS = new OC_Minimizer_CSS();
+	$minimizerCSS->clearCache();
+	$minimizerJS = new OC_Minimizer_JS();
+	$minimizerJS->clearCache();
+	OC_Config::setValue('version', implode('.', OC_Util::getVersion()));
+	OC_App::checkAppsRequirements();
+	// load all apps to also upgrade enabled apps
+	OC_App::loadApps();
+	OC_Config::setValue('maintenance', false);
+	$watcher->success('Turned off maintenance mode');
+	$watcher->done();
+}
+
+class UpdateWatcher {
+	/**
+	 * @var \OC_EventSource $eventSource;
+	 */
+	private $eventSource;
+
+	public function __construct($eventSource) {
+		$this->eventSource = $eventSource;
+	}
+
+	public function success($message) {
+		OC_Util::obEnd();
+		$this->eventSource->send('success', $message);
+		ob_start();
+	}
+
+	public function error($message) {
+		OC_Util::obEnd();
+		$this->eventSource->send('error', $message);
+		ob_start();
+	}
+
+	public function failure($message) {
+		OC_Util::obEnd();
+		$this->eventSource->send('failure', $message);
+		$this->eventSource->close();
+		die();
+	}
+
+	public function done() {
+		OC_Util::obEnd();
+		$this->eventSource->send('done', '');
+		$this->eventSource->close();
+	}
+
+}
\ No newline at end of file
diff --git a/core/css/styles.css b/core/css/styles.css
index d635916b5ae6a5ab554e54de271f0093c5963fb7..6e1cef72eda8a0a0642c64d521ac1b0cbb2775a3 100644
--- a/core/css/styles.css
+++ b/core/css/styles.css
@@ -214,7 +214,8 @@ div.jp-play-bar, div.jp-seek-bar { padding:0; }
 .pager { list-style:none; float:right; display:inline; margin:.7em 13em 0 0; }
 .pager li { display:inline-block; }
 
-li.error { width:640px; margin:4em auto; padding:1em 1em 1em 4em; background:#ffe .8em .8em no-repeat; color:#FF3B3B; border:1px solid #ccc; -moz-border-radius:10px; -webkit-border-radius:10px; border-radius:10px; }
+li.update, li.error { width:640px; margin:4em auto; padding:1em 1em 1em 4em; background:#ffe .8em .8em no-repeat;  border:1px solid #ccc; -moz-border-radius:10px; -webkit-border-radius:10px; border-radius:10px; cursor:default; }
+.error { color:#FF3B3B; }
 .ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { overflow:hidden; text-overflow:ellipsis; }
 .hint { background-image:url('../img/actions/info.png'); background-repeat:no-repeat; color:#777777; padding-left:25px; background-position:0 0.3em;}
 .separator { display:inline; border-left:1px solid #d3d3d3; border-right:1px solid #fff; height:10px; width:0px; margin:4px; }
diff --git a/core/templates/update.php b/core/templates/update.php
new file mode 100644
index 0000000000000000000000000000000000000000..c9f3144f25770dcc29086b64a75c0efaeaa56d01
--- /dev/null
+++ b/core/templates/update.php
@@ -0,0 +1,31 @@
+<ul>
+	<li class='update'>
+		<?php echo $l->t('Updating ownCloud to version %s, this may take a while.', array($_['version'])); ?><br /><br />
+	</li>
+</ul>
+<script>
+	$(document).ready(function () {
+		OC.EventSource.requesttoken = oc_requesttoken;
+		var updateEventSource = new OC.EventSource(OC.webroot+'/core/ajax/update.php');
+		updateEventSource.listen('success', function(message) {
+			$('<span>').append(message).append('<br />').appendTo($('.update'));
+		});
+		updateEventSource.listen('error', function(message) {
+			$('<span>').addClass('error').append(message).append('<br />').appendTo($('.update'));
+		});
+		updateEventSource.listen('failure', function(message) {
+			$('<span>').addClass('error').append(message).append('<br />').appendTo($('.update'));
+			$('<span>')
+				.addClass('error bold')
+				.append('<br />')
+				.append(t('core', 'The update was unsuccessful. Please report this issue to the <a href="https://github.com/owncloud/core/issues" target="_blank">ownCloud community</a>.'))
+				.appendTo($('.update'));
+		});
+		updateEventSource.listen('done', function(message) {
+			$('<span>').addClass('bold').append('<br />').append(t('core', 'The update was successful. Redirecting you to ownCloud now.')).appendTo($('.update'));
+			setTimeout(function () {
+				window.location.href = OC.webroot;
+			}, 3000);
+		});
+	});
+</script>
\ No newline at end of file
diff --git a/lib/app.php b/lib/app.php
index 30f76300365f54cca5dd785e5925ea6b6fe30f0b..e60bce2a201e9c775f103daf96b7e455c425c874 100644
--- a/lib/app.php
+++ b/lib/app.php
@@ -648,12 +648,15 @@ class OC_App{
 		if ($currentVersion) {
 			$installedVersion = $versions[$app];
 			if (version_compare($currentVersion, $installedVersion, '>')) {
+				$info = self::getAppInfo($app);
 				OC_Log::write($app, 'starting app upgrade from '.$installedVersion.' to '.$currentVersion, OC_Log::DEBUG);
 				try {
 					OC_App::updateApp($app);
+					OC_Hook::emit('update', 'success', 'Updated '.$info['name'].' app');
 				}
 				catch (Exception $e) {
 					echo 'Failed to upgrade "'.$app.'". Exception="'.$e->getMessage().'"';
+					OC_Hook::emit('update', 'failure', 'Failed to update '.$info['name'].' app: '.$e->getMessage());
 					die;
 				}
 				OC_Appconfig::setValue($app, 'installed_version', OC_App::getAppVersion($app));
@@ -678,6 +681,7 @@ class OC_App{
 			if(!isset($info['require']) or (($version[0].'.'.$version[1])>$info['require'])) {
 				OC_Log::write('core', 'App "'.$info['name'].'" ('.$app.') can\'t be used because it is not compatible with this version of ownCloud', OC_Log::ERROR);
 				OC_App::disable( $app );
+				OC_Hook::emit('update', 'success', 'Disabled '.$info['name'].' app because it is not compatible');
 			}
 		}
 	}
diff --git a/lib/base.php b/lib/base.php
index ef203b33c2b1b45846d7edb54f789e16971a2e7c..3d3e7d59f909f9affcf93bf868d6215c1ade18e1 100644
--- a/lib/base.php
+++ b/lib/base.php
@@ -193,6 +193,15 @@ class OC
         );
     }
 
+	public static function checkConfig() {
+		if (file_exists(OC::$SERVERROOT . "/config/config.php") and !is_writable(OC::$SERVERROOT . "/config/config.php")) {
+			$tmpl = new OC_Template('', 'error', 'guest');
+			$tmpl->assign('errors', array(1 => array('error' => "Can't write into config directory 'config'", 'hint' => "You can usually fix this by giving the webserver user write access to the config directory in owncloud")));
+			$tmpl->printPage();
+			exit();
+		}
+	}
+
     public static function checkInstalled()
     {
         // Redirect to installer if not installed
@@ -219,43 +228,35 @@ class OC
         }
     }
 
-    public static function checkUpgrade()
-    {
-        if (OC_Config::getValue('installed', false)) {
-            $installedVersion = OC_Config::getValue('version', '0.0.0');
-            $currentVersion = implode('.', OC_Util::getVersion());
-            if (version_compare($currentVersion, $installedVersion, '>')) {
-                // Check if the .htaccess is existing - this is needed for upgrades from really old ownCloud versions
-                if (isset($_SERVER['SERVER_SOFTWARE']) && strstr($_SERVER['SERVER_SOFTWARE'], 'Apache')) {
-                    if (!OC_Util::ishtaccessworking()) {
-                        if (!file_exists(OC::$SERVERROOT . '/data/.htaccess')) {
-                            OC_Setup::protectDataDirectory();
-                        }
-                    }
-                }
-                OC_Log::write('core', 'starting upgrade from ' . $installedVersion . ' to ' . $currentVersion, OC_Log::DEBUG);
-                $result = OC_DB::updateDbFromStructure(OC::$SERVERROOT . '/db_structure.xml');
-                if (!$result) {
-                    echo 'Error while upgrading the database';
-                    die();
-                }
-                if (file_exists(OC::$SERVERROOT . "/config/config.php") and !is_writable(OC::$SERVERROOT . "/config/config.php")) {
-                    $tmpl = new OC_Template('', 'error', 'guest');
-                    $tmpl->assign('errors', array(1 => array('error' => "Can't write into config directory 'config'", 'hint' => "You can usually fix this by giving the webserver user write access to the config directory in owncloud")));
-                    $tmpl->printPage();
-                    exit;
-                }
-                $minimizerCSS = new OC_Minimizer_CSS();
-                $minimizerCSS->clearCache();
-                $minimizerJS = new OC_Minimizer_JS();
-                $minimizerJS->clearCache();
-                OC_Config::setValue('version', implode('.', OC_Util::getVersion()));
-                OC_App::checkAppsRequirements();
-                // load all apps to also upgrade enabled apps
-                OC_App::loadApps();
-            }
-        }
-    }
+	public static function checkMaintenanceMode() {
+		// Allow ajax update script to execute without being stopped
+		if (OC_Config::getValue('maintenance', false) && OC::$SUBURI != '/core/ajax/update.php') {
+			$tmpl = new OC_Template('', 'error', 'guest');
+			$tmpl->assign('errors', array(1 => array('error' => 'ownCloud is in maintenance mode')));
+			$tmpl->printPage();
+			exit();
+		}
+	}
+
+	public static function checkUpgrade($showTemplate = true) {
+		if (OC_Config::getValue('installed', false)) {
+			$installedVersion = OC_Config::getValue('version', '0.0.0');
+			$currentVersion = implode('.', OC_Util::getVersion());
+			if (version_compare($currentVersion, $installedVersion, '>')) {
+				if ($showTemplate && !OC_Config::getValue('maintenance', false)) {
+					OC_Config::setValue('maintenance', true);
+					OC_Log::write('core', 'starting upgrade from ' . $installedVersion . ' to ' . $currentVersion, OC_Log::DEBUG);
+					$tmpl = new OC_Template('', 'update', 'guest');
+					$tmpl->assign('version', OC_Util::getVersionString());
+					$tmpl->printPage();
+					exit();
+				} else {
+					return true;
+				}
+			}
+			return false;
+		}
+	}
 
     public static function initTemplateEngine()
     {
@@ -273,12 +274,6 @@ class OC
         OC_Util::addScript('search', 'result');
         OC_Util::addScript('router');
 
-        if (OC_Config::getValue('installed', false)) {
-            if (OC_Appconfig::getValue('core', 'backgroundjobs_mode', 'ajax') == 'ajax') {
-                OC_Util::addScript('backgroundjobs');
-            }
-        }
-
         OC_Util::addStyle("styles");
         OC_Util::addStyle("multiselect");
         OC_Util::addStyle("jquery-ui-1.8.16.custom");
@@ -403,11 +398,13 @@ class OC
         stream_wrapper_register('static', 'OC_StaticStreamWrapper');
         stream_wrapper_register('close', 'OC_CloseStreamWrapper');
 
+	self::checkConfig();
         self::checkInstalled();
         self::checkSSL();
         self::initSession();
         self::initTemplateEngine();
-        self::checkUpgrade();
+	self::checkMaintenanceMode();
+	self::checkUpgrade();
 
         $errors = OC_Util::checkServer();
         if (count($errors) > 0) {
@@ -482,6 +479,11 @@ class OC
         if (OC_Util::issetlocaleworking() == false) {
             OC_Log::write('core', 'setting locate to en_US.UTF-8 failed. Support is probably not installed on your system', OC_Log::ERROR);
         }
+	if (OC_Config::getValue('installed', false)) {
+		if (OC_Appconfig::getValue('core', 'backgroundjobs_mode', 'ajax') == 'ajax') {
+			OC_Util::addScript('backgroundjobs');
+		}
+	}
     }
 
     /**
diff --git a/lib/db.php b/lib/db.php
index 7e60b41d2305434a0b95ed2bd0191f7bd4ba2e1e..74e7ca5b0e0957db219ba60f71a49e528cd1d265 100644
--- a/lib/db.php
+++ b/lib/db.php
@@ -495,8 +495,9 @@ class OC_DB {
 		if (PEAR::isError($previousSchema)) {
 			$error = $previousSchema->getMessage();
 			$detail = $previousSchema->getDebugInfo();
-			OC_Log::write('core', 'Failed to get existing database structure for upgrading ('.$error.', '.$detail.')', OC_Log::FATAL);
-			return false;
+			$message = 'Failed to get existing database structure for updating ('.$error.', '.$detail.')';
+			OC_Log::write('core', $message, OC_Log::FATAL);
+			throw new Exception($message);
 		}
 
 		// Make changes and save them to an in-memory file
@@ -523,8 +524,9 @@ class OC_DB {
 		if (PEAR::isError($op)) {
 			$error = $op->getMessage();
 			$detail = $op->getDebugInfo();
-			OC_Log::write('core', 'Failed to update database structure ('.$error.', '.$detail.')', OC_Log::FATAL);
-			return false;
+			$message = 'Failed to update database structure ('.$error.', '.$detail.')';
+			OC_Log::write('core', $message, OC_Log::FATAL);
+			throw new Exception($message);
 		}
 		return true;
 	}