From d78a2a9f78dc2a65bffa8f3fc4299c4540c4d5be Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Mon, 30 Jun 2014 15:46:37 +0200 Subject: Add StorageNotAvailableException --- lib/private/files/storage/dav.php | 44 ++++++++++++++--------- lib/public/files/storagenotavailableexception.php | 19 ++++++++++ 2 files changed, 46 insertions(+), 17 deletions(-) create mode 100644 lib/public/files/storagenotavailableexception.php diff --git a/lib/private/files/storage/dav.php b/lib/private/files/storage/dav.php index 8b97f750204..726688fe444 100644 --- a/lib/private/files/storage/dav.php +++ b/lib/private/files/storage/dav.php @@ -8,6 +8,9 @@ namespace OC\Files\Storage; +use OCP\Files\StorageNotAvailableException; +use Sabre\DAV\Exception; + class DAV extends \OC\Files\Storage\Common { protected $password; protected $user; @@ -463,29 +466,36 @@ class DAV extends \OC\Files\Storage\Common { * * @param string $path * @param int $time + * @throws \OCP\Files\StorageNotAvailableException * @return bool */ public function hasUpdated($path, $time) { $this->init(); - $response = $this->client->propfind($this->encodePath($path), array( - '{DAV:}getlastmodified', - '{DAV:}getetag', - '{http://owncloud.org/ns}permissions' - )); - if (isset($response['{DAV:}getetag'])) { - $cachedData = $this->getCache()->get($path); - $etag = trim($response['{DAV:}getetag'], '"'); - if ($cachedData['etag'] !== $etag) { - return true; - } else if (isset($response['{http://owncloud.org/ns}permissions'])) { - $permissions = $this->parsePermissions($response['{http://owncloud.org/ns}permissions']); - return $permissions !== $cachedData['permissions']; + try { + $response = $this->client->propfind($this->encodePath($path), array( + '{DAV:}getlastmodified', + '{DAV:}getetag', + '{http://owncloud.org/ns}permissions' + )); + if (isset($response['{DAV:}getetag'])) { + $cachedData = $this->getCache()->get($path); + $etag = trim($response['{DAV:}getetag'], '"'); + if ($cachedData['etag'] !== $etag) { + return true; + } else if (isset($response['{http://owncloud.org/ns}permissions'])) { + $permissions = $this->parsePermissions($response['{http://owncloud.org/ns}permissions']); + return $permissions !== $cachedData['permissions']; + } else { + return false; + } } else { - return false; + $remoteMtime = strtotime($response['{DAV:}getlastmodified']); + return $remoteMtime > $time; } - } else { - $remoteMtime = strtotime($response['{DAV:}getlastmodified']); - return $remoteMtime > $time; + } catch (Exception\NotFound $e) { + return false; + } catch (Exception $e) { + throw new StorageNotAvailableException(); } } } diff --git a/lib/public/files/storagenotavailableexception.php b/lib/public/files/storagenotavailableexception.php new file mode 100644 index 00000000000..fcc0c9cacfe --- /dev/null +++ b/lib/public/files/storagenotavailableexception.php @@ -0,0 +1,19 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +/** + * Public interface of ownCloud for apps to use. + * Files/AlreadyExistsException class + */ + +// use OCP namespace for all classes that are considered public. +// This means that they should be used by apps instead of the internal ownCloud classes +namespace OCP\Files; + +class StorageNotAvailableException extends \Exception { +} -- cgit v1.2.3 From 4526bc0ba6f23a2fae5f7372d9b7702736eb46f6 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Mon, 30 Jun 2014 16:12:12 +0200 Subject: Handle StorageNotAvailableException in ajax/list.php --- apps/files/ajax/list.php | 64 ++++++++++++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 27 deletions(-) diff --git a/apps/files/ajax/list.php b/apps/files/ajax/list.php index bae3628402f..b94d00ed8f9 100644 --- a/apps/files/ajax/list.php +++ b/apps/files/ajax/list.php @@ -1,30 +1,40 @@ close(); - -// Load the files -$dir = isset( $_GET['dir'] ) ? $_GET['dir'] : ''; -$dir = \OC\Files\Filesystem::normalizePath($dir); -$dirInfo = \OC\Files\Filesystem::getFileInfo($dir); -if (!$dirInfo || !$dirInfo->getType() === 'dir') { - header("HTTP/1.0 404 Not Found"); - exit(); +try { + OCP\JSON::checkLoggedIn(); + \OC::$session->close(); + + // Load the files + $dir = isset($_GET['dir']) ? $_GET['dir'] : ''; + $dir = \OC\Files\Filesystem::normalizePath($dir); + $dirInfo = \OC\Files\Filesystem::getFileInfo($dir); + if (!$dirInfo || !$dirInfo->getType() === 'dir') { + header("HTTP/1.0 404 Not Found"); + exit(); + } + + $data = array(); + $baseUrl = OCP\Util::linkTo('files', 'index.php') . '?dir='; + + $permissions = $dirInfo->getPermissions(); + + $sortAttribute = isset($_GET['sort']) ? $_GET['sort'] : 'name'; + $sortDirection = isset($_GET['sortdirection']) ? ($_GET['sortdirection'] === 'desc') : false; + + // make filelist + + $files = \OCA\Files\Helper::getFiles($dir, $sortAttribute, $sortDirection); + $data['directory'] = $dir; + $data['files'] = \OCA\Files\Helper::formatFileInfos($files); + $data['permissions'] = $permissions; + + OCP\JSON::success(array('data' => $data)); +} catch (\OCP\Files\StorageNotAvailableException $e) { + $l = OC_L10N::get('files'); + OCP\JSON::error(array( + 'data' => array( + 'exception' => '\OCP\Files\StorageNotAvailableException', + 'message' => $l->t('Storage not available') + ) + )); } - -$data = array(); -$baseUrl = OCP\Util::linkTo('files', 'index.php') . '?dir='; - -$permissions = $dirInfo->getPermissions(); - -$sortAttribute = isset( $_GET['sort'] ) ? $_GET['sort'] : 'name'; -$sortDirection = isset( $_GET['sortdirection'] ) ? ($_GET['sortdirection'] === 'desc') : false; - -// make filelist -$files = \OCA\Files\Helper::getFiles($dir, $sortAttribute, $sortDirection); - -$data['directory'] = $dir; -$data['files'] = \OCA\Files\Helper::formatFileInfos($files); -$data['permissions'] = $permissions; - -OCP\JSON::success(array('data' => $data)); -- cgit v1.2.3 From 30c240a145dd8c9e54b4cd64a78f1020e41a15f4 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Mon, 30 Jun 2014 16:27:31 +0200 Subject: If loading a directory fails, navigate back to the previous directory --- apps/files/js/filelist.js | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js index 0477a657035..ef28794b1b4 100644 --- a/apps/files/js/filelist.js +++ b/apps/files/js/filelist.js @@ -836,13 +836,18 @@ * @param {boolean} force set to true to force changing directory */ changeDirectory: function(targetDir, changeUrl, force) { + var self = this; var currentDir = this.getCurrentDirectory(); targetDir = targetDir || '/'; if (!force && currentDir === targetDir) { return; } this._setCurrentDir(targetDir, changeUrl); - this.reload(); + this.reload().then(function(success){ + if (!success) { + self.changeDirectory(currentDir, true); + } + }); }, linkTo: function(dir) { return OC.linkTo('files', 'index.php')+"?dir="+ encodeURIComponent(dir).replace(/%2F/g, '/'); @@ -902,7 +907,6 @@ * @brief Reloads the file list using ajax call */ reload: function() { - var self = this; this._selectedFiles = {}; this._selectionSummary.clear(); this.$el.find('.select-all').prop('checked', false); @@ -916,14 +920,10 @@ dir : this.getCurrentDirectory(), sort: this._sort, sortdirection: this._sortDirection - }, - error: function(result) { - self.reloadCallback(result); - }, - success: function(result) { - self.reloadCallback(result); } }); + var callBack = this.reloadCallback.bind(this); + return this._reloadCall.then(callBack, callBack); }, reloadCallback: function(result) { delete this._reloadCall; @@ -931,17 +931,17 @@ if (!result || result.status === 'error') { OC.Notification.show(result.data.message); - return; + return false; } if (result.status === 404) { // go back home this.changeDirectory('/'); - return; + return false; } // aborted ? if (result.status === 0){ - return; + return true; } // TODO: should rather return upload file size through @@ -953,6 +953,7 @@ } this.setFiles(result.data.files); + return true }, updateStorageStatistics: function(force) { -- cgit v1.2.3 From 99960d774750ae836697f8191504341f3a6418b6 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Mon, 30 Jun 2014 16:36:11 +0200 Subject: Handle StorageNotAvailableException in webdav --- lib/private/connector/sabre/objecttree.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/private/connector/sabre/objecttree.php b/lib/private/connector/sabre/objecttree.php index 54596db3c47..f283fcf47f7 100644 --- a/lib/private/connector/sabre/objecttree.php +++ b/lib/private/connector/sabre/objecttree.php @@ -11,6 +11,7 @@ namespace OC\Connector\Sabre; use OC\Files\FileInfo; use OC\Files\Filesystem; use OC\Files\Mount\MoveableMount; +use OCP\Files\StorageNotAvailableException; class ObjectTree extends \Sabre\DAV\ObjectTree { @@ -83,7 +84,11 @@ class ObjectTree extends \Sabre\DAV\ObjectTree { } } else { // read from cache - $info = $this->fileView->getFileInfo($path); + try { + $info = $this->fileView->getFileInfo($path); + } catch (StorageNotAvailableException $e) { + throw new \Sabre\DAV\Exception\ServiceUnavailable('Storage not available'); + } } if (!$info) { -- cgit v1.2.3 From 1c43081d3819ab360fad3f44b6cf2cd8d2cf25a9 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Tue, 1 Jul 2014 14:35:44 +0200 Subject: Detect removed public shares --- apps/files_sharing/lib/external/scanner.php | 18 +----- apps/files_sharing/lib/external/storage.php | 77 ++++++++++++++++++++++- lib/public/files/storageinvalidexception.php | 22 +++++++ lib/public/files/storagenotavailableexception.php | 3 + 4 files changed, 102 insertions(+), 18 deletions(-) create mode 100644 lib/public/files/storageinvalidexception.php diff --git a/apps/files_sharing/lib/external/scanner.php b/apps/files_sharing/lib/external/scanner.php index 8921dd1a4c0..4dc5d4be9d8 100644 --- a/apps/files_sharing/lib/external/scanner.php +++ b/apps/files_sharing/lib/external/scanner.php @@ -19,23 +19,7 @@ class Scanner extends \OC\Files\Cache\Scanner { } public function scanAll() { - $remote = $this->storage->getRemote(); - $token = $this->storage->getToken(); - $password = $this->storage->getPassword(); - $url = $remote . '/index.php/apps/files_sharing/shareinfo?t=' . $token; - - $ch = curl_init(); - - curl_setopt($ch, CURLOPT_URL, $url); - curl_setopt($ch, CURLOPT_POST, 1); - curl_setopt($ch, CURLOPT_POSTFIELDS, - http_build_query(array('password' => $password))); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - - $result = curl_exec($ch); - curl_close($ch); - - $data = json_decode($result, true); + $data = $this->storage->getShareInfo(); if ($data['status'] === 'success') { $this->addResult($data['data'], ''); } else { diff --git a/apps/files_sharing/lib/external/storage.php b/apps/files_sharing/lib/external/storage.php index 454196f15ae..be3f367c383 100644 --- a/apps/files_sharing/lib/external/storage.php +++ b/apps/files_sharing/lib/external/storage.php @@ -10,7 +10,11 @@ namespace OCA\Files_Sharing\External; use OC\Files\Filesystem; use OC\Files\Storage\DAV; +use OC\ForbiddenException; use OCA\Files_Sharing\ISharedStorage; +use OCP\Files\NotFoundException; +use OCP\Files\StorageInvalidException; +use OCP\Files\StorageNotAvailableException; class Storage extends DAV implements ISharedStorage { /** @@ -108,6 +112,8 @@ class Storage extends DAV implements ISharedStorage { * * @param string $path * @param int $time + * @throws \OCP\Files\StorageNotAvailableException + * @throws \OCP\Files\StorageInvalidException * @return bool */ public function hasUpdated($path, $time) { @@ -117,6 +123,75 @@ class Storage extends DAV implements ISharedStorage { return false; } $this->updateChecked = true; - return parent::hasUpdated('', $time); + try { + return parent::hasUpdated('', $time); + } catch (StorageNotAvailableException $e) { + // see if we can find out why the share is unavailable\ + try { + $this->getShareInfo(); + } catch (NotFoundException $shareException) { + // a 404 can either mean that the share no longer exists or there is no ownCloud on the remote + if ($this->testRemote()) { + // valid ownCloud instance means that the public share no longer exists + // since this is permanent (re-sharing the file will create a new token) + // we mark the storage as invalid + throw new StorageInvalidException(); + } else { + // ownCloud instance is gone, likely to be a temporary server configuration error + throw $e; + } + } catch(\Exception $shareException) { + // todo, maybe handle 403 better and ask the user for a new password + throw $e; + } + throw $e; + } + } + + /** + * check if the configured remote is a valid ownCloud instance + * + * @return bool + */ + protected function testRemote() { + try { + $result = file_get_contents($this->remote . '/status.php'); + $data = json_decode($result); + return is_object($data) and !empty($data->version); + } catch (\Exception $e) { + return false; + } + } + + public function getShareInfo() { + $remote = $this->getRemote(); + $token = $this->getToken(); + $password = $this->getPassword(); + $url = $remote . '/index.php/apps/files_sharing/shareinfo?t=' . $token; + + $ch = curl_init(); + + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_POST, 1); + curl_setopt($ch, CURLOPT_POSTFIELDS, + http_build_query(array('password' => $password))); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + + $result = curl_exec($ch); + + $status = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + + switch ($status) { + case 401: + case 403: + throw new ForbiddenException(); + case 404: + throw new NotFoundException(); + case 500: + throw new \Exception(); + } + + return json_decode($result, true); } } diff --git a/lib/public/files/storageinvalidexception.php b/lib/public/files/storageinvalidexception.php new file mode 100644 index 00000000000..7419ccc1d11 --- /dev/null +++ b/lib/public/files/storageinvalidexception.php @@ -0,0 +1,22 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +/** + * Public interface of ownCloud for apps to use. + * Files/AlreadyExistsException class + */ + +// use OCP namespace for all classes that are considered public. +// This means that they should be used by apps instead of the internal ownCloud classes +namespace OCP\Files; + +/** + * Storage has invalid configuration + */ +class StorageInvalidException extends \Exception { +} diff --git a/lib/public/files/storagenotavailableexception.php b/lib/public/files/storagenotavailableexception.php index fcc0c9cacfe..b526cb4ea0f 100644 --- a/lib/public/files/storagenotavailableexception.php +++ b/lib/public/files/storagenotavailableexception.php @@ -15,5 +15,8 @@ // This means that they should be used by apps instead of the internal ownCloud classes namespace OCP\Files; +/** + * Storage is temporarily not available + */ class StorageNotAvailableException extends \Exception { } -- cgit v1.2.3 From 8061a4ccc09bbd6ba675521d1f9e2ced396c862f Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Tue, 1 Jul 2014 14:58:07 +0200 Subject: Remove external shares if the share is invalid --- apps/files_sharing/lib/external/manager.php | 2 ++ apps/files_sharing/lib/external/storage.php | 9 ++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/apps/files_sharing/lib/external/manager.php b/apps/files_sharing/lib/external/manager.php index 4441a72fb16..e4e4d60029d 100644 --- a/apps/files_sharing/lib/external/manager.php +++ b/apps/files_sharing/lib/external/manager.php @@ -108,7 +108,9 @@ class Manager { * @return Mount */ protected function mountShare($data) { + $data['manager'] = $this; $mountPoint = '/' . $this->userSession->getUser()->getUID() . '/files' . $data['mountpoint']; + $data['mountpoint'] = $mountPoint; $mount = new Mount(self::STORAGE, $mountPoint, $data, $this, $this->storageLoader); $this->mountManager->addMount($mount); return $mount; diff --git a/apps/files_sharing/lib/external/storage.php b/apps/files_sharing/lib/external/storage.php index be3f367c383..cbde21d14fb 100644 --- a/apps/files_sharing/lib/external/storage.php +++ b/apps/files_sharing/lib/external/storage.php @@ -39,7 +39,13 @@ class Storage extends DAV implements ISharedStorage { private $updateChecked = false; + /** + * @var \OCA\Files_Sharing\External\Manager + */ + private $manager; + public function __construct($options) { + $this->manager = $options['manager']; $this->remote = $options['remote']; $this->remoteUser = $options['owner']; list($protocol, $remote) = explode('://', $this->remote); @@ -134,7 +140,8 @@ class Storage extends DAV implements ISharedStorage { if ($this->testRemote()) { // valid ownCloud instance means that the public share no longer exists // since this is permanent (re-sharing the file will create a new token) - // we mark the storage as invalid + // we remove the invalid storage + $this->manager->removeShare($this->mountPoint); throw new StorageInvalidException(); } else { // ownCloud instance is gone, likely to be a temporary server configuration error -- cgit v1.2.3 From 8339618ead32bf21e76d65d0e0015cf0cd8adc1f Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Tue, 1 Jul 2014 14:58:17 +0200 Subject: More error catching in list.php --- apps/files/ajax/list.php | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/apps/files/ajax/list.php b/apps/files/ajax/list.php index b94d00ed8f9..b4641343ed4 100644 --- a/apps/files/ajax/list.php +++ b/apps/files/ajax/list.php @@ -1,12 +1,14 @@ close(); +OCP\JSON::checkLoggedIn(); +\OC::$session->close(); +$l = OC_L10N::get('files'); + +// Load the files +$dir = isset($_GET['dir']) ? $_GET['dir'] : ''; +$dir = \OC\Files\Filesystem::normalizePath($dir); - // Load the files - $dir = isset($_GET['dir']) ? $_GET['dir'] : ''; - $dir = \OC\Files\Filesystem::normalizePath($dir); +try { $dirInfo = \OC\Files\Filesystem::getFileInfo($dir); if (!$dirInfo || !$dirInfo->getType() === 'dir') { header("HTTP/1.0 404 Not Found"); @@ -30,11 +32,24 @@ try { OCP\JSON::success(array('data' => $data)); } catch (\OCP\Files\StorageNotAvailableException $e) { - $l = OC_L10N::get('files'); OCP\JSON::error(array( 'data' => array( 'exception' => '\OCP\Files\StorageNotAvailableException', 'message' => $l->t('Storage not available') ) )); +} catch (\OCP\Files\StorageInvalidException $e) { + OCP\JSON::error(array( + 'data' => array( + 'exception' => '\OCP\Files\StorageInvalidException', + 'message' => $l->t('Storage invalid') + ) + )); +} catch (\Exception $e) { + OCP\JSON::error(array( + 'data' => array( + 'exception' => '\Exception', + 'message' => $l->t('Unknown error') + ) + )); } -- cgit v1.2.3 From 816110442032e34b025f7386e4d680140919a834 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Tue, 1 Jul 2014 15:03:29 +0200 Subject: Catch StorageInvalidException in webdav --- lib/private/connector/sabre/objecttree.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/private/connector/sabre/objecttree.php b/lib/private/connector/sabre/objecttree.php index f283fcf47f7..d7a96cfc88e 100644 --- a/lib/private/connector/sabre/objecttree.php +++ b/lib/private/connector/sabre/objecttree.php @@ -11,6 +11,7 @@ namespace OC\Connector\Sabre; use OC\Files\FileInfo; use OC\Files\Filesystem; use OC\Files\Mount\MoveableMount; +use OCP\Files\StorageInvalidException; use OCP\Files\StorageNotAvailableException; class ObjectTree extends \Sabre\DAV\ObjectTree { @@ -88,6 +89,8 @@ class ObjectTree extends \Sabre\DAV\ObjectTree { $info = $this->fileView->getFileInfo($path); } catch (StorageNotAvailableException $e) { throw new \Sabre\DAV\Exception\ServiceUnavailable('Storage not available'); + } catch (StorageInvalidException $e){ + throw new \Sabre\DAV\Exception\NotFound('Storage ' . $path . ' is invalid'); } } -- cgit v1.2.3 From fd68034357170763573db49a7e8b52893e554f30 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Tue, 1 Jul 2014 17:34:01 +0200 Subject: Fixed remote share password param detection --- apps/files_sharing/js/external.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/files_sharing/js/external.js b/apps/files_sharing/js/external.js index 1eb447da896..969a2b184d4 100644 --- a/apps/files_sharing/js/external.js +++ b/apps/files_sharing/js/external.js @@ -58,7 +58,7 @@ $(document).ready(function () { if (params.remote && params.token && params.owner && params.name) { // clear hash, it is unlikely that it contain any extra parameters location.hash = ''; - params.passwordProtected = parseInt(params.passwordProtected, 10) === 1; + params.passwordProtected = parseInt(params.protected, 10) === 1; OCA.Sharing.showAddExternalDialog( params.remote, params.token, -- cgit v1.2.3 From 0008db9995baede8136a22892a9240c25b2c2ef8 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 2 Jul 2014 14:39:45 +0200 Subject: Fix unit test --- apps/files_sharing/tests/externalstorage.php | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/files_sharing/tests/externalstorage.php b/apps/files_sharing/tests/externalstorage.php index 60c5787f295..1258148af53 100644 --- a/apps/files_sharing/tests/externalstorage.php +++ b/apps/files_sharing/tests/externalstorage.php @@ -72,6 +72,7 @@ class Test_Files_Sharing_External_Storage extends \PHPUnit_Framework_TestCase { 'mountpoint' => 'remoteshare', 'token' => 'abcdef', 'password' => '', + 'manager' => null ) ); $this->assertEquals($baseUri, $storage->getBaseUri()); -- cgit v1.2.3 From edb67f9f4dc8d3c028ba6f2d157d2174fb40aba8 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 2 Jul 2014 15:00:12 +0200 Subject: Remove invalid mounts from the active fs --- apps/files_sharing/lib/external/storage.php | 1 + lib/private/files/mount/manager.php | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/apps/files_sharing/lib/external/storage.php b/apps/files_sharing/lib/external/storage.php index cbde21d14fb..3a0de51192e 100644 --- a/apps/files_sharing/lib/external/storage.php +++ b/apps/files_sharing/lib/external/storage.php @@ -142,6 +142,7 @@ class Storage extends DAV implements ISharedStorage { // since this is permanent (re-sharing the file will create a new token) // we remove the invalid storage $this->manager->removeShare($this->mountPoint); + $this->manager->getMountManager()->removeMount($this->mountPoint); throw new StorageInvalidException(); } else { // ownCloud instance is gone, likely to be a temporary server configuration error diff --git a/lib/private/files/mount/manager.php b/lib/private/files/mount/manager.php index 45a9f339fba..e5180cfe173 100644 --- a/lib/private/files/mount/manager.php +++ b/lib/private/files/mount/manager.php @@ -27,6 +27,10 @@ class Manager { * @param string $mountPoint */ public function removeMount($mountPoint) { + $mountPoint = Filesystem::normalizePath($mountPoint); + if (strlen($mountPoint) > 1) { + $mountPoint .= '/'; + } unset($this->mounts[$mountPoint]); } -- cgit v1.2.3