diff --git a/apps/files_sharing/lib/Cache.php b/apps/files_sharing/lib/Cache.php index 1c311935bb642..e4e298e4a2e4d 100644 --- a/apps/files_sharing/lib/Cache.php +++ b/apps/files_sharing/lib/Cache.php @@ -29,6 +29,7 @@ use OC\Files\Cache\FailedCache; use OC\Files\Cache\Wrapper\CacheJail; +use OC\Files\Storage\Wrapper\Jail; use OCP\Files\Cache\ICacheEntry; /** @@ -61,12 +62,30 @@ public function __construct($storage, ICacheEntry $sourceRootInfo) { $this->storage = $storage; $this->sourceRootInfo = $sourceRootInfo; $this->numericId = $sourceRootInfo->getStorageId(); + parent::__construct( null, - $this->sourceRootInfo->getPath() + null ); } + protected function getRoot() { + if (is_null($this->root)) { + $absoluteRoot = $this->sourceRootInfo->getPath(); + + // the sourceRootInfo path is the absolute path of the folder in the "real" storage + // in the case where a folder is shared from a Jail we need to ensure that the share Jail + // has it's root set relative to the source Jail + $currentStorage = $this->storage->getSourceStorage(); + if ($currentStorage->instanceOfStorage(Jail::class)) { + /** @var Jail $currentStorage */ + $absoluteRoot = $currentStorage->getJailedPath($absoluteRoot); + } + $this->root = $absoluteRoot; + } + return $this->root; + } + public function getCache() { if (is_null($this->cache)) { $sourceStorage = $this->storage->getSourceStorage(); @@ -90,7 +109,7 @@ public function getNumericStorageId() { public function get($file) { if ($this->rootUnchanged && ($file === '' || $file === $this->sourceRootInfo->getId())) { - return $this->formatCacheEntry(clone $this->sourceRootInfo); + return $this->formatCacheEntry(clone $this->sourceRootInfo, ''); } return parent::get($file); } @@ -115,16 +134,20 @@ public function moveFromCache(\OCP\Files\Cache\ICache $sourceCache, $sourcePath, return parent::moveFromCache($sourceCache, $sourcePath, $targetPath); } - protected function formatCacheEntry($entry) { - $path = isset($entry['path']) ? $entry['path'] : ''; - $entry = parent::formatCacheEntry($entry); + protected function formatCacheEntry($entry, $path = null) { + if (is_null($path)) { + $path = isset($entry['path']) ? $entry['path'] : ''; + $entry['path'] = $this->getJailedPath($path); + } else { + $entry['path'] = $path; + } $sharePermissions = $this->storage->getPermissions($path); if (isset($entry['permissions'])) { $entry['permissions'] &= $sharePermissions; } else { $entry['permissions'] = $sharePermissions; } - $entry['uid_owner'] = $this->storage->getOwner($path); + $entry['uid_owner'] = $this->storage->getOwner(''); $entry['displayname_owner'] = $this->getOwnerDisplayName(); if ($path === '') { $entry['is_share_mount_point'] = true; diff --git a/apps/files_sharing/tests/CacheTest.php b/apps/files_sharing/tests/CacheTest.php index 26ba5b21e4634..033d1d769b69b 100644 --- a/apps/files_sharing/tests/CacheTest.php +++ b/apps/files_sharing/tests/CacheTest.php @@ -30,6 +30,8 @@ namespace OCA\Files_Sharing\Tests; +use OC\Files\Storage\Temporary; +use OC\Files\Storage\Wrapper\Jail; use OCA\Files_Sharing\SharedStorage; /** @@ -552,4 +554,41 @@ public function testNumericStorageId() { $this->assertEquals($sourceStorage->getCache()->getNumericStorageId(), $sharedStorage->getCache()->getNumericStorageId()); } + + public function testShareJailedStorage() { + $sourceStorage = new Temporary(); + $sourceStorage->mkdir('jail'); + $sourceStorage->mkdir('jail/sub'); + $sourceStorage->file_put_contents('jail/sub/foo.txt', 'foo'); + $jailedSource = new Jail([ + 'storage' => $sourceStorage, + 'root' => 'jail' + ]); + $sourceStorage->getScanner()->scan(''); + $this->registerMount(self::TEST_FILES_SHARING_API_USER1, $jailedSource, '/' . self::TEST_FILES_SHARING_API_USER1 . '/files/foo'); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + + $rootFolder = \OC::$server->getUserFolder(self::TEST_FILES_SHARING_API_USER1); + $node = $rootFolder->get('foo/sub'); + $share = $this->shareManager->newShare(); + $share->setNode($node) + ->setShareType(\OCP\Share::SHARE_TYPE_USER) + ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) + ->setPermissions(\OCP\Constants::PERMISSION_ALL); + $this->shareManager->createShare($share); + \OC_Util::tearDownFS(); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + $this->assertEquals('foo', \OC\Files\Filesystem::file_get_contents('/sub/foo.txt')); + + \OC\Files\Filesystem::file_put_contents('/sub/bar.txt', 'bar'); + /** @var SharedStorage $sharedStorage */ + list($sharedStorage) = \OC\Files\Filesystem::resolvePath('/' . self::TEST_FILES_SHARING_API_USER2 . '/files/sub'); + + $this->assertTrue($sharedStorage->getCache()->inCache('bar.txt')); + + $this->assertTrue($sourceStorage->getCache()->inCache('jail/sub/bar.txt')); + } } diff --git a/lib/private/Files/Cache/Wrapper/CacheJail.php b/lib/private/Files/Cache/Wrapper/CacheJail.php index 8f12ca77ee668..37111206df0d4 100644 --- a/lib/private/Files/Cache/Wrapper/CacheJail.php +++ b/lib/private/Files/Cache/Wrapper/CacheJail.php @@ -26,6 +26,7 @@ */ namespace OC\Files\Cache\Wrapper; + use OC\Files\Cache\Cache; use OCP\Files\Cache\ICacheEntry; use OCP\Files\Search\ISearchQuery; @@ -48,11 +49,15 @@ public function __construct($cache, $root) { $this->root = $root; } + protected function getRoot() { + return $this->root; + } + protected function getSourcePath($path) { if ($path === '') { - return $this->root; + return $this->getRoot(); } else { - return $this->root . '/' . ltrim($path, '/'); + return $this->getRoot() . '/' . ltrim($path, '/'); } } @@ -61,13 +66,13 @@ protected function getSourcePath($path) { * @return null|string the jailed path or null if the path is outside the jail */ protected function getJailedPath($path) { - if ($this->root === '') { + if ($this->getRoot() === '') { return $path; } - $rootLength = strlen($this->root) + 1; - if ($path === $this->root) { + $rootLength = strlen($this->getRoot()) + 1; + if ($path === $this->getRoot()) { return ''; - } else if (substr($path, 0, $rootLength) === $this->root . '/') { + } else if (substr($path, 0, $rootLength) === $this->getRoot() . '/') { return substr($path, $rootLength); } else { return null; @@ -86,8 +91,8 @@ protected function formatCacheEntry($entry) { } protected function filterCacheEntry($entry) { - $rootLength = strlen($this->root) + 1; - return ($entry['path'] === $this->root) or (substr($entry['path'], 0, $rootLength) === $this->root . '/'); + $rootLength = strlen($this->getRoot()) + 1; + return ($entry['path'] === $this->getRoot()) or (substr($entry['path'], 0, $rootLength) === $this->getRoot() . '/'); } /** @@ -189,7 +194,7 @@ protected function getMoveInfo($path) { * remove all entries for files that are stored on the storage from the cache */ public function clear() { - $this->getCache()->remove($this->root); + $this->getCache()->remove($this->getRoot()); } /** diff --git a/lib/private/Files/Storage/Wrapper/Jail.php b/lib/private/Files/Storage/Wrapper/Jail.php index 4fa2428c968c7..d7f244b7d3194 100644 --- a/lib/private/Files/Storage/Wrapper/Jail.php +++ b/lib/private/Files/Storage/Wrapper/Jail.php @@ -58,6 +58,17 @@ public function getUnjailedPath($path) { } } + public function getJailedPath($path) { + $root = rtrim($this->rootPath, '/') . '/'; + + if (strpos($path, $root) !== 0) { + return null; + } else { + $path = substr($path, strlen($this->rootPath)); + return trim($path, '/'); + } + } + public function getId() { return parent::getId(); }