diff --git a/apps/files_external/lib/config.php b/apps/files_external/lib/config.php
index 952463b8015c985fc7c308bc13d80e18e25b8f25..92bb891ca21b032be309fc82546f6984ffa7cee6 100755
--- a/apps/files_external/lib/config.php
+++ b/apps/files_external/lib/config.php
@@ -118,6 +118,22 @@ class OC_Mount_Config {
 			}
 			$manager->addMount($mount);
 		}
+
+		if ($data['user']) {
+			$user = \OC::$server->getUserManager()->get($data['user']);
+			$userView = new \OC\Files\View('/' . $user->getUID() . '/files');
+			$changePropagator = new \OC\Files\Cache\ChangePropagator($userView);
+			$etagPropagator = new \OCA\Files_External\EtagPropagator($user, $changePropagator, \OC::$server->getConfig());
+			$etagPropagator->propagateDirtyMountPoints();
+			\OCP\Util::connectHook(
+				\OC\Files\Filesystem::CLASSNAME,
+				\OC\Files\Filesystem::signal_create_mount,
+				$etagPropagator, 'updateHook');
+			\OCP\Util::connectHook(
+				\OC\Files\Filesystem::CLASSNAME,
+				\OC\Files\Filesystem::signal_delete_mount,
+				$etagPropagator, 'updateHook');
+		}
 	}
 
 	/**
@@ -463,6 +479,7 @@ class OC_Mount_Config {
 										 $priority = null) {
 		$backends = self::getBackends();
 		$mountPoint = OC\Files\Filesystem::normalizePath($mountPoint);
+		$relMountPoint = $mountPoint;
 		if ($mountPoint === '' || $mountPoint === '/') {
 			// can't mount at root folder
 			return false;
@@ -495,6 +512,10 @@ class OC_Mount_Config {
 		}
 
 		$mountPoints = self::readData($isPersonal ? OCP\User::getUser() : NULL);
+		// who else loves multi-dimensional array ?
+		$isNew = !isset($mountPoints[$mountType]) ||
+			!isset($mountPoints[$mountType][$applicable]) ||
+			!isset($mountPoints[$mountType][$applicable][$mountPoint]);
 		$mountPoints = self::mergeMountPoints($mountPoints, $mount, $mountType);
 
 		// Set default priority if none set
@@ -510,7 +531,19 @@ class OC_Mount_Config {
 
 		self::writeData($isPersonal ? OCP\User::getUser() : NULL, $mountPoints);
 
-		return self::getBackendStatus($class, $classOptions, $isPersonal);
+		$result = self::getBackendStatus($class, $classOptions, $isPersonal);
+		if ($result && $isNew) {
+			\OC_Hook::emit(
+				\OC\Files\Filesystem::CLASSNAME,
+				\OC\Files\Filesystem::signal_create_mount,
+				array(
+					\OC\Files\Filesystem::signal_param_path => $relMountPoint,
+					\OC\Files\Filesystem::signal_param_mount_type => $mountType,
+					\OC\Files\Filesystem::signal_param_users => $applicable,
+				)
+			);
+		}
+		return $result;
 	}
 
 	/**
@@ -523,6 +556,7 @@ class OC_Mount_Config {
 	*/
 	public static function removeMountPoint($mountPoint, $mountType, $applicable, $isPersonal = false) {
 		// Verify that the mount point applies for the current user
+		$relMountPoints = $mountPoint;
 		if ($isPersonal) {
 			if ($applicable != OCP\User::getUser()) {
 				return false;
@@ -543,6 +577,15 @@ class OC_Mount_Config {
 			}
 		}
 		self::writeData($isPersonal ? OCP\User::getUser() : NULL, $mountPoints);
+		\OC_Hook::emit(
+			\OC\Files\Filesystem::CLASSNAME,
+			\OC\Files\Filesystem::signal_delete_mount,
+			array(
+				\OC\Files\Filesystem::signal_param_path => $relMountPoints,
+				\OC\Files\Filesystem::signal_param_mount_type => $mountType,
+				\OC\Files\Filesystem::signal_param_users => $applicable,
+			)
+		);
 		return true;
 	}
 
diff --git a/apps/files_external/lib/etagpropagator.php b/apps/files_external/lib/etagpropagator.php
new file mode 100644
index 0000000000000000000000000000000000000000..80a3849b150d2effb128f9e0dd3c19b99cf6cad0
--- /dev/null
+++ b/apps/files_external/lib/etagpropagator.php
@@ -0,0 +1,126 @@
+<?php
+/**
+ * Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace OCA\Files_External;
+
+use OC\Files\Filesystem;
+
+/**
+ * Updates the etag of parent folders whenever a new external storage mount
+ * point has been created or deleted. Updates need to be triggered using
+ * the updateHook() method.
+ *
+ * There are two modes of operation:
+ * - for personal mount points, the etag is propagated directly
+ * - for system mount points, a dirty flag is saved in the configuration and
+ * the etag will be updated the next time propagateDirtyMountPoints() is called
+ */
+class EtagPropagator {
+	/**
+	 * @var \OCP\IUser
+	 */
+	protected $user;
+
+	/**
+	 * @var \OC\Files\Cache\ChangePropagator
+	 */
+	protected $changePropagator;
+
+	/**
+	 * @var \OCP\IConfig
+	 */
+	protected $config;
+
+	/**
+	 * @param \OCP\IUser $user current user, must match the propagator's
+	 * user
+	 * @param \OC\Files\Cache\ChangePropagator $changePropagator change propagator
+	 * initialized with a view for $user
+	 * @param \OCP\IConfig $config
+	 */
+	public function __construct($user, $changePropagator, $config) {
+		$this->user = $user;
+		$this->changePropagator = $changePropagator;
+		$this->config = $config;
+	}
+
+	/**
+	 * Propagate the etag changes for all mountpoints marked as dirty and mark the mountpoints as clean
+	 *
+	 * @param int $time
+	 */
+	public function propagateDirtyMountPoints($time = null) {
+		if ($time === null) {
+			$time = time();
+		}
+		$mountPoints = $this->getDirtyMountPoints();
+		foreach ($mountPoints as $mountPoint) {
+			$this->changePropagator->addChange($mountPoint);
+			$this->config->setUserValue($this->user->getUID(), 'files_external', $mountPoint, $time);
+		}
+		if (count($mountPoints)) {
+			$this->changePropagator->propagateChanges($time);
+		}
+	}
+
+	/**
+	 * Get all mountpoints we need to update the etag for
+	 *
+	 * @return string[]
+	 */
+	protected function getDirtyMountPoints() {
+		$dirty = array();
+		$mountPoints = $this->config->getAppKeys('files_external');
+		foreach ($mountPoints as $mountPoint) {
+			if (substr($mountPoint, 0, 1) === '/') {
+				$updateTime = $this->config->getAppValue('files_external', $mountPoint);
+				$userTime = $this->config->getUserValue($this->user->getUID(), 'files_external', $mountPoint);
+				if ($updateTime > $userTime) {
+					$dirty[] = $mountPoint;
+				}
+			}
+		}
+		return $dirty;
+	}
+
+	/**
+	 * @param string $mountPoint
+	 * @param int $time
+	 */
+	protected function markDirty($mountPoint, $time = null) {
+		if ($time === null) {
+			$time = time();
+		}
+		$this->config->setAppValue('files_external', $mountPoint, $time);
+	}
+
+	/**
+	 * Update etags for mount points for known user
+	 * For global or group mount points, updating the etag for every user is not feasible
+	 * instead we mark the mount point as dirty and update the etag when the filesystem is loaded for the user
+	 * For personal mount points, the change is propagated directly
+	 *
+	 * @param array $params hook parameters
+	 * @param int $time update time to use when marking a mount point as dirty
+	 */
+	public function updateHook($params, $time = null) {
+		if ($time === null) {
+			$time = time();
+		}
+		$users = $params[Filesystem::signal_param_users];
+		$type = $params[Filesystem::signal_param_mount_type];
+		$mountPoint = $params[Filesystem::signal_param_path];
+		$mountPoint = Filesystem::normalizePath($mountPoint);
+		if ($type === \OC_Mount_Config::MOUNT_TYPE_GROUP or $users === 'all') {
+			$this->markDirty($mountPoint, $time);
+		} else {
+			$this->changePropagator->addChange($mountPoint);
+			$this->changePropagator->propagateChanges($time);
+		}
+	}
+}
diff --git a/apps/files_external/tests/etagpropagator.php b/apps/files_external/tests/etagpropagator.php
new file mode 100644
index 0000000000000000000000000000000000000000..7fa1863f9627ee95cab04a64ca45c4795258ecf3
--- /dev/null
+++ b/apps/files_external/tests/etagpropagator.php
@@ -0,0 +1,328 @@
+<?php
+/**
+ * Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace Tests\Files_External;
+
+use OC\Files\Filesystem;
+use OC\User\User;
+
+class EtagPropagator extends \PHPUnit_Framework_TestCase {
+	protected function getUser() {
+		return new User(uniqid(), null);
+	}
+
+	/**
+	 * @return \PHPUnit_Framework_MockObject_MockObject | \OC\Files\Cache\ChangePropagator
+	 */
+	protected function getChangePropagator() {
+		return $this->getMockBuilder('\OC\Files\Cache\ChangePropagator')
+			->disableOriginalConstructor()
+			->getMock();
+	}
+
+	/**
+	 * @return \PHPUnit_Framework_MockObject_MockObject | \OCP\IConfig
+	 */
+	protected function getConfig() {
+		$appConfig = array();
+		$userConfig = array();
+		$mock = $this->getMockBuilder('\OCP\IConfig')
+			->disableOriginalConstructor()
+			->getMock();
+
+		$mock->expects($this->any())
+			->method('getAppValue')
+			->will($this->returnCallback(function ($appId, $key, $default = null) use (&$appConfig) {
+				if (isset($appConfig[$appId]) and isset($appConfig[$appId][$key])) {
+					return $appConfig[$appId][$key];
+				} else {
+					return $default;
+				}
+			}));
+		$mock->expects($this->any())
+			->method('setAppValue')
+			->will($this->returnCallback(function ($appId, $key, $value) use (&$appConfig) {
+				if (!isset($appConfig[$appId])) {
+					$appConfig[$appId] = array();
+				}
+				$appConfig[$appId][$key] = $value;
+			}));
+		$mock->expects($this->any())
+			->method('getAppKeys')
+			->will($this->returnCallback(function ($appId) use (&$appConfig) {
+				if (!isset($appConfig[$appId])) {
+					$appConfig[$appId] = array();
+				}
+				return array_keys($appConfig[$appId]);
+			}));
+
+		$mock->expects($this->any())
+			->method('getUserValue')
+			->will($this->returnCallback(function ($userId, $appId, $key, $default = null) use (&$userConfig) {
+				if (isset($userConfig[$userId]) and isset($userConfig[$userId][$appId]) and isset($userConfig[$userId][$appId][$key])) {
+					return $userConfig[$userId][$appId][$key];
+				} else {
+					return $default;
+				}
+			}));
+		$mock->expects($this->any())
+			->method('setUserValue')
+			->will($this->returnCallback(function ($userId, $appId, $key, $value) use (&$userConfig) {
+				if (!isset($userConfig[$userId])) {
+					$userConfig[$userId] = array();
+				}
+				if (!isset($userConfig[$userId][$appId])) {
+					$userConfig[$userId][$appId] = array();
+				}
+				$userConfig[$userId][$appId][$key] = $value;
+			}));
+
+		return $mock;
+	}
+
+	public function testSingleUserMount() {
+		$time = time();
+		$user = $this->getUser();
+		$config = $this->getConfig();
+		$changePropagator = $this->getChangePropagator();
+		$propagator = new \OCA\Files_External\EtagPropagator($user, $changePropagator, $config);
+
+		$changePropagator->expects($this->once())
+			->method('addChange')
+			->with('/test');
+		$changePropagator->expects($this->once())
+			->method('propagateChanges')
+			->with($time);
+
+		$propagator->updateHook(array(
+			Filesystem::signal_param_path => '/test',
+			Filesystem::signal_param_mount_type => \OC_Mount_Config::MOUNT_TYPE_USER,
+			Filesystem::signal_param_users => $user->getUID(),
+		), $time);
+	}
+
+	public function testGlobalMountNoDirectUpdate() {
+		$time = time();
+		$user = $this->getUser();
+		$config = $this->getConfig();
+		$changePropagator = $this->getChangePropagator();
+		$propagator = new \OCA\Files_External\EtagPropagator($user, $changePropagator, $config);
+
+		// not updated directly
+		$changePropagator->expects($this->never())
+			->method('addChange');
+		$changePropagator->expects($this->never())
+			->method('propagateChanges');
+
+		$propagator->updateHook(array(
+			Filesystem::signal_param_path => '/test',
+			Filesystem::signal_param_mount_type => \OC_Mount_Config::MOUNT_TYPE_USER,
+			Filesystem::signal_param_users => 'all',
+		), $time);
+
+		// mount point marked as dirty
+		$this->assertEquals(array('/test'), $config->getAppKeys('files_external'));
+		$this->assertEquals($time, $config->getAppValue('files_external', '/test'));
+	}
+
+	public function testGroupMountNoDirectUpdate() {
+		$time = time();
+		$user = $this->getUser();
+		$config = $this->getConfig();
+		$changePropagator = $this->getChangePropagator();
+		$propagator = new \OCA\Files_External\EtagPropagator($user, $changePropagator, $config);
+
+		// not updated directly
+		$changePropagator->expects($this->never())
+			->method('addChange');
+		$changePropagator->expects($this->never())
+			->method('propagateChanges');
+
+		$propagator->updateHook(array(
+			Filesystem::signal_param_path => '/test',
+			Filesystem::signal_param_mount_type => \OC_Mount_Config::MOUNT_TYPE_GROUP,
+			Filesystem::signal_param_users => 'test',
+		), $time);
+
+		// mount point marked as dirty
+		$this->assertEquals(array('/test'), $config->getAppKeys('files_external'));
+		$this->assertEquals($time, $config->getAppValue('files_external', '/test'));
+	}
+
+	public function testGlobalMountNoDirtyMountPoint() {
+		$time = time();
+		$user = $this->getUser();
+		$config = $this->getConfig();
+		$changePropagator = $this->getChangePropagator();
+		$propagator = new \OCA\Files_External\EtagPropagator($user, $changePropagator, $config);
+
+		$changePropagator->expects($this->never())
+			->method('addChange');
+		$changePropagator->expects($this->never())
+			->method('propagateChanges');
+
+		$propagator->propagateDirtyMountPoints($time);
+
+		$this->assertEquals(0, $config->getUserValue($user->getUID(), 'files_external', '/test', 0));
+	}
+
+	public function testGlobalMountDirtyMountPointFirstTime() {
+		$time = time();
+		$user = $this->getUser();
+		$config = $this->getConfig();
+		$changePropagator = $this->getChangePropagator();
+		$propagator = new \OCA\Files_External\EtagPropagator($user, $changePropagator, $config);
+
+		$config->setAppValue('files_external', '/test', $time - 10);
+
+		$changePropagator->expects($this->once())
+			->method('addChange')
+			->with('/test');
+		$changePropagator->expects($this->once())
+			->method('propagateChanges')
+			->with($time);
+
+		$propagator->propagateDirtyMountPoints($time);
+
+		$this->assertEquals($time, $config->getUserValue($user->getUID(), 'files_external', '/test'));
+	}
+
+	public function testGlobalMountNonDirtyMountPoint() {
+		$time = time();
+		$user = $this->getUser();
+		$config = $this->getConfig();
+		$changePropagator = $this->getChangePropagator();
+		$propagator = new \OCA\Files_External\EtagPropagator($user, $changePropagator, $config);
+
+		$config->setAppValue('files_external', '/test', $time - 10);
+		$config->setUserValue($user->getUID(), 'files_external', '/test', $time - 10);
+
+		$changePropagator->expects($this->never())
+			->method('addChange');
+		$changePropagator->expects($this->never())
+			->method('propagateChanges');
+
+		$propagator->propagateDirtyMountPoints($time);
+
+		$this->assertEquals($time - 10, $config->getUserValue($user->getUID(), 'files_external', '/test'));
+	}
+
+	public function testGlobalMountNonDirtyMountPointOtherUser() {
+		$time = time();
+		$user = $this->getUser();
+		$user2 = $this->getUser();
+		$config = $this->getConfig();
+		$changePropagator = $this->getChangePropagator();
+		$propagator = new \OCA\Files_External\EtagPropagator($user, $changePropagator, $config);
+
+		$config->setAppValue('files_external', '/test', $time - 10);
+		$config->setUserValue($user2->getUID(), 'files_external', '/test', $time - 10);
+
+		$changePropagator->expects($this->once())
+			->method('addChange')
+			->with('/test');
+		$changePropagator->expects($this->once())
+			->method('propagateChanges')
+			->with($time);
+
+		$propagator->propagateDirtyMountPoints($time);
+
+		$this->assertEquals($time, $config->getUserValue($user->getUID(), 'files_external', '/test'));
+	}
+
+	public function testGlobalMountDirtyMountPointSecondTime() {
+		$time = time();
+		$user = $this->getUser();
+		$config = $this->getConfig();
+		$changePropagator = $this->getChangePropagator();
+		$propagator = new \OCA\Files_External\EtagPropagator($user, $changePropagator, $config);
+
+		$config->setAppValue('files_external', '/test', $time - 10);
+		$config->setUserValue($user->getUID(), 'files_external', '/test', $time - 20);
+
+		$changePropagator->expects($this->once())
+			->method('addChange')
+			->with('/test');
+		$changePropagator->expects($this->once())
+			->method('propagateChanges')
+			->with($time);
+
+		$propagator->propagateDirtyMountPoints($time);
+
+		$this->assertEquals($time, $config->getUserValue($user->getUID(), 'files_external', '/test'));
+	}
+
+	public function testGlobalMountMultipleUsers() {
+		$time = time();
+		$config = $this->getConfig();
+		$user1 = $this->getUser();
+		$user2 = $this->getUser();
+		$user3 = $this->getUser();
+		$changePropagator1 = $this->getChangePropagator();
+		$changePropagator2 = $this->getChangePropagator();
+		$changePropagator3 = $this->getChangePropagator();
+		$propagator1 = new \OCA\Files_External\EtagPropagator($user1, $changePropagator1, $config);
+		$propagator2 = new \OCA\Files_External\EtagPropagator($user2, $changePropagator2, $config);
+		$propagator3 = new \OCA\Files_External\EtagPropagator($user3, $changePropagator3, $config);
+
+		$config->setAppValue('files_external', '/test', $time - 10);
+
+		$changePropagator1->expects($this->once())
+			->method('addChange')
+			->with('/test');
+		$changePropagator1->expects($this->once())
+			->method('propagateChanges')
+			->with($time);
+
+		$propagator1->propagateDirtyMountPoints($time);
+
+		$this->assertEquals($time, $config->getUserValue($user1->getUID(), 'files_external', '/test'));
+		$this->assertEquals(0, $config->getUserValue($user2->getUID(), 'files_external', '/test', 0));
+		$this->assertEquals(0, $config->getUserValue($user3->getUID(), 'files_external', '/test', 0));
+
+		$changePropagator2->expects($this->once())
+			->method('addChange')
+			->with('/test');
+		$changePropagator2->expects($this->once())
+			->method('propagateChanges')
+			->with($time);
+
+		$propagator2->propagateDirtyMountPoints($time);
+
+		$this->assertEquals($time, $config->getUserValue($user1->getUID(), 'files_external', '/test'));
+		$this->assertEquals($time, $config->getUserValue($user2->getUID(), 'files_external', '/test', 0));
+		$this->assertEquals(0, $config->getUserValue($user3->getUID(), 'files_external', '/test', 0));
+	}
+
+	public function testGlobalMountMultipleDirtyMountPoints() {
+		$time = time();
+		$user = $this->getUser();
+		$config = $this->getConfig();
+		$changePropagator = $this->getChangePropagator();
+		$propagator = new \OCA\Files_External\EtagPropagator($user, $changePropagator, $config);
+
+		$config->setAppValue('files_external', '/test', $time - 10);
+		$config->setAppValue('files_external', '/foo', $time - 50);
+		$config->setAppValue('files_external', '/bar', $time - 70);
+
+		$config->setUserValue($user->getUID(), 'files_external', '/foo', $time - 70);
+		$config->setUserValue($user->getUID(), 'files_external', '/bar', $time - 70);
+
+		$changePropagator->expects($this->exactly(2))
+			->method('addChange');
+		$changePropagator->expects($this->once())
+			->method('propagateChanges')
+			->with($time);
+
+		$propagator->propagateDirtyMountPoints($time);
+
+		$this->assertEquals($time, $config->getUserValue($user->getUID(), 'files_external', '/test'));
+		$this->assertEquals($time, $config->getUserValue($user->getUID(), 'files_external', '/foo'));
+		$this->assertEquals($time - 70, $config->getUserValue($user->getUID(), 'files_external', '/bar'));
+	}
+}
diff --git a/apps/files_external/tests/mountconfig.php b/apps/files_external/tests/mountconfig.php
index fc482823843a8983157b1cebb5a01f28a4b39297..c11e48b82f34598a732c21e79a4304fd1546bfea 100644
--- a/apps/files_external/tests/mountconfig.php
+++ b/apps/files_external/tests/mountconfig.php
@@ -26,6 +26,42 @@ class Test_Mount_Config_Dummy_Storage {
 	}
 }
 
+class Test_Mount_Config_Hook_Test {
+	static $signal;
+	static $params;
+
+	public static function setUpHooks() {
+		self::clear();
+		\OCP\Util::connectHook(
+			\OC\Files\Filesystem::CLASSNAME,
+			\OC\Files\Filesystem::signal_create_mount,
+			'\Test_Mount_Config_Hook_Test', 'createHookCallback');
+		\OCP\Util::connectHook(
+			\OC\Files\Filesystem::CLASSNAME,
+			\OC\Files\Filesystem::signal_delete_mount,
+			'\Test_Mount_Config_Hook_Test', 'deleteHookCallback');
+	}
+
+	public static function clear() {
+		self::$signal = null;
+		self::$params = null;
+	}
+
+	public static function createHookCallback($params) {
+		self::$signal = \OC\Files\Filesystem::signal_create_mount;
+		self::$params = $params;
+	}
+
+	public static function deleteHookCallback($params) {
+		self::$signal = \OC\Files\Filesystem::signal_delete_mount;
+		self::$params = $params;
+	}
+
+	public static function getLastCall() {
+		return array(self::$signal, self::$params);
+	}
+}
+
 /**
  * Class Test_Mount_Config
  */
@@ -77,9 +113,11 @@ class Test_Mount_Config extends \PHPUnit_Framework_TestCase {
 		);
 
 		OC_Mount_Config::$skipTest = true;
+		Test_Mount_Config_Hook_Test::setupHooks();
 	}
 
 	public function tearDown() {
+		Test_Mount_Config_Hook_Test::clear();
 		OC_Mount_Config::$skipTest = false;
 
 		\OC_User::deleteUser(self::TEST_USER2);
@@ -337,6 +375,102 @@ class Test_Mount_Config extends \PHPUnit_Framework_TestCase {
 		$this->assertEquals(array_keys($options), array_keys($savedOptions));
 	}
 
+	public function testHooks() {
+		$mountPoint = '/test';
+		$mountType = 'user';
+		$applicable = 'all';
+		$isPersonal = false;
+
+		$mountConfig = array(
+			'host' => 'smbhost',
+			'user' => 'smbuser',
+			'password' => 'smbpassword',
+			'share' => 'smbshare',
+			'root' => 'smbroot'
+		);
+
+		// write config
+		$this->assertTrue(
+			OC_Mount_Config::addMountPoint(
+				$mountPoint,
+				'\OC\Files\Storage\SMB',
+				$mountConfig,
+				$mountType,
+				$applicable,
+				$isPersonal
+			)
+		);
+
+		list($hookName, $params) = Test_Mount_Config_Hook_Test::getLastCall();
+		$this->assertEquals(
+			\OC\Files\Filesystem::signal_create_mount,
+			$hookName
+		);
+		$this->assertEquals(
+			$mountPoint,
+			$params[\OC\Files\Filesystem::signal_param_path]
+		);
+		$this->assertEquals(
+			$mountType,
+			$params[\OC\Files\Filesystem::signal_param_mount_type]
+		);
+		$this->assertEquals(
+			$applicable,
+			$params[\OC\Files\Filesystem::signal_param_users]
+		);
+
+		Test_Mount_Config_Hook_Test::clear();
+
+		// edit
+		$mountConfig['host'] = 'anothersmbhost';
+		$this->assertTrue(
+			OC_Mount_Config::addMountPoint(
+				$mountPoint,
+				'\OC\Files\Storage\SMB',
+				$mountConfig,
+				$mountType,
+				$applicable,
+				$isPersonal
+			)
+		);
+
+		// hook must not be called on edit
+		list($hookName, $params) = Test_Mount_Config_Hook_Test::getLastCall();
+		$this->assertEquals(
+			null,
+			$hookName
+		);
+
+		Test_Mount_Config_Hook_Test::clear();
+
+		$this->assertTrue(
+			OC_Mount_Config::removeMountPoint(
+				$mountPoint,
+				$mountType,
+				$applicable,
+				$isPersonal
+			)
+		);
+
+		list($hookName, $params) = Test_Mount_Config_Hook_Test::getLastCall();
+		$this->assertEquals(
+			\OC\Files\Filesystem::signal_delete_mount,
+			$hookName
+		);
+		$this->assertEquals(
+			$mountPoint,
+			$params[\OC\Files\Filesystem::signal_param_path]
+		);
+		$this->assertEquals(
+			$mountType,
+			$params[\OC\Files\Filesystem::signal_param_mount_type]
+		);
+		$this->assertEquals(
+			$applicable,
+			$params[\OC\Files\Filesystem::signal_param_users]
+		);
+	}
+
 	/**
 	 * Test password obfuscation
 	 */
diff --git a/lib/private/allconfig.php b/lib/private/allconfig.php
index 721ec337ff8c7fa06c34d3b052fcc01faab05c1e..7ebff7cf2db8629d78f621c815ed353ea95122f8 100644
--- a/lib/private/allconfig.php
+++ b/lib/private/allconfig.php
@@ -43,6 +43,15 @@ class AllConfig implements \OCP\IConfig {
 		\OCP\Config::deleteSystemValue($key);
 	}
 
+	/**
+	 * Get all keys stored for an app
+	 *
+	 * @param string $appName the appName that we stored the value under
+	 * @return string[] the keys stored for the app
+	 */
+	public function getAppKeys($appName) {
+		return \OC::$server->getAppConfig()->getKeys($appName);
+	}
 
 	/**
 	 * Writes a new app wide value
diff --git a/lib/private/files/filesystem.php b/lib/private/files/filesystem.php
index db46bcfd1ea1564edb0c417cec1dff5da5539a8f..cdbbbf3d3cd10ab90277ea528eb4b4af0a845f3a 100644
--- a/lib/private/files/filesystem.php
+++ b/lib/private/files/filesystem.php
@@ -158,6 +158,11 @@ class Filesystem {
 	 */
 	const signal_param_run = 'run';
 
+	const signal_create_mount = 'create_mount';
+	const signal_delete_mount = 'delete_mount';
+	const signal_param_mount_type = 'mounttype';
+	const signal_param_users = 'users';
+
 	/**
 	 * @var \OC\Files\Storage\Loader $loader
 	 */
diff --git a/lib/public/iconfig.php b/lib/public/iconfig.php
index 755da09ee6ba0a3cb817627db56ffa0cf9819e80..404cf030dee998de37145918a34e89152d36b350 100644
--- a/lib/public/iconfig.php
+++ b/lib/public/iconfig.php
@@ -58,6 +58,13 @@ interface IConfig {
 	 */
 	public function deleteSystemValue($key);
 
+	/**
+	 * Get all keys stored for an app
+	 *
+	 * @param string $appName the appName that we stored the value under
+	 * @return string[] the keys stored for the app
+	 */
+	public function getAppKeys($appName);
 
 	/**
 	 * Writes a new app wide value