diff --git a/apps/files/lib/helper.php b/apps/files/lib/helper.php
index 7d8906e22514b9f9383685519839a7a7682c2250..b84b6c06d30c22e70885a4ca43e3026949f1c40c 100644
--- a/apps/files/lib/helper.php
+++ b/apps/files/lib/helper.php
@@ -113,7 +113,7 @@ class Helper
 		if (\OC::$server->getPreviewManager()->isMimeSupported($i['mimetype'])) {
 			$entry['isPreviewAvailable'] = true;
 		}
-		$entry['name'] = $i['name'];
+		$entry['name'] = $i->getName();
 		$entry['permissions'] = $i['permissions'];
 		$entry['mimetype'] = $i['mimetype'];
 		$entry['size'] = $i['size'];
diff --git a/apps/files/tests/ajax_rename.php b/apps/files/tests/ajax_rename.php
index 9928053e5015ac0861f604e5a84cd76b1c771e97..fed366aa8ebc9f3bb697dab23ff45acbb235e15f 100644
--- a/apps/files/tests/ajax_rename.php
+++ b/apps/files/tests/ajax_rename.php
@@ -81,7 +81,7 @@ class Test_OC_Files_App_Rename extends \PHPUnit_Framework_TestCase {
 		$this->viewMock->expects($this->any())
 			->method('getFileInfo')
 			->will($this->returnValue(new \OC\Files\FileInfo(
-				'/',
+				'/new_name',
 				new \OC\Files\Storage\Local(array('datadir' => '/')),
 				'/',
 				array(
diff --git a/apps/files/tests/helper.php b/apps/files/tests/helper.php
index 9b3603cd5633197d272898ac71d0744ddeb2ffcb..f269cc70ed55e7dc57df10e61197a3abb49d31f4 100644
--- a/apps/files/tests/helper.php
+++ b/apps/files/tests/helper.php
@@ -17,7 +17,7 @@ class Test_Files_Helper extends \PHPUnit_Framework_TestCase {
 
 	private function makeFileInfo($name, $size, $mtime, $isDir = false) {
 		return new \OC\Files\FileInfo(
-			'/',
+			'/' . $name,
 			null,
 			'/',
 			array(
diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php
index 66e2bccd59fda41ab621704b1d3220ae37e5e9ef..f546ef723739ee2219f05948f7d7c06ecc0338ec 100644
--- a/apps/files_encryption/hooks/hooks.php
+++ b/apps/files_encryption/hooks/hooks.php
@@ -34,6 +34,8 @@ class Hooks {
 	private static $renamedFiles = array();
 	// file for which we want to delete the keys after the delete operation was successful
 	private static $deleteFiles = array();
+	// file for which we want to delete the keys after the delete operation was successful
+	private static $umountedFiles = array();
 
 	/**
 	 * Startup encryption backend upon user login
@@ -610,4 +612,57 @@ class Hooks {
 			'path' => $ownerPath);
 	}
 
+	/**
+	 * remember files/folders which get unmounted
+	 */
+	public static function preUmount($params) {
+		$path = $params[\OC\Files\Filesystem::signal_param_path];
+		$user = \OCP\USER::getUser();
+
+		$view = new \OC\Files\View();
+		$itemType = $view->is_dir('/' . $user . '/files' . $path) ? 'folder' : 'file';
+
+		$util = new Util($view, $user);
+		list($owner, $ownerPath) = $util->getUidAndFilename($path);
+
+		self::$umountedFiles[$params[\OC\Files\Filesystem::signal_param_path]] = array(
+			'uid' => $owner,
+			'path' => $ownerPath,
+			'itemType' => $itemType);
+	}
+
+	public static function postUmount($params) {
+
+		if (!isset(self::$umountedFiles[$params[\OC\Files\Filesystem::signal_param_path]])) {
+			return true;
+		}
+
+		$umountedFile = self::$umountedFiles[$params[\OC\Files\Filesystem::signal_param_path]];
+		$path = $umountedFile['path'];
+		$user = $umountedFile['uid'];
+		$itemType = $umountedFile['itemType'];
+
+		$view = new \OC\Files\View();
+		$util = new Util($view, $user);
+
+		// we don't need to remember the file any longer
+		unset(self::$umountedFiles[$params[\OC\Files\Filesystem::signal_param_path]]);
+
+		// if we unshare a folder we need a list of all (sub-)files
+		if ($itemType === 'folder') {
+			$allFiles = $util->getAllFiles($path);
+		} else {
+			$allFiles = array($path);
+		}
+
+		foreach ($allFiles as $path) {
+
+			// check if the user still has access to the file, otherwise delete share key
+			$sharingUsers = \OCP\Share::getUsersSharingFile($path, $user);
+			if (!in_array(\OCP\User::getUser(), $sharingUsers['users'])) {
+				Keymanager::delShareKey($view, array(\OCP\User::getUser()), $path);
+			}
+		}
+	}
+
 }
diff --git a/apps/files_encryption/lib/helper.php b/apps/files_encryption/lib/helper.php
index 564e97e0592765dcea1878b25dd45e6b66d65837..2684bf7be3377a45d6196c3e81d81cf58b522c32 100755
--- a/apps/files_encryption/lib/helper.php
+++ b/apps/files_encryption/lib/helper.php
@@ -65,6 +65,8 @@ class Helper {
 		\OCP\Util::connectHook('OC_Filesystem', 'post_rename', 'OCA\Encryption\Hooks', 'postRename');
 		\OCP\Util::connectHook('OC_Filesystem', 'post_delete', 'OCA\Encryption\Hooks', 'postDelete');
 		\OCP\Util::connectHook('OC_Filesystem', 'delete', 'OCA\Encryption\Hooks', 'preDelete');
+		\OCP\Util::connectHook('OC_Filesystem', 'post_umount', 'OCA\Encryption\Hooks', 'postUmount');
+		\OCP\Util::connectHook('OC_Filesystem', 'umount', 'OCA\Encryption\Hooks', 'preUmount');
 	}
 
 	/**
diff --git a/apps/files_encryption/tests/hooks.php b/apps/files_encryption/tests/hooks.php
index 95f5996bb8e4a6d705f342947c76b7463513378f..a2e3ea30f04a62b79f66644d1f955620fbdab0a8 100644
--- a/apps/files_encryption/tests/hooks.php
+++ b/apps/files_encryption/tests/hooks.php
@@ -257,14 +257,14 @@ class Test_Encryption_Hooks extends \PHPUnit_Framework_TestCase {
 
 		$this->assertTrue($result);
 
-		// now keys from user1s home should be gone
-		$this->assertFalse($this->rootView->file_exists(
+		// share key for user2 from user1s home should be gone, all other keys should still exists
+		$this->assertTrue($this->rootView->file_exists(
 			self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/share-keys/'
 			. $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1 . '.shareKey'));
 		$this->assertFalse($this->rootView->file_exists(
 				self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/share-keys/'
 				. $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2 . '.shareKey'));
-		$this->assertFalse($this->rootView->file_exists(
+		$this->assertTrue($this->rootView->file_exists(
 			self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/keyfiles/' . $this->filename . '.key'));
 
 		// cleanup
diff --git a/apps/files_external/lib/config.php b/apps/files_external/lib/config.php
index 28e28ffcde69642a9780b1453c855a7377b69f26..6f78e569b64162649f21564c1b1bf7307f188a13 100755
--- a/apps/files_external/lib/config.php
+++ b/apps/files_external/lib/config.php
@@ -104,8 +104,15 @@ class OC_Mount_Config {
 	 */
 	public static function initMountPointsHook($data) {
 		$mountPoints = self::getAbsoluteMountPoints($data['user']);
+		$loader = \OC\Files\Filesystem::getLoader();
+		$manager = \OC\Files\Filesystem::getMountManager();
 		foreach ($mountPoints as $mountPoint => $options) {
-			\OC\Files\Filesystem::mount($options['class'], $options['options'], $mountPoint);
+			if ($options['personal']){
+				$mount = new \OCA\Files_External\PersonalMount($options['class'], $mountPoint, $options['options'], $loader);
+			} else{
+				$mount = new \OC\Files\Mount\Mount($options['class'], $mountPoint, $options['options'], $loader);
+			}
+			$manager->addMount($mount);
 		}
 	}
 
@@ -135,6 +142,7 @@ class OC_Mount_Config {
 		// Global mount points (is this redundant?)
 		if (isset($mountConfig[self::MOUNT_TYPE_GLOBAL])) {
 			foreach ($mountConfig[self::MOUNT_TYPE_GLOBAL] as $mountPoint => $options) {
+				$options['personal'] = false;
 				$options['options'] = self::decryptPasswords($options['options']);
 				if (!isset($options['priority'])) {
 					$options['priority'] = $backends[$options['class']]['priority'];
@@ -178,6 +186,7 @@ class OC_Mount_Config {
 						foreach ($options as &$option) {
 							$option = self::setUserVars($user, $option);
 						}
+						$options['personal'] = false;
 						$options['options'] = self::decryptPasswords($options['options']);
 						if (!isset($options['priority'])) {
 							$options['priority'] = $backends[$options['class']]['priority'];
@@ -203,6 +212,7 @@ class OC_Mount_Config {
 						foreach ($options as &$option) {
 							$option = self::setUserVars($user, $option);
 						}
+						$options['personal'] = false;
 						$options['options'] = self::decryptPasswords($options['options']);
 						if (!isset($options['priority'])) {
 							$options['priority'] = $backends[$options['class']]['priority'];
@@ -224,6 +234,7 @@ class OC_Mount_Config {
 		$mountConfig = self::readData($user);
 		if (isset($mountConfig[self::MOUNT_TYPE_USER][$user])) {
 			foreach ($mountConfig[self::MOUNT_TYPE_USER][$user] as $mountPoint => $options) {
+				$options['personal'] = true;
 				$options['options'] = self::decryptPasswords($options['options']);
 
 				// Always override previous config
@@ -506,6 +517,7 @@ class OC_Mount_Config {
 		} else {
 			$mountPoint = '/$user/files/'.ltrim($mountPoint, '/');
 		}
+		$mountPoint = \OC\Files\Filesystem::normalizePath($mountPoint);
 		$mountPoints = self::readData($isPersonal ? OCP\User::getUser() : NULL);
 		// Remove mount point
 		unset($mountPoints[$mountType][$applicable][$mountPoint]);
@@ -520,6 +532,28 @@ class OC_Mount_Config {
 		return true;
 	}
 
+	/**
+	 *
+	 * @param string $mountPoint Mount point
+	 * @param string $target The new mount point
+	 * @param string $mountType MOUNT_TYPE_GROUP | MOUNT_TYPE_USER
+	 * @return bool
+	 */
+	public static function movePersonalMountPoint($mountPoint, $target, $mountType) {
+		$mountPoint = rtrim($mountPoint, '/');
+		$user = OCP\User::getUser();
+		$mountPoints = self::readData($user);
+		if (!isset($mountPoints[$mountType][$user][$mountPoint])) {
+			return false;
+		}
+		$mountPoints[$mountType][$user][$target] = $mountPoints[$mountType][$user][$mountPoint];
+		// Remove old mount point
+		unset($mountPoints[$mountType][$user][$mountPoint]);
+
+		self::writeData($user, $mountPoints);
+		return true;
+	}
+
 	/**
 	* Read the mount points in the config file into an array
 	* @param string|null $user If not null, personal for $user, otherwise system
diff --git a/apps/files_external/lib/personalmount.php b/apps/files_external/lib/personalmount.php
new file mode 100644
index 0000000000000000000000000000000000000000..708128d644ac63457a4f6772bbfa5ffc9473ed74
--- /dev/null
+++ b/apps/files_external/lib/personalmount.php
@@ -0,0 +1,40 @@
+<?php
+/**
+ * Copyright (c) 2012 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\Mount\Mount;
+use OC\Files\Mount\MoveableMount;
+
+/**
+ * Person mount points can be moved by the user
+ */
+class PersonalMount extends Mount implements MoveableMount {
+	/**
+	 * Move the mount point to $target
+	 *
+	 * @param string $target the target mount point
+	 * @return bool
+	 */
+	public function moveMount($target) {
+		$result = \OC_Mount_Config::movePersonalMountPoint($this->getMountPoint(), $target, \OC_Mount_Config::MOUNT_TYPE_USER);
+		$this->setMountPoint($target);
+		return $result;
+	}
+
+	/**
+	 * Remove the mount points
+	 *
+	 * @return bool
+	 */
+	public function removeMount() {
+		$user = \OCP\User::getUser();
+		$relativeMountPoint = substr($this->getMountPoint(), strlen('/' . $user . '/files/'));
+		return \OC_Mount_Config::removeMountPoint($relativeMountPoint, \OC_Mount_Config::MOUNT_TYPE_USER, $user , true);
+	}
+}
diff --git a/apps/files_sharing/appinfo/update.php b/apps/files_sharing/appinfo/update.php
index bc8cda42313cb929c3eca379a005f3ca91681f97..fc547ba349df17fa15503abb55495e03d8f5e9bc 100644
--- a/apps/files_sharing/appinfo/update.php
+++ b/apps/files_sharing/appinfo/update.php
@@ -1,6 +1,11 @@
 <?php
 
 $installedVersion = OCP\Config::getAppValue('files_sharing', 'installed_version');
+
+if (version_compare($installedVersion, '0.5', '<')) {
+	updateFilePermissions();
+}
+
 if (version_compare($installedVersion, '0.4', '<')) {
 	removeSharedFolder();
 }
@@ -11,6 +16,39 @@ if (version_compare($installedVersion, '0.3.5.6', '<')) {
 }
 
 
+/**
+ * it is no longer possible to share single files with delete permissions. User
+ * should only be able to unshare single files but never to delete them.
+ */
+function updateFilePermissions($chunkSize = 99) {
+	$query = OCP\DB::prepare('SELECT * FROM `*PREFIX*share` WHERE `item_type` = ?');
+	$result = $query->execute(array('file'));
+
+	$updatedRows = array();
+
+	while ($row = $result->fetchRow()) {
+		if ($row['permissions'] & \OCP\PERMISSION_DELETE) {
+			$updatedRows[$row['id']] = (int)$row['permissions'] & ~\OCP\PERMISSION_DELETE;
+		}
+	}
+
+	$chunkedPermissionList = array_chunk($updatedRows, $chunkSize, true);
+
+	foreach ($chunkedPermissionList as $subList) {
+		$statement = "UPDATE `*PREFIX*share` SET `permissions` = CASE `id` ";
+		//update share table
+		$ids = implode(',', array_keys($subList));
+		foreach ($subList as $id => $permission) {
+			$statement .= "WHEN " . $id . " THEN " . $permission . " ";
+		}
+		$statement .= ' END WHERE `id` IN (' . $ids . ')';
+
+		$query = OCP\DB::prepare($statement);
+		$query->execute();
+	}
+
+}
+
 /**
  * update script for the removal of the logical "Shared" folder, we create physical "Shared" folder and
  * update the users file_target so that it doesn't make any difference for the user
diff --git a/apps/files_sharing/appinfo/version b/apps/files_sharing/appinfo/version
index 267577d47e497a0630bc454b3f74c4fd9a10ced4..2eb3c4fe4eebcdea3da0790cc0ba74cb286ec4f4 100644
--- a/apps/files_sharing/appinfo/version
+++ b/apps/files_sharing/appinfo/version
@@ -1 +1 @@
-0.4.1
+0.5
diff --git a/apps/files_sharing/js/share.js b/apps/files_sharing/js/share.js
index d63a590fb8e60ab39144c118c1fa032a3f6d1c6d..47fe0bd2c571304508df9d8abd457c7dfa599379 100644
--- a/apps/files_sharing/js/share.js
+++ b/apps/files_sharing/js/share.js
@@ -18,12 +18,17 @@
 				var oldCreateRow = OCA.Files.FileList.prototype._createRow;
 				OCA.Files.FileList.prototype._createRow = function(fileData) {
 					var tr = oldCreateRow.apply(this, arguments);
+					var sharePermissions = fileData.permissions;
+					if (fileData.type === 'file') {
+						// files can't be shared with delete permissions
+						sharePermissions = sharePermissions & ~OC.PERMISSION_DELETE;
+					}
+					tr.attr('data-share-permissions', sharePermissions);
 					if (fileData.shareOwner) {
 						tr.attr('data-share-owner', fileData.shareOwner);
 						// user should always be able to rename a mount point
 						if (fileData.isShareMountPoint) {
 							tr.attr('data-permissions', fileData.permissions | OC.PERMISSION_UPDATE);
-							tr.attr('data-reshare-permissions', fileData.permissions);
 						}
 					}
 					if (fileData.recipientsDisplayName) {
@@ -94,7 +99,7 @@
 				if ($tr.data('type') === 'dir') {
 					itemType = 'folder';
 				}
-				var possiblePermissions = $tr.data('reshare-permissions');
+				var possiblePermissions = $tr.data('share-permissions');
 				if (_.isUndefined(possiblePermissions)) {
 					possiblePermissions = $tr.data('permissions');
 				}
diff --git a/apps/files_sharing/lib/cache.php b/apps/files_sharing/lib/cache.php
index f6c42e930d15acba11397d06870e0d9518c5151e..b2594aa0b4db5ff47a75b664d1bdacb0da787e81 100644
--- a/apps/files_sharing/lib/cache.php
+++ b/apps/files_sharing/lib/cache.php
@@ -94,6 +94,11 @@ class Shared_Cache extends Cache {
 					$data['is_share_mount_point'] = true;
 				}
 				$data['uid_owner'] = $this->storage->getOwner($file);
+				if (isset($data['permissions'])) {
+					$data['permissions'] = $data['permissions'] & $this->storage->getPermissions('');
+				} else {
+					$data['permissions'] = $this->storage->getPermissions('');
+				}
 				return $data;
 			}
 		} else {
@@ -130,6 +135,7 @@ class Shared_Cache extends Cache {
 				$data['name'] = basename($this->storage->getMountPoint());
 				$data['is_share_mount_point'] = true;
 			}
+			$data['permissions'] = $data['permissions'] & $this->storage->getPermissions('');
 			return $data;
 		}
 		return false;
@@ -157,6 +163,7 @@ class Shared_Cache extends Cache {
 				$sourceFolderContent[$key]['path'] = $dir . $c['name'];
 				$sourceFolderContent[$key]['uid_owner'] = $parent['uid_owner'];
 				$sourceFolderContent[$key]['displayname_owner'] = $parent['uid_owner'];
+				$sourceFolderContent[$key]['permissions'] = $sourceFolderContent[$key]['permissions'] & $this->storage->getPermissions('');
 			}
 
 			return $sourceFolderContent;
diff --git a/apps/files_sharing/lib/sharedmount.php b/apps/files_sharing/lib/sharedmount.php
new file mode 100644
index 0000000000000000000000000000000000000000..8d0ecbc6789be1dff9af7723f246054f3ec68b7a
--- /dev/null
+++ b/apps/files_sharing/lib/sharedmount.php
@@ -0,0 +1,161 @@
+<?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_Sharing;
+
+use OC\Files\Filesystem;
+use OC\Files\Mount\Mount;
+use OC\Files\Mount\MoveableMount;
+use OC\Files\Storage\Shared;
+
+/**
+ * Shared mount points can be moved by the user
+ */
+class SharedMount extends Mount implements MoveableMount {
+	/**
+	 * @var \OC\Files\Storage\Shared $storage
+	 */
+	protected $storage = null;
+
+	public function __construct($storage, $mountpoint, $arguments = null, $loader = null) {
+		// first update the mount point before creating the parent
+		$newMountPoint = self::verifyMountPoint($arguments['share']);
+		$absMountPoint = '/' . \OCP\User::getUser() . '/files' . $newMountPoint;
+		parent::__construct($storage, $absMountPoint, $arguments, $loader);
+	}
+
+	/**
+	 * check if the parent folder exists otherwise move the mount point up
+	 */
+	private static function verifyMountPoint(&$share) {
+
+		$mountPoint = basename($share['file_target']);
+		$parent = dirname($share['file_target']);
+
+		while (!\OC\Files\Filesystem::is_dir($parent)) {
+			$parent = dirname($parent);
+		}
+
+		$newMountPoint = \OCA\Files_Sharing\Helper::generateUniqueTarget(
+				\OC\Files\Filesystem::normalizePath($parent . '/' . $mountPoint),
+				array(),
+				new \OC\Files\View('/' . \OCP\User::getUser() . '/files')
+				);
+
+		if($newMountPoint !== $share['file_target']) {
+			self::updateFileTarget($newMountPoint, $share);
+			$share['file_target'] = $newMountPoint;
+			$share['unique_name'] = true;
+		}
+
+		return $newMountPoint;
+	}
+
+	/**
+	 * update fileTarget in the database if the mount point changed
+	 * @param string $newPath
+	 * @param array $share reference to the share which should be modified
+	 * @return type
+	 */
+	private static function updateFileTarget($newPath, &$share) {
+		// if the user renames a mount point from a group share we need to create a new db entry
+		// for the unique name
+		if ($share['share_type'] === \OCP\Share::SHARE_TYPE_GROUP && empty($share['unique_name'])) {
+			$query = \OC_DB::prepare('INSERT INTO `*PREFIX*share` (`item_type`, `item_source`, `item_target`,'
+			.' `share_type`, `share_with`, `uid_owner`, `permissions`, `stime`, `file_source`,'
+			.' `file_target`, `token`, `parent`) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)');
+			$arguments = array($share['item_type'], $share['item_source'], $share['item_target'],
+				2, \OCP\User::getUser(), $share['uid_owner'], $share['permissions'], $share['stime'], $share['file_source'],
+				$newPath, $share['token'], $share['id']);
+		} else {
+			// rename mount point
+			$query = \OC_DB::prepare(
+					'Update `*PREFIX*share`
+						SET `file_target` = ?
+						WHERE `id` = ?'
+					);
+			$arguments = array($newPath, $share['id']);
+		}
+
+		$result = $query->execute($arguments);
+
+		return $result === 1 ? true : false;
+	}
+
+	/**
+	 * Format a path to be relative to the /user/files/ directory
+	 *
+	 * @param string $path the absolute path
+	 * @return string e.g. turns '/admin/files/test.txt' into '/test.txt'
+	 */
+	private function stripUserFilesPath($path) {
+		$trimmed = ltrim($path, '/');
+		$split = explode('/', $trimmed);
+
+		// it is not a file relative to data/user/files
+		if (count($split) < 3 || $split[1] !== 'files') {
+			\OCP\Util::writeLog('file sharing',
+				'Can not strip userid and "files/" from path: ' . $path,
+				\OCP\Util::DEBUG);
+			return false;
+		}
+
+		// skip 'user' and 'files'
+		$sliced = array_slice($split, 2);
+		$relPath = implode('/', $sliced);
+
+		return '/' . $relPath;
+	}
+
+	/**
+	 * Move the mount point to $target
+	 *
+	 * @param string $target the target mount point
+	 * @return bool
+	 */
+	public function moveMount($target) {
+		// it shouldn't be possible to move a Shared storage into another one
+		list($targetStorage,) = Filesystem::resolvePath($target);
+		if ($targetStorage instanceof Shared) {
+			\OCP\Util::writeLog('file sharing',
+				'It is not allowed to move one mount point into another one',
+				\OCP\Util::DEBUG);
+			return false;
+		}
+
+		$relTargetPath = $this->stripUserFilesPath($target);
+		$share = $this->storage->getShare();
+
+		$result = $this->updateFileTarget($relTargetPath, $share);
+
+		if ($result) {
+			$this->setMountPoint($target);
+			$this->storage->setUniqueName();
+			$this->storage->setMountPoint($relTargetPath);
+
+		} else {
+			\OCP\Util::writeLog('file sharing',
+				'Could not rename mount point for shared folder "' . $this->getMountPoint() . '" to "' . $target . '"',
+				\OCP\Util::ERROR);
+		}
+
+		return $result;
+	}
+
+	/**
+	 * Remove the mount points
+	 *
+	 * @return bool
+	 */
+	public function removeMount() {
+		$storage = $this->getStorage();
+		$result =  \OCP\Share::unshareFromSelf($storage->getItemType(), $storage->getMountPoint());
+
+		return $result;
+	}
+}
diff --git a/apps/files_sharing/lib/sharedstorage.php b/apps/files_sharing/lib/sharedstorage.php
index f93982ee8577e8e8a9ca2d166ddd5cbba47c94bb..59de2dfa4c474c56c5c9e333a7f51ab9e2126180 100644
--- a/apps/files_sharing/lib/sharedstorage.php
+++ b/apps/files_sharing/lib/sharedstorage.php
@@ -22,6 +22,8 @@
  */
 
 namespace OC\Files\Storage;
+use OC\Files\Filesystem;
+use OCA\Files_Sharing\SharedMount;
 
 /**
  * Convert target path to source path and pass the function call to the correct storage provider
@@ -104,8 +106,8 @@ class Shared extends \OC\Files\Storage\Common {
 	 */
 	public function getPermissions($target = '') {
 		$permissions = $this->share['permissions'];
-		// part file are always have delete permissions
-		if (pathinfo($target, PATHINFO_EXTENSION) === 'part') {
+		// part files and the mount point always have delete permissions
+		if ($target === '' || pathinfo($target, PATHINFO_EXTENSION) === 'part') {
 			$permissions |= \OCP\PERMISSION_DELETE;
 		}
 
@@ -126,7 +128,18 @@ class Shared extends \OC\Files\Storage\Common {
 		return false;
 	}
 
+	/**
+	 * Delete the directory if DELETE permission is granted
+	 * @param string $path
+	 * @return boolean
+	 */
 	public function rmdir($path) {
+
+		// never delete a share mount point
+		if(empty($path)) {
+			return false;
+		}
+
 		if (($source = $this->getSourcePath($path)) && $this->isDeletable($path)) {
 			list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
 			return $storage->rmdir($internalPath);
@@ -254,9 +267,17 @@ class Shared extends \OC\Files\Storage\Common {
 		return false;
 	}
 
+	/**
+	 * Delete the file if DELETE permission is granted
+	 * @param string $path
+	 * @return boolean
+	 */
 	public function unlink($path) {
-		// Delete the file if DELETE permission is granted
-		$path = ($path === false) ? '' : $path;
+
+		// never delete a share mount point
+		if (empty($path)) {
+			return false;
+		}
 		if ($source = $this->getSourcePath($path)) {
 			if ($this->isDeletable($path)) {
 				list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
@@ -266,124 +287,14 @@ class Shared extends \OC\Files\Storage\Common {
 		return false;
 	}
 
-	/**
-	 * Format a path to be relative to the /user/files/ directory
-	 * @param string $path the absolute path
-	 * @return string e.g. turns '/admin/files/test.txt' into '/test.txt'
-	 */
-	private static function stripUserFilesPath($path) {
-		$trimmed = ltrim($path, '/');
-		$split = explode('/', $trimmed);
-
-		// it is not a file relative to data/user/files
-		if (count($split) < 3 || $split[1] !== 'files') {
-			\OCP\Util::writeLog('file sharing',
-					'Can not strip userid and "files/" from path: ' . $path,
-					\OCP\Util::DEBUG);
-			return false;
-		}
-
-		// skip 'user' and 'files'
-		$sliced = array_slice($split, 2);
-		$relPath = implode('/', $sliced);
-
-		return '/' . $relPath;
-	}
-
-	/**
-	 * rename a shared folder/file
-	 * @param string $sourcePath
-	 * @param string $targetPath
-	 * @return bool
-	 */
-	private function renameMountPoint($sourcePath, $targetPath) {
-
-		// it shouldn't be possible to move a Shared storage into another one
-		list($targetStorage, ) = \OC\Files\Filesystem::resolvePath($targetPath);
-		if ($targetStorage->instanceOfStorage('\OC\Files\Storage\Shared')) {
-			\OCP\Util::writeLog('file sharing',
-					'It is not allowed to move one mount point into another one',
-					\OCP\Util::DEBUG);
-			return false;
-		}
-
-		$relTargetPath = $this->stripUserFilesPath($targetPath);
-
-		if ($relTargetPath === false) {
-			\OCP\Util::writeLog('file sharing', 'Wrong target path given: ' . $targetPath, \OCP\Util::ERROR);
-			return false;
-		}
-
-		$result = self::updateFileTarget($relTargetPath, $this->share);
-
-		if ($result) {
-			// update the mount manager with the new paths
-			$mountManager = \OC\Files\Filesystem::getMountManager();
-			$mount = $mountManager->find($sourcePath);
-			$mount->setMountPoint($targetPath . '/');
-			$mountManager->addMount($mount);
-			$mountManager->removeMount($sourcePath . '/');
-			$this->setUniqueName();
-			$this->setMountPoint($relTargetPath);
-
-		} else {
-			\OCP\Util::writeLog('file sharing',
-					'Could not rename mount point for shared folder "' . $sourcePath . '" to "' . $targetPath . '"',
-					\OCP\Util::ERROR);
-		}
-
-		return (bool)$result;
-	}
-
-	/**
-	 * @update fileTarget in the database if the mount point changed
-	 * @param string $newPath
-	 * @param array $share reference to the share which should be modified
-	 * @return type
-	 */
-	private static function updateFileTarget($newPath, &$share) {
-		// if the user renames a mount point from a group share we need to create a new db entry
-		// for the unique name
-		if ($share['share_type'] === \OCP\Share::SHARE_TYPE_GROUP &&
-				(isset($share['unique_name']) && $share['unique_name'])) {
-			$query = \OC_DB::prepare('INSERT INTO `*PREFIX*share` (`item_type`, `item_source`, `item_target`,'
-			.' `share_type`, `share_with`, `uid_owner`, `permissions`, `stime`, `file_source`,'
-			.' `file_target`, `token`, `parent`) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)');
-			$arguments = array($share['item_type'], $share['item_source'], $share['item_target'],
-				2, \OCP\User::getUser(), $share['uid_owner'], $share['permissions'], $share['stime'], $share['file_source'],
-				$newPath, $share['token'], $share['id']);
-
-		} else {
-			// rename mount point
-			$query = \OC_DB::prepare(
-					'Update `*PREFIX*share`
-						SET `file_target` = ?
-						WHERE `id` = ?'
-					);
-			$arguments = array($newPath, $share['id']);
-		}
-
-		return $query->execute($arguments);
-	}
-
 	public function rename($path1, $path2) {
 
-		$sourceMountPoint = \OC\Files\Filesystem::getMountPoint($path1);
-		$targetMountPoint = \OC\Files\Filesystem::getMountPoint($path2);
-		$relPath1 = \OCA\Files_Sharing\Helper::stripUserFilesPath($path1);
-		$relPath2 = \OCA\Files_Sharing\Helper::stripUserFilesPath($path2);
-
-		// if we renamed the mount point we need to adjust the file_target in the
-		// database
-		if (\OC\Files\Filesystem::normalizePath($sourceMountPoint) === \OC\Files\Filesystem::normalizePath($path1)) {
-			return $this->renameMountPoint($path1, $path2);
-		}
+		// we need the paths relative to data/user/files
+		$relPath1 = $this->getMountPoint() . '/' . $path1;
+		$relPath2 = $this->getMountPoint() . '/' . $path2;
 
-
-		if (	// Within the same mount point, we only need UPDATE permissions
-				($sourceMountPoint === $targetMountPoint && $this->isUpdatable($sourceMountPoint)) ||
-				// otherwise DELETE and CREATE permissions required
-				($this->isDeletable($path1) && $this->isCreatable(dirname($path2)))) {
+		// check for update permissions on the share
+		if ($this->isUpdatable('')) {
 
 			$pathinfo = pathinfo($relPath1);
 			// for part files we need to ask for the owner and path from the parent directory because
@@ -486,47 +397,28 @@ class Shared extends \OC\Files\Storage\Common {
 
 	public static function setup($options) {
 		$shares = \OCP\Share::getItemsSharedWith('file');
+		$manager = Filesystem::getMountManager();
+		$loader = Filesystem::getLoader();
 		if (!\OCP\User::isLoggedIn() || \OCP\User::getUser() != $options['user']
 			|| $shares
 		) {
 			foreach ($shares as $share) {
-				self::verifyMountPoint($share);
-				\OC\Files\Filesystem::mount('\OC\Files\Storage\Shared',
-						array(
-							'share' => $share,
-							),
-						$options['user_dir'] . '/' . $share['file_target']);
+				// don't mount shares where we have no permissions
+				if ($share['permissions'] > 0) {
+					$mount = new SharedMount(
+							'\OC\Files\Storage\Shared',
+							$options['user_dir'] . '/' . $share['file_target'],
+							array(
+								'share' => $share,
+								),
+							$loader
+							);
+					$manager->addMount($mount);
+				}
 			}
 		}
 	}
 
-	/**
-	 * check if the parent folder exists otherwise move the mount point up
-	 *
-	 * @param array $share reference to the share we want to check
-	 */
-	private static function verifyMountPoint(&$share) {
-		$mountPoint = basename($share['file_target']);
-		$parent = dirname($share['file_target']);
-
-		while (!\OC\Files\Filesystem::is_dir($parent)) {
-			$parent = dirname($parent);
-		}
-
-		$newMountPoint = \OCA\Files_Sharing\Helper::generateUniqueTarget(
-				\OC\Files\Filesystem::normalizePath($parent . '/' . $mountPoint),
-				array(),
-				new \OC\Files\View('/' . \OCP\User::getUser() . '/files')
-				);
-
-		if($newMountPoint !== $share['file_target']) {
-
-			self::updateFileTarget($newMountPoint, $share);
-			$share['file_target'] = $newMountPoint;
-
-		}
-	}
-
 	/**
 	 * return mount point of share, relative to data/user/files
 	 *
@@ -536,28 +428,54 @@ class Shared extends \OC\Files\Storage\Common {
 		return $this->share['file_target'];
 	}
 
-	private function setMountPoint($path) {
+	public function setMountPoint($path) {
 		$this->share['file_target'] = $path;
 	}
 
+	public function getShareType() {
+		return $this->share['share_type'];
+	}
+
+	/**
+	 * does the group share already has a user specific unique name
+	 * @return bool
+	 */
+	public function uniqueNameSet() {
+		return (isset($this->share['unique_name']) && $this->share['unique_name']);
+	}
+
 	/**
 	 * the share now uses a unique name of this user
 	 *
 	 * @brief the share now uses a unique name of this user
 	 */
-	private function setUniqueName() {
+	public function setUniqueName() {
 		$this->share['unique_name'] = true;
 	}
 
 	/**
-	 * @brief get the user who shared the file
-	 *
+	 * get share ID
+	 * @return integer unique share ID
+	 */
+	public function getShareId() {
+		return $this->share['id'];
+	}
+
+	/**
+	 * get the user who shared the file
 	 * @return string
 	 */
 	public function getSharedFrom() {
 		return $this->share['uid_owner'];
 	}
 
+	/**
+	 * @return array
+	 */
+	public function getShare() {
+		return $this->share;
+	}
+
 	/**
 	 * return share type, can be "file" or "folder"
 	 * @return string
diff --git a/apps/files_sharing/tests/api.php b/apps/files_sharing/tests/api.php
index 6d0ed434ef2e9bc89f734749a8128e1d06cbf4d0..3c683afacb440a3da281332cb958fb88393f012b 100644
--- a/apps/files_sharing/tests/api.php
+++ b/apps/files_sharing/tests/api.php
@@ -784,7 +784,7 @@ class Test_Files_Sharing_Api extends Test_Files_Sharing_Base {
 		$fileInfo = $this->view->getFileInfo($this->filename);
 
 		$result = \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
-				\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2, 31);
+				\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2, \OCP\PERMISSION_ALL);
 
 		// share was successful?
 		$this->assertTrue($result);
@@ -816,9 +816,11 @@ class Test_Files_Sharing_Api extends Test_Files_Sharing_Base {
 		$this->assertTrue(is_array($linkShare));
 		$this->assertTrue(is_array($userShare));
 
-		// update permissions
+		// check if share have expected permissions, single shared files never have
+		// delete permissions
+		$this->assertEquals(\OCP\PERMISSION_ALL & ~\OCP\PERMISSION_DELETE, $userShare['permissions']);
 
-		$this->assertEquals('31', $userShare['permissions']);
+		// update permissions
 
 		$params = array();
 		$params['id'] = $userShare['id'];
@@ -893,7 +895,7 @@ class Test_Files_Sharing_Api extends Test_Files_Sharing_Base {
 		$items = \OCP\Share::getItemShared('file', null);
 
 		// make sure that we found a link share and a user share
-		$this->assertEquals(count($items), 1);
+		$this->assertEquals(1, count($items));
 
 		$linkShare = null;
 
diff --git a/apps/files_sharing/tests/permissions.php b/apps/files_sharing/tests/permissions.php
index 5ac251b0527cf59b321cceb473796dc03d4ebee1..0a222b08512253d0bbb49d7517ac79157266ac96 100644
--- a/apps/files_sharing/tests/permissions.php
+++ b/apps/files_sharing/tests/permissions.php
@@ -111,5 +111,10 @@ class Test_Files_Sharing_Permissions extends Test_Files_Sharing_Base {
 		$this->assertEquals(7, $contents[0]['permissions']);
 		$this->assertEquals('textfile1.txt', $contents[1]['name']);
 		$this->assertEquals(7, $contents[1]['permissions']);
+
+		// the share mount point should always have delete permissions to allow the user
+		// to unmount it
+		$restrictedShare = $this->secondView->getFileInfo('files/shareddirrestricted');
+		$this->assertEquals(7 | \OCP\PERMISSION_DELETE, $restrictedShare['permissions']);
 	}
 }
diff --git a/apps/files_sharing/tests/share.php b/apps/files_sharing/tests/share.php
new file mode 100644
index 0000000000000000000000000000000000000000..d3ca1816c75f7074da1bcf9d16ef31828990043c
--- /dev/null
+++ b/apps/files_sharing/tests/share.php
@@ -0,0 +1,173 @@
+<?php
+/**
+ * ownCloud
+ *
+ * @author Bjoern Schiessle
+ * @copyright 2014 Bjoern Schiessle <schiessle@owncloud.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public
+ * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+require_once __DIR__ . '/base.php';
+
+use OCA\Files\Share;
+
+/**
+ * Class Test_Files_Sharing
+ */
+class Test_Files_Sharing extends Test_Files_Sharing_Base {
+
+	const TEST_FOLDER_NAME = '/folder_share_api_test';
+
+	private static $tempStorage;
+
+	function setUp() {
+		parent::setUp();
+
+		$this->folder = self::TEST_FOLDER_NAME;
+		$this->subfolder  = '/subfolder_share_api_test';
+		$this->subsubfolder = '/subsubfolder_share_api_test';
+
+		$this->filename = '/share-api-test.txt';
+
+		// save file with content
+		$this->view->file_put_contents($this->filename, $this->data);
+		$this->view->mkdir($this->folder);
+		$this->view->mkdir($this->folder . $this->subfolder);
+		$this->view->mkdir($this->folder . $this->subfolder . $this->subsubfolder);
+		$this->view->file_put_contents($this->folder.$this->filename, $this->data);
+		$this->view->file_put_contents($this->folder . $this->subfolder . $this->filename, $this->data);
+	}
+
+	function tearDown() {
+		$this->view->unlink($this->filename);
+		$this->view->deleteAll($this->folder);
+
+		self::$tempStorage = null;
+
+		parent::tearDown();
+	}
+
+	function testUnshareFromSelf() {
+
+		\OC_Group::createGroup('testGroup');
+		\OC_Group::addToGroup(self::TEST_FILES_SHARING_API_USER2, 'testGroup');
+		\OC_Group::addToGroup(self::TEST_FILES_SHARING_API_USER3, 'testGroup');
+
+		$fileinfo = $this->view->getFileInfo($this->filename);
+
+		$pathinfo = pathinfo($this->filename);
+
+		$duplicate = '/' . $pathinfo['filename'] . ' (2).' . $pathinfo['extension'];
+
+		$result = \OCP\Share::shareItem('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
+				\Test_Files_Sharing::TEST_FILES_SHARING_API_USER2, 31);
+
+		$this->assertTrue($result);
+
+		$result = \OCP\Share::shareItem('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP,
+				'testGroup', 31);
+
+		$this->assertTrue($result);
+
+		self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
+		$this->assertTrue(\OC\Files\Filesystem::file_exists($this->filename));
+		$this->assertTrue(\OC\Files\Filesystem::file_exists($duplicate));
+
+		self::loginHelper(self::TEST_FILES_SHARING_API_USER3);
+		$this->assertTrue(\OC\Files\Filesystem::file_exists($this->filename));
+		$this->assertFalse(\OC\Files\Filesystem::file_exists($duplicate));
+
+		self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
+		\OC\Files\Filesystem::unlink($this->filename);
+		self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
+		$this->assertFalse(\OC\Files\Filesystem::file_exists($this->filename));
+		$this->assertTrue(\OC\Files\Filesystem::file_exists($duplicate));
+
+		// for user3 nothing should change
+		self::loginHelper(self::TEST_FILES_SHARING_API_USER3);
+		$this->assertTrue(\OC\Files\Filesystem::file_exists($this->filename));
+		$this->assertFalse(\OC\Files\Filesystem::file_exists($duplicate));
+
+		self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
+		\OC\Files\Filesystem::unlink($duplicate);
+		self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
+		$this->assertFalse(\OC\Files\Filesystem::file_exists($this->filename));
+		$this->assertFalse(\OC\Files\Filesystem::file_exists($duplicate));
+
+		// for user3 nothing should change
+		self::loginHelper(self::TEST_FILES_SHARING_API_USER3);
+		$this->assertTrue(\OC\Files\Filesystem::file_exists($this->filename));
+		$this->assertFalse(\OC\Files\Filesystem::file_exists($duplicate));
+
+		//cleanup
+		self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
+		\OCP\Share::unshare('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP,
+				'testGroup');
+		\OCP\Share::unshare('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
+				self::TEST_FILES_SHARING_API_USER2);
+		\OC_Group::removeFromGroup(self::TEST_FILES_SHARING_API_USER2, 'testGroup');
+		\OC_Group::removeFromGroup(self::TEST_FILES_SHARING_API_USER2, 'testGroup');
+		\OC_Group::deleteGroup('testGroup');
+
+
+	}
+
+	/**
+	 * shared files should never have delete permissions
+	 * @dataProvider  DataProviderTestFileSharePermissions
+	 */
+	function testFileSharePermissions($permission, $expectedPermissions) {
+
+		$fileinfo = $this->view->getFileInfo($this->filename);
+
+		$result = \OCP\Share::shareItem('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
+				\Test_Files_Sharing::TEST_FILES_SHARING_API_USER2, $permission);
+
+		$this->assertTrue($result);
+
+		$result = \OCP\Share::getItemShared('file', null);
+
+		$this->assertTrue(is_array($result));
+
+		// test should return exactly one shares created from testCreateShare()
+		$this->assertTrue(count($result) === 1);
+
+		$share = reset($result);
+		$this->assertSame($expectedPermissions, $share['permissions']);
+
+		\OCP\Share::unshare('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
+				\Test_Files_Sharing::TEST_FILES_SHARING_API_USER2);
+	}
+
+	function DataProviderTestFileSharePermissions() {
+		$permission1 = \OCP\PERMISSION_ALL;
+		$permission2 = \OCP\PERMISSION_DELETE;
+		$permission3 = \OCP\PERMISSION_READ;
+		$permission4 = \OCP\PERMISSION_READ | \OCP\PERMISSION_UPDATE;
+		$permission5 = \OCP\PERMISSION_READ | \OCP\PERMISSION_DELETE;
+		$permission6 = \OCP\PERMISSION_READ | \OCP\PERMISSION_UPDATE | \OCP\PERMISSION_DELETE;
+
+		return array(
+			array($permission1, \OCP\PERMISSION_ALL & ~\OCP\PERMISSION_DELETE),
+			array($permission2, 0),
+			array($permission3, $permission3),
+			array($permission4, $permission4),
+			array($permission5, $permission3),
+			array($permission6, $permission4),
+		);
+	}
+
+}
diff --git a/apps/files_sharing/tests/sharedmount.php b/apps/files_sharing/tests/sharedmount.php
new file mode 100644
index 0000000000000000000000000000000000000000..f8c657341849dc27e01d37b749510e156f21f3a6
--- /dev/null
+++ b/apps/files_sharing/tests/sharedmount.php
@@ -0,0 +1,197 @@
+<?php
+/**
+ * ownCloud
+ *
+ * @author Bjoern Schiessle
+ * @copyright 2014 Bjoern Schiessle <schiessle@owncloud.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public
+ * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+require_once __DIR__ . '/base.php';
+
+/**
+ * Class Test_Files_Sharing_Api
+ */
+class Test_Files_Sharing_Mount extends Test_Files_Sharing_Base {
+
+	function setUp() {
+		parent::setUp();
+
+		$this->folder = '/folder_share_storage_test';
+
+		$this->filename = '/share-api-storage.txt';
+
+
+		$this->view->mkdir($this->folder);
+
+		// save file with content
+		$this->view->file_put_contents($this->filename, "root file");
+		$this->view->file_put_contents($this->folder . $this->filename, "file in subfolder");
+	}
+
+	function tearDown() {
+		$this->view->unlink($this->folder);
+		$this->view->unlink($this->filename);
+
+		parent::tearDown();
+	}
+
+	/**
+	 * test if the mount point moves up if the parent folder no longer exists
+	 */
+	function testShareMountLoseParentFolder() {
+
+		// share to user
+		$fileinfo = $this->view->getFileInfo($this->folder);
+		$result = \OCP\Share::shareItem('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
+			self::TEST_FILES_SHARING_API_USER2, 31);
+
+		$statement = "UPDATE `*PREFIX*share` SET `file_target` = ? where `share_with` = ?";
+		$query = \OC_DB::prepare($statement);
+		$arguments = array('/foo/bar' . $this->folder, self::TEST_FILES_SHARING_API_USER2);
+		$query->execute($arguments);
+
+		$query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share`');
+		$result = $query->execute();
+
+		$shares = $result->fetchAll();
+
+		$this->assertSame(1, count($shares));
+
+		$share = reset($shares);
+		$this->assertSame('/foo/bar' . $this->folder, $share['file_target']);
+
+		self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
+
+		// share should have moved up
+
+		$query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share`');
+		$result = $query->execute();
+
+		$shares = $result->fetchAll();
+
+		$this->assertSame(1, count($shares));
+
+		$share = reset($shares);
+		$this->assertSame($this->folder, $share['file_target']);
+
+		//cleanup
+		self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
+		\OCP\Share::unshare('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER, self::TEST_FILES_SHARING_API_USER2);
+		$this->view->unlink($this->folder);
+	}
+
+	/**
+	 * @medium
+	 */
+	function testDeleteParentOfMountPoint() {
+
+		// share to user
+		$fileinfo = $this->view->getFileInfo($this->folder);
+		$result = \OCP\Share::shareItem('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
+			self::TEST_FILES_SHARING_API_USER2, 31);
+
+		$this->assertTrue($result);
+
+		self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
+		$user2View = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files');
+		$this->assertTrue($user2View->file_exists($this->folder));
+
+		// create a local folder
+		$result = $user2View->mkdir('localfolder');
+		$this->assertTrue($result);
+
+		// move mount point to local folder
+		$result = $user2View->rename($this->folder, '/localfolder/' . $this->folder);
+		$this->assertTrue($result);
+
+		// mount point in the root folder should no longer exist
+		$this->assertFalse($user2View->is_dir($this->folder));
+
+		// delete the local folder
+		$result = $user2View->unlink('/localfolder');
+		$this->assertTrue($result);
+
+		//enforce reload of the mount points
+		self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
+
+		//mount point should be back at the root
+		$this->assertTrue($user2View->is_dir($this->folder));
+
+		//cleanup
+		self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
+		$this->view->unlink($this->folder);
+	}
+
+	function testMoveSharedFile() {
+		$fileinfo = $this->view->getFileInfo($this->filename);
+		$result = \OCP\Share::shareItem('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
+			self::TEST_FILES_SHARING_API_USER2, 31);
+
+		self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
+
+		\OC\Files\Filesystem::rename($this->filename, "newFileName");
+
+		$this->assertTrue(\OC\Files\Filesystem::file_exists('newFileName'));
+		$this->assertFalse(\OC\Files\Filesystem::file_exists($this->filename));
+
+		self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
+		$this->assertTrue(\OC\Files\Filesystem::file_exists($this->filename));
+		$this->assertFalse(\OC\Files\Filesystem::file_exists("newFileName"));
+
+		//cleanup
+		\OCP\Share::unshare('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER, self::TEST_FILES_SHARING_API_USER2);
+	}
+
+	/**
+	 * share file with a group if a user renames the file the filename should not change
+	 * for the other users
+	 */
+	function testMoveGroupShare () {
+		\OC_Group::createGroup('testGroup');
+		\OC_Group::addToGroup(self::TEST_FILES_SHARING_API_USER1, 'testGroup');
+		\OC_Group::addToGroup(self::TEST_FILES_SHARING_API_USER2, 'testGroup');
+		\OC_Group::addToGroup(self::TEST_FILES_SHARING_API_USER3, 'testGroup');
+
+		$fileinfo = $this->view->getFileInfo($this->filename);
+		$result = \OCP\Share::shareItem('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP,
+			"testGroup", 31);
+
+		self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
+
+		$this->assertTrue(\OC\Files\Filesystem::file_exists($this->filename));
+
+		\OC\Files\Filesystem::rename($this->filename, "newFileName");
+
+		$this->assertTrue(\OC\Files\Filesystem::file_exists('newFileName'));
+		$this->assertFalse(\OC\Files\Filesystem::file_exists($this->filename));
+
+		self::loginHelper(self::TEST_FILES_SHARING_API_USER3);
+		$this->assertTrue(\OC\Files\Filesystem::file_exists($this->filename));
+		$this->assertFalse(\OC\Files\Filesystem::file_exists("newFileName"));
+
+		self::loginHelper(self::TEST_FILES_SHARING_API_USER3);
+		$this->assertTrue(\OC\Files\Filesystem::file_exists($this->filename));
+		$this->assertFalse(\OC\Files\Filesystem::file_exists("newFileName"));
+
+		//cleanup
+		\OCP\Share::unshare('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP, 'testGroup');
+		\OC_Group::removeFromGroup(self::TEST_FILES_SHARING_API_USER1, 'testGroup');
+		\OC_Group::removeFromGroup(self::TEST_FILES_SHARING_API_USER2, 'testGroup');
+		\OC_Group::removeFromGroup(self::TEST_FILES_SHARING_API_USER3, 'testGroup');
+	}
+
+}
diff --git a/apps/files_sharing/tests/update.php b/apps/files_sharing/tests/update.php
new file mode 100644
index 0000000000000000000000000000000000000000..b0215d681765718f64a72f317d37870459394911
--- /dev/null
+++ b/apps/files_sharing/tests/update.php
@@ -0,0 +1,233 @@
+<?php
+/**
+ * ownCloud
+ *
+ * @author Morris Jobke, Bjoern Schiessle
+ * @copyright 2014 Morris Jobke <morris.jobke@gmail.com>
+ *            2014 Bjoern Schiessle <schiessle@ownlcoud.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public
+ * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+require_once __DIR__ . '/../appinfo/update.php';
+require_once __DIR__ . '/base.php';
+
+/**
+ * Class Test_Files_Sharing_Update
+ */
+class Test_Files_Sharing_Update_Routine extends Test_Files_Sharing_Base {
+
+	const TEST_FOLDER_NAME = '/folder_share_api_test';
+
+	function setUp() {
+		parent::setUp();
+
+		$this->folder = self::TEST_FOLDER_NAME;
+
+		$this->filename = '/share-api-test.txt';
+
+		// save file with content
+		$this->view->file_put_contents($this->filename, $this->data);
+		$this->view->mkdir($this->folder);
+		$this->view->file_put_contents($this->folder . '/' . $this->filename, $this->data);
+	}
+
+	function tearDown() {
+		$this->view->unlink($this->filename);
+		$this->view->deleteAll($this->folder);
+
+		$removeShares = \OC_DB::prepare('DELETE FROM `*PREFIX*share`');
+		$removeShares->execute();
+		$removeItems = \OC_DB::prepare('DELETE FROM `*PREFIX*filecache`');
+		$removeItems->execute();
+
+		parent::tearDown();
+	}
+
+	/**
+	 * test update of file permission. The update should remove from all shared
+	 * files the delete permission
+	 */
+	function testUpdateFilePermissions() {
+
+		self::prepareDBUpdateFilePermissions();
+		// run the update routine to update the share permission
+		updateFilePermissions(2);
+
+		// verify results
+		$query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share`');
+		$result = $query->execute(array());
+
+		while ($row = $result->fetchRow()) {
+			if ($row['item_type'] === 'file') {
+				// for all files the delete permission should be removed
+				$this->assertSame(0, (int)$row['permissions'] & \OCP\PERMISSION_DELETE);
+			} else {
+				// for all other the permission shouldn't change
+				$this->assertSame(31, (int)$row['permissions'] & \OCP\PERMISSION_ALL);
+			}
+		}
+
+		// cleanup
+		$this->cleanupSharedTable();
+	}
+
+	/**
+	 * @medium
+	 */
+	function testRemoveBrokenShares() {
+
+		$this->prepareFileCache();
+
+		// check if there are just 3 shares (see setUp - precondition: empty table)
+		$countShares = \OC_DB::prepare('SELECT COUNT(`id`) FROM `*PREFIX*share`');
+		$result = $countShares->execute()->fetchOne();
+		$this->assertEquals(3, $result);
+
+		// check if there are just 2 items (see setUp - precondition: empty table)
+		$countItems = \OC_DB::prepare('SELECT COUNT(`fileid`) FROM `*PREFIX*filecache`');
+		$result = $countItems->execute()->fetchOne();
+		$this->assertEquals(2, $result);
+
+		// execute actual code which should be tested
+		\OC\Files\Cache\Shared_Updater::fixBrokenSharesOnAppUpdate();
+
+		// check if there are just 2 shares (one gets killed by the code as there is no filecache entry for this)
+		$countShares = \OC_DB::prepare('SELECT COUNT(`id`) FROM `*PREFIX*share`');
+		$result = $countShares->execute()->fetchOne();
+		$this->assertEquals(2, $result);
+
+		// check if the share of file '200' is removed as there is no entry for this in filecache table
+		$countShares = \OC_DB::prepare('SELECT COUNT(`id`) FROM `*PREFIX*share` WHERE `file_source` = 200');
+		$result = $countShares->execute()->fetchOne();
+		$this->assertEquals(0, $result);
+
+		// check if there are just 2 items
+		$countItems = \OC_DB::prepare('SELECT COUNT(`fileid`) FROM `*PREFIX*filecache`');
+		$result = $countItems->execute()->fetchOne();
+		$this->assertEquals(2, $result);
+	}
+
+	/**
+	 * test update for the removal of the logical "Shared" folder. It should update
+	 * the file_target for every share and create a physical "Shared" folder for each user
+	 */
+	function testRemoveSharedFolder() {
+		self::prepareDB();
+		// run the update routine to remove the shared folder and replace it with a real folder
+		removeSharedFolder(false, 2);
+
+		// verify results
+		$query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share`');
+		$result = $query->execute(array());
+
+		$newDBContent = $result->fetchAll();
+
+		foreach ($newDBContent as $row) {
+			if ((int)$row['share_type'] === \OCP\Share::SHARE_TYPE_USER) {
+				$this->assertSame('/Shared', substr($row['file_target'], 0, strlen('/Shared')));
+			} else {
+				$this->assertSame('/ShouldNotChange', $row['file_target']);
+			}
+		}
+
+		// cleanup
+		$this->cleanupSharedTable();
+
+	}
+
+	private function cleanupSharedTable() {
+		$query = \OC_DB::prepare('DELETE FROM `*PREFIX*share`');
+		$query->execute();
+	}
+
+	/**
+	 * prepare sharing table for testRemoveSharedFolder()
+	 */
+	private function prepareDB() {
+		$this->cleanupSharedTable();
+		// add items except one - because this is the test case for the broken share table
+		$addItems = \OC_DB::prepare('INSERT INTO `*PREFIX*share` (`share_type`, `item_type`, ' .
+			'`share_with`, `uid_owner` , `file_target`) ' .
+			'VALUES (?, ?, ?, ?, ?)');
+		$items = array(
+			array(\OCP\Share::SHARE_TYPE_USER, 'file', 'user1', 'admin' , '/foo'),
+			array(\OCP\Share::SHARE_TYPE_USER, 'folder', 'user2', 'admin', '/foo2'),
+			array(\OCP\Share::SHARE_TYPE_USER, 'file', 'user3', 'admin', '/foo3'),
+			array(\OCP\Share::SHARE_TYPE_USER, 'folder', 'user4', 'admin', '/foo4'),
+			array(\OCP\Share::SHARE_TYPE_LINK, 'file', 'user1', 'admin', '/ShouldNotChange'),
+			array(\OCP\Share::SHARE_TYPE_CONTACT, 'contact', 'admin', 'user1', '/ShouldNotChange'),
+
+			);
+		foreach($items as $item) {
+			// the number is used as path_hash
+			$addItems->execute($item);
+		}
+	}
+
+	/**
+	 * prepare sharing table for testUpdateFilePermissions()
+	 */
+	private function prepareDBUpdateFilePermissions() {
+		$this->cleanupSharedTable();
+		// add items except one - because this is the test case for the broken share table
+		$addItems = \OC_DB::prepare('INSERT INTO `*PREFIX*share` (`share_type`, `item_type`, ' .
+			'`share_with`, `uid_owner` , `file_target`, `permissions`) ' .
+			'VALUES (?, ?, ?, ?, ?, ?)');
+		$items = array(
+			array(\OCP\Share::SHARE_TYPE_LINK, 'file', 'user1', 'admin', '/foo', \OCP\PERMISSION_ALL),
+			array(\OCP\Share::SHARE_TYPE_CONTACT, 'contact', 'admin', 'user1', '/foo', \OCP\PERMISSION_ALL),
+			array(\OCP\Share::SHARE_TYPE_USER, 'folder', 'user4', 'admin', '/foo', \OCP\PERMISSION_ALL),
+			array(\OCP\Share::SHARE_TYPE_USER, 'file', 'user3', 'admin', '/foo3', \OCP\PERMISSION_ALL),
+			array(\OCP\Share::SHARE_TYPE_USER, 'file', 'user1', 'admin' , '/foo', \OCP\PERMISSION_DELETE),
+			array(\OCP\Share::SHARE_TYPE_USER, 'file', 'user1', 'admin' , '/foo', \OCP\PERMISSION_READ & \OCP\PERMISSION_DELETE),
+			array(\OCP\Share::SHARE_TYPE_USER, 'file', 'user1', 'admin' , '/foo', \OCP\PERMISSION_SHARE & \OCP\PERMISSION_UPDATE),
+			array(\OCP\Share::SHARE_TYPE_USER, 'file', 'user1', 'admin' , '/foo', \OCP\PERMISSION_ALL),
+			array(\OCP\Share::SHARE_TYPE_USER, 'file', 'user1', 'admin' , '/foo', \OCP\PERMISSION_SHARE & \OCP\PERMISSION_READ & \OCP\PERMISSION_DELETE),
+			);
+		foreach($items as $item) {
+			// the number is used as path_hash
+			$addItems->execute($item);
+		}
+	}
+
+	/**
+	 * prepare file cache for testRemoveBrokenShares()
+	 */
+	private function prepareFileCache() {
+		// some previous tests didn't clean up and therefore this has to be done here
+		// FIXME: DIRTY HACK - TODO: find tests, that don't clean up and fix it there
+		$this->tearDown();
+
+		// add items except one - because this is the test case for the broken share table
+		$addItems = \OC_DB::prepare('INSERT INTO `*PREFIX*filecache` (`storage`, `path_hash`, ' .
+			'`parent`, `mimetype`, `mimepart`, `size`, `mtime`, `storage_mtime`) ' .
+			'VALUES (1, ?, 1, 1, 1, 1, 1, 1)');
+		$items = array(1, 3);
+		$fileIds = array();
+		foreach($items as $item) {
+			// the number is used as path_hash
+			$addItems->execute(array($item));
+			$fileIds[] = \OC_DB::insertId('*PREFIX*filecache');
+		}
+
+		$addShares = \OC_DB::prepare('INSERT INTO `*PREFIX*share` (`file_source`, `item_type`, `uid_owner`) VALUES (?, \'file\', 1)');
+		// the number is used as item_source
+		$addShares->execute(array($fileIds[0]));
+		$addShares->execute(array(200)); // id of "deleted" file
+		$addShares->execute(array($fileIds[1]));
+	}
+
+}
diff --git a/apps/files_sharing/tests/updater.php b/apps/files_sharing/tests/updater.php
index 1b851cccf6c7423b6b33eea86cb474e65b47f16c..8183e7067a42a68ecd4ffd245daf99761b48870d 100644
--- a/apps/files_sharing/tests/updater.php
+++ b/apps/files_sharing/tests/updater.php
@@ -47,11 +47,6 @@ class Test_Files_Sharing_Updater extends Test_Files_Sharing_Base {
 		$this->view->unlink($this->filename);
 		$this->view->deleteAll($this->folder);
 
-		$removeShares = \OC_DB::prepare('DELETE FROM `*PREFIX*share`');
-		$removeShares->execute();
-		$removeItems = \OC_DB::prepare('DELETE FROM `*PREFIX*filecache`');
-		$removeItems->execute();
-
 		parent::tearDown();
 	}
 
@@ -111,124 +106,4 @@ class Test_Files_Sharing_Updater extends Test_Files_Sharing_Base {
 		}
 	}
 
-	/**
-	 * @medium
-	 */
-	function testRemoveBrokenShares() {
-
-		$this->prepareFileCache();
-
-		// check if there are just 3 shares (see setUp - precondition: empty table)
-		$countShares = \OC_DB::prepare('SELECT COUNT(`id`) FROM `*PREFIX*share`');
-		$result = $countShares->execute()->fetchOne();
-		$this->assertEquals(3, $result);
-
-		// check if there are just 2 items (see setUp - precondition: empty table)
-		$countItems = \OC_DB::prepare('SELECT COUNT(`fileid`) FROM `*PREFIX*filecache`');
-		$result = $countItems->execute()->fetchOne();
-		$this->assertEquals(2, $result);
-
-		// execute actual code which should be tested
-		\OC\Files\Cache\Shared_Updater::fixBrokenSharesOnAppUpdate();
-
-		// check if there are just 2 shares (one gets killed by the code as there is no filecache entry for this)
-		$countShares = \OC_DB::prepare('SELECT COUNT(`id`) FROM `*PREFIX*share`');
-		$result = $countShares->execute()->fetchOne();
-		$this->assertEquals(2, $result);
-
-		// check if the share of file '200' is removed as there is no entry for this in filecache table
-		$countShares = \OC_DB::prepare('SELECT COUNT(`id`) FROM `*PREFIX*share` WHERE `file_source` = 200');
-		$result = $countShares->execute()->fetchOne();
-		$this->assertEquals(0, $result);
-
-		// check if there are just 2 items
-		$countItems = \OC_DB::prepare('SELECT COUNT(`fileid`) FROM `*PREFIX*filecache`');
-		$result = $countItems->execute()->fetchOne();
-		$this->assertEquals(2, $result);
-	}
-
-	/**
-	 * test update for the removal of the logical "Shared" folder. It should update
-	 * the file_target for every share and create a physical "Shared" folder for each user
-	 */
-	function testRemoveSharedFolder() {
-		self::prepareDB();
-		// run the update routine to remove the shared folder and replace it with a real folder
-		removeSharedFolder(false, 2);
-
-		// verify results
-		$query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share`');
-		$result = $query->execute(array());
-
-		$newDBContent = $result->fetchAll();
-
-		foreach ($newDBContent as $row) {
-			if ((int)$row['share_type'] === \OCP\Share::SHARE_TYPE_USER) {
-				$this->assertSame('/Shared', substr($row['file_target'], 0, strlen('/Shared')));
-			} else {
-				$this->assertSame('/ShouldNotChange', $row['file_target']);
-			}
-		}
-
-		// cleanup
-		$this->cleanupSharedTable();
-
-	}
-
-	private function cleanupSharedTable() {
-		$query = \OC_DB::prepare('DELETE FROM `*PREFIX*share`');
-		$query->execute();
-	}
-
-	/**
-	 * prepare sharing table for testRemoveSharedFolder()
-	 */
-	private function prepareDB() {
-		$this->cleanupSharedTable();
-		// add items except one - because this is the test case for the broken share table
-		$addItems = \OC_DB::prepare('INSERT INTO `*PREFIX*share` (`share_type`, `item_type`, ' .
-			'`share_with`, `uid_owner` , `file_target`) ' .
-			'VALUES (?, ?, ?, ?, ?)');
-		$items = array(
-			array(\OCP\Share::SHARE_TYPE_USER, 'file', 'user1', 'admin' , '/foo'),
-			array(\OCP\Share::SHARE_TYPE_USER, 'folder', 'user2', 'admin', '/foo2'),
-			array(\OCP\Share::SHARE_TYPE_USER, 'file', 'user3', 'admin', '/foo3'),
-			array(\OCP\Share::SHARE_TYPE_USER, 'folder', 'user4', 'admin', '/foo4'),
-			array(\OCP\Share::SHARE_TYPE_LINK, 'file', 'user1', 'admin', '/ShouldNotChange'),
-			array(\OCP\Share::SHARE_TYPE_CONTACT, 'contact', 'admin', 'user1', '/ShouldNotChange'),
-
-			);
-		foreach($items as $item) {
-			// the number is used as path_hash
-			$addItems->execute($item);
-		}
-	}
-
-	/**
-	 * prepare file cache for testRemoveBrokenShares()
-	 */
-	private function prepareFileCache() {
-		// some previous tests didn't clean up and therefore this has to be done here
-		// FIXME: DIRTY HACK - TODO: find tests, that don't clean up and fix it there
-		$this->tearDown();
-
-		// add items except one - because this is the test case for the broken share table
-		$addItems = \OC_DB::prepare('INSERT INTO `*PREFIX*filecache` (`storage`, `path_hash`, ' .
-			'`parent`, `mimetype`, `mimepart`, `size`, `mtime`, `storage_mtime`) ' .
-			'VALUES (1, ?, 1, 1, 1, 1, 1, 1)');
-		$items = array(1, 3);
-		$fileIds = array();
-		foreach($items as $item) {
-			// the number is used as path_hash
-			$addItems->execute(array($item));
-			$fileIds[] = \OC_DB::insertId('*PREFIX*filecache');
-		}
-
-		$addShares = \OC_DB::prepare('INSERT INTO `*PREFIX*share` (`file_source`, `item_type`, `uid_owner`) VALUES (?, \'file\', 1)');
-		// the number is used as item_source
-		$addShares->execute(array($fileIds[0]));
-		$addShares->execute(array(200)); // id of "deleted" file
-		$addShares->execute(array($fileIds[1]));
-	}
-
 }
diff --git a/lib/private/connector/sabre/objecttree.php b/lib/private/connector/sabre/objecttree.php
index a3de2efaa50b8c961780bc0be31fc707fe76336b..c55a392bca0c31f7b86cd9942f2bd0bad0c5102a 100644
--- a/lib/private/connector/sabre/objecttree.php
+++ b/lib/private/connector/sabre/objecttree.php
@@ -126,10 +126,6 @@ class ObjectTree extends \Sabre\DAV\ObjectTree {
 			throw new \Sabre\DAV\Exception\Forbidden();
 		}
 		if ($sourceDir !== $destinationDir) {
-			// for a full move we need update privileges on sourcePath and sourceDir as well as destinationDir
-			if (ltrim($destinationDir, '/') === '') {
-				throw new \Sabre\DAV\Exception\Forbidden();
-			}
 			if (!$this->fileView->isUpdatable($sourceDir)) {
 				throw new \Sabre\DAV\Exception\Forbidden();
 			}
diff --git a/lib/private/files/cache/updater.php b/lib/private/files/cache/updater.php
index f6feb6624b29dc5c6f7fdedc0da02cf3c170cded..f15c203cd5828d1a5909918b741e8ba34a2f1ef0 100644
--- a/lib/private/files/cache/updater.php
+++ b/lib/private/files/cache/updater.php
@@ -83,6 +83,10 @@ class Updater {
 		 * @var string $internalTo
 		 */
 		list($storageFrom, $internalFrom) = self::resolvePath($from);
+		// if it's a moved mountpoint we dont need to do anything
+		if ($internalFrom === '') {
+			return;
+		}
 		list($storageTo, $internalTo) = self::resolvePath($to);
 		if ($storageFrom && $storageTo) {
 			if ($storageFrom === $storageTo) {
diff --git a/lib/private/files/fileinfo.php b/lib/private/files/fileinfo.php
index e7afeb4cccee400912c74751e66f84abebca052a..d012c0c5a639a0e32b64043d4aad16d47a9bdcb4 100644
--- a/lib/private/files/fileinfo.php
+++ b/lib/private/files/fileinfo.php
@@ -108,7 +108,7 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess {
 	 * @return string
 	 */
 	public function getName() {
-		return $this->data['name'];
+		return basename($this->getPath());
 	}
 
 	/**
diff --git a/lib/private/files/mount/manager.php b/lib/private/files/mount/manager.php
index db1f4600c742ba5f2994792885d13429d15aa5c2..45a9f339fba575cc9e64d28f95fec0145889bed7 100644
--- a/lib/private/files/mount/manager.php
+++ b/lib/private/files/mount/manager.php
@@ -30,6 +30,15 @@ class Manager {
 		unset($this->mounts[$mountPoint]);
 	}
 
+	/**
+	 * @param string $mountPoint
+	 * @param string $target
+	 */
+	public function moveMount($mountPoint, $target){
+		$this->mounts[$target] = $this->mounts[$mountPoint];
+		unset($this->mounts[$mountPoint]);
+	}
+
 	/**
 	 * Find the mount for $path
 	 *
diff --git a/lib/private/files/mount/mount.php b/lib/private/files/mount/mount.php
index 7c40853ac95d30993c3785db8bffe506da951df1..04bccbcab87551f3d3e8ffb0cc869c0b13c580e3 100644
--- a/lib/private/files/mount/mount.php
+++ b/lib/private/files/mount/mount.php
@@ -16,11 +16,11 @@ class Mount {
 	/**
 	 * @var \OC\Files\Storage\Storage $storage
 	 */
-	private $storage = null;
-	private $class;
-	private $storageId;
-	private $arguments = array();
-	private $mountPoint;
+	protected $storage = null;
+	protected $class;
+	protected $storageId;
+	protected $arguments = array();
+	protected $mountPoint;
 
 	/**
 	 * @var \OC\Files\Storage\Loader $loader
@@ -142,7 +142,8 @@ class Mount {
 		} else {
 			$internalPath = substr($path, strlen($this->mountPoint));
 		}
-		return $internalPath;
+		// substr returns false instead of an empty string, we always want a string
+		return (string)$internalPath;
 	}
 
 	/**
diff --git a/lib/private/files/mount/moveablemount.php b/lib/private/files/mount/moveablemount.php
new file mode 100644
index 0000000000000000000000000000000000000000..117649339e96a5146ec84ebb7102a8218458bb81
--- /dev/null
+++ b/lib/private/files/mount/moveablemount.php
@@ -0,0 +1,30 @@
+<?php
+/**
+ * Copyright (c) 2012 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 OC\Files\Mount;
+
+/**
+ * Defines the mount point to be (re)moved by the user
+ */
+interface MoveableMount {
+	/**
+	 * Move the mount point to $target
+	 *
+	 * @param string $target the target mount point
+	 * @return bool
+	 */
+	public function moveMount($target);
+
+	/**
+	 * Remove the mount points
+	 *
+	 * @return mixed
+	 * @return bool
+	 */
+	public function removeMount();
+}
diff --git a/lib/private/files/view.php b/lib/private/files/view.php
index 1dc6c405bcf4a2676739924741638a1c28ef93ea..d42f6cbf9fe012f5848e2fe452534ad0f21bd678 100644
--- a/lib/private/files/view.php
+++ b/lib/private/files/view.php
@@ -26,6 +26,7 @@
 namespace OC\Files;
 
 use OC\Files\Cache\Updater;
+use OC\Files\Mount\MoveableMount;
 
 class View {
 	private $fakeRoot = '';
@@ -357,14 +358,27 @@ class View {
 		}
 		$postFix = (substr($path, -1, 1) === '/') ? '/' : '';
 		$absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path));
-		list($storage, $internalPath) = Filesystem::resolvePath($absolutePath . $postFix);
-		if (!($storage instanceof \OC\Files\Storage\Shared) &&
-			(!$internalPath || $internalPath === '' || $internalPath === '/')
-		) {
-			// do not allow deleting the storage's root / the mount point
-			// because for some storages it might delete the whole contents
-			// but isn't supposed to work that way
-			return false;
+		$mount = Filesystem::getMountManager()->find($absolutePath . $postFix);
+		if ($mount->getInternalPath($absolutePath) === '') {
+			if ($mount instanceof MoveableMount) {
+				\OC_Hook::emit(
+						Filesystem::CLASSNAME, "umount",
+						array(Filesystem::signal_param_path => $path)
+						);
+				$result = $mount->removeMount();
+				if ($result) {
+					\OC_Hook::emit(
+							Filesystem::CLASSNAME, "post_umount",
+							array(Filesystem::signal_param_path => $path)
+							);
+				}
+				return $result;
+			} else {
+				// do not allow deleting the storage's root / the mount point
+				// because for some storages it might delete the whole contents
+				// but isn't supposed to work that way
+				return false;
+			}
 		}
 		return $this->basicOperation('unlink', $path, array('delete'));
 	}
@@ -411,18 +425,19 @@ class View {
 			if ($run) {
 				$mp1 = $this->getMountPoint($path1 . $postFix1);
 				$mp2 = $this->getMountPoint($path2 . $postFix2);
-				list($storage1, $internalPath1) = Filesystem::resolvePath($absolutePath1 . $postFix1);
+				$manager = Filesystem::getMountManager();
+				$mount = $manager->find($absolutePath1 . $postFix1);
+				$storage1 = $mount->getStorage();
+				$internalPath1 = $mount->getInternalPath($absolutePath1 . $postFix1);
 				list(, $internalPath2) = Filesystem::resolvePath($absolutePath2 . $postFix2);
-				// if source and target are on the same storage we can call the rename operation from the
-				// storage. If it is a "Shared" file/folder we call always the rename operation of the
-				// shared storage to handle mount point renaming, etc correctly
-				if ($storage1 instanceof \OC\Files\Storage\Shared) {
-					if ($storage1) {
-						$result = $storage1->rename($absolutePath1, $absolutePath2);
-						\OC_FileProxy::runPostProxies('rename', $absolutePath1, $absolutePath2);
-					} else {
-						$result = false;
-					}
+				if ($internalPath1 === '' and $mount instanceof MoveableMount) {
+					/**
+					 * @var \OC\Files\Mount\Mount | \OC\Files\Mount\MoveableMount $mount
+					 */
+					$sourceMountPoint = $mount->getMountPoint();
+					$result = $mount->moveMount($absolutePath2);
+					$manager->moveMount($sourceMountPoint, $mount->getMountPoint());
+					\OC_FileProxy::runPostProxies('rename', $absolutePath1, $absolutePath2);
 				} elseif ($mp1 == $mp2) {
 					if ($storage1) {
 						$result = $storage1->rename($internalPath1, $internalPath2);
@@ -888,10 +903,6 @@ class View {
 			return $result;
 		}
 		$path = Filesystem::normalizePath($this->fakeRoot . '/' . $directory);
-		/**
-		 * @var \OC\Files\Storage\Storage $storage
-		 * @var string $internalPath
-		 */
 		list($storage, $internalPath) = Filesystem::resolvePath($path);
 		if ($storage) {
 			$cache = $storage->getCache($internalPath);
@@ -924,9 +935,10 @@ class View {
 			}
 
 			//add a folder for any mountpoint in this directory and add the sizes of other mountpoints to the folders
-			$mountPoints = Filesystem::getMountPoints($path);
+			$mounts = Filesystem::getMountManager()->findIn($path);
 			$dirLength = strlen($path);
-			foreach ($mountPoints as $mountPoint) {
+			foreach ($mounts as $mount) {
+				$mountPoint = $mount->getMountPoint();
 				$subStorage = Filesystem::getStorage($mountPoint);
 				if ($subStorage) {
 					$subCache = $subStorage->getCache('');
@@ -953,8 +965,8 @@ class View {
 							$permissions = $rootEntry['permissions'];
 							// do not allow renaming/deleting the mount point if they are not shared files/folders
 							// for shared files/folders we use the permissions given by the owner
-							if ($subStorage instanceof \OC\Files\Storage\Shared) {
-								$rootEntry['permissions'] = $permissions;
+							if ($mount instanceof MoveableMount) {
+								$rootEntry['permissions'] = $permissions | \OCP\PERMISSION_UPDATE | \OCP\PERMISSION_DELETE;
 							} else {
 								$rootEntry['permissions'] = $permissions & (\OCP\PERMISSION_ALL - (\OCP\PERMISSION_UPDATE | \OCP\PERMISSION_DELETE));
 							}
diff --git a/lib/private/hook.php b/lib/private/hook.php
index 30e22847c7f1b0410a5c9095055beed7e1cac6c1..c9ca58f779e7084ebab1af781d7a3bb6f772d9a0 100644
--- a/lib/private/hook.php
+++ b/lib/private/hook.php
@@ -31,6 +31,12 @@ class OC_Hook{
 			self::$registered[$signalclass][$signalname] = array();
 		}
 
+		// dont connect hooks twice
+		foreach (self::$registered[$signalclass][$signalname] as $hook) {
+			if ($hook['class'] === $slotclass and $hook['name'] === $slotname) {
+				return false;
+			}
+		}
 		// Connect the hook handler to the requested emitter
 		self::$registered[$signalclass][$signalname][] = array(
 				"class" => $slotclass,
diff --git a/lib/private/share/helper.php b/lib/private/share/helper.php
index ab9e0ca4926ded5959d1c375ffe2b4e8d5c6c6d5..c92aa15b4bfe88baf85b0e0569c60ecd80968d75 100644
--- a/lib/private/share/helper.php
+++ b/lib/private/share/helper.php
@@ -166,27 +166,6 @@ class Helper extends \OC\Share\Constants {
 			// Reset parents array, only go through loop again if items are found
 			$parents = array();
 			while ($item = $result->fetchRow()) {
-				// Search for a duplicate parent share, this occurs when an
-				// item is shared to the same user through a group and user or the
-				// same item is shared by different users
-				$userAndGroups = array_merge(array($item['uid_owner']), \OC_Group::getUserGroups($item['uid_owner']));
-				$query = \OC_DB::prepare('SELECT `id`, `permissions` FROM `*PREFIX*share`'
-					.' WHERE `item_type` = ?'
-					.' AND `item_target` = ?'
-					.' AND `share_type` IN (?,?,?)'
-					.' AND `share_with` IN (\''.implode('\',\'', $userAndGroups).'\')'
-					.' AND `uid_owner` != ? AND `id` != ?');
-				$duplicateParent = $query->execute(array($item['item_type'], $item['item_target'],
-					self::SHARE_TYPE_USER, self::SHARE_TYPE_GROUP, self::$shareTypeGroupUserUnique,
-					$item['uid_owner'], $item['parent']))->fetchRow();
-				if ($duplicateParent) {
-					// Change the parent to the other item id if share permission is granted
-					if ($duplicateParent['permissions'] & \OCP\PERMISSION_SHARE) {
-						$query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `parent` = ? WHERE `id` = ?');
-						$query->execute(array($duplicateParent['id'], $item['id']));
-						continue;
-					}
-				}
 				$ids[] = $item['id'];
 				$parents[] = $item['id'];
 			}
diff --git a/lib/private/share/share.php b/lib/private/share/share.php
index 2126a1d2dd4e5d14b9f96920ca3a8690c845a33f..f02eacfed744f12ac3370225e887d68b84b81e0c 100644
--- a/lib/private/share/share.php
+++ b/lib/private/share/share.php
@@ -519,6 +519,11 @@ class Share extends \OC\Share\Constants {
 			}
 		}
 
+		// single file shares should never have delete permissions
+		if ($itemType === 'file') {
+			$permissions = (int)$permissions & ~\OCP\PERMISSION_DELETE;
+		}
+
 		// Verify share type and sharing conditions are met
 		if ($shareType === self::SHARE_TYPE_USER) {
 			if ($shareWith == $uidOwner) {
@@ -712,33 +717,54 @@ class Share extends \OC\Share\Constants {
 	 * Unsharing from self is not allowed for items inside collections
 	 */
 	public static function unshareFromSelf($itemType, $itemTarget) {
-		$item = self::getItemSharedWith($itemType, $itemTarget);
-		if (!empty($item)) {
-			if ((int)$item['share_type'] === self::SHARE_TYPE_GROUP) {
-				// Insert an extra row for the group share and set permission
-				// to 0 to prevent it from showing up for the user
-				$query = \OC_DB::prepare('INSERT INTO `*PREFIX*share`'
+
+		$uid = \OCP\User::getUser();
+
+		if ($itemType === 'file' || $itemType === 'folder') {
+			$statement = 'SELECT * FROM `*PREFIX*share` WHERE `item_type` = ? and `file_target` = ?';
+		} else {
+			$statement = 'SELECT * FROM `*PREFIX*share` WHERE `item_type` = ? and `item_target` = ?';
+		}
+
+		$query = \OCP\DB::prepare($statement);
+		$result = $query->execute(array($itemType, $itemTarget));
+
+		$shares = $result->fetchAll();
+
+		$itemUnshared = false;
+		foreach ($shares as $share) {
+			if ((int)$share['share_type'] === \OCP\Share::SHARE_TYPE_USER &&
+					$share['share_with'] === $uid) {
+				Helper::delete($share['id']);
+				$itemUnshared = true;
+				break;
+			} elseif ((int)$share['share_type'] === \OCP\Share::SHARE_TYPE_GROUP) {
+				if (\OC_Group::inGroup($uid, $share['share_with'])) {
+					$groupShare = $share;
+				}
+			} elseif ((int)$share['share_type'] === self::$shareTypeGroupUserUnique &&
+					$share['share_with'] === $uid) {
+				$uniqueGroupShare = $share;
+			}
+		}
+
+		if (!$itemUnshared && isset($groupShare)) {
+			$query = \OC_DB::prepare('INSERT INTO `*PREFIX*share`'
 					.' (`item_type`, `item_source`, `item_target`, `parent`, `share_type`,'
 					.' `share_with`, `uid_owner`, `permissions`, `stime`, `file_source`, `file_target`)'
 					.' VALUES (?,?,?,?,?,?,?,?,?,?,?)');
-				$query->execute(array($item['item_type'], $item['item_source'], $item['item_target'],
-					$item['id'], self::$shareTypeGroupUserUnique,
-					\OC_User::getUser(), $item['uid_owner'], 0, $item['stime'], $item['file_source'],
-					$item['file_target']));
-				\OC_DB::insertid('*PREFIX*share');
-				// Delete all reshares by this user of the group share
-				Helper::delete($item['id'], true, \OC_User::getUser());
-			} else if ((int)$item['share_type'] === self::$shareTypeGroupUserUnique) {
-				// Set permission to 0 to prevent it from showing up for the user
-				$query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `permissions` = ? WHERE `id` = ?');
-				$query->execute(array(0, $item['id']));
-				Helper::delete($item['id'], true);
-			} else {
-				Helper::delete($item['id']);
-			}
-			return true;
+			$query->execute(array($groupShare['item_type'], $groupShare['item_source'], $groupShare['item_target'],
+				$groupShare['id'], self::$shareTypeGroupUserUnique,
+				\OC_User::getUser(), $groupShare['uid_owner'], 0, $groupShare['stime'], $groupShare['file_source'],
+				$groupShare['file_target']));
+			$itemUnshared = true;
+		} elseif (!$itemUnshared && isset($uniqueGroupShare)) {
+			$query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `permissions` = ? WHERE `id` = ?');
+			$query->execute(array(0, $uniqueGroupShare['id']));
+			$itemUnshared = true;
 		}
-		return false;
+
+		return $itemUnshared;
 	}
 
 	/**