diff options
Diffstat (limited to 'lib/private/Files/Node/Root.php')
-rw-r--r-- | lib/private/Files/Node/Root.php | 83 |
1 files changed, 81 insertions, 2 deletions
diff --git a/lib/private/Files/Node/Root.php b/lib/private/Files/Node/Root.php index 84493551003..7592d4caf37 100644 --- a/lib/private/Files/Node/Root.php +++ b/lib/private/Files/Node/Root.php @@ -44,6 +44,7 @@ use OCP\EventDispatcher\IEventDispatcher; use OCP\Files\Config\IUserMountCache; use OCP\Files\Events\Node\FilesystemTornDownEvent; use OCP\Files\IRootFolder; +use OCP\Files\Mount\IMountPoint; use OCP\Files\NotFoundException; use OCP\Files\NotPermittedException; use OCP\IUser; @@ -216,7 +217,7 @@ class Root extends Folder implements IRootFolder { /** * @param string $targetPath - * @return \OC\Files\Node\Node + * @return Node * @throws \OCP\Files\NotPermittedException */ public function rename($targetPath) { @@ -229,7 +230,7 @@ class Root extends Folder implements IRootFolder { /** * @param string $targetPath - * @return \OC\Files\Node\Node + * @return Node * @throws \OCP\Files\NotPermittedException */ public function copy($targetPath) { @@ -404,4 +405,82 @@ class Root extends Folder implements IRootFolder { public function getUserMountCache() { return $this->userMountCache; } + + /** + * @param int $id + * @return Node[] + */ + public function getByIdInPath(int $id, string $path): array { + $mountCache = $this->getUserMountCache(); + if (strpos($path, '/', 1) > 0) { + [, $user] = explode('/', $path); + } else { + $user = null; + } + $mountsContainingFile = $mountCache->getMountsForFileId($id, $user); + + // when a user has access trough the same storage trough multiple paths + // (such as an external storage that is both mounted for a user and shared to the user) + // the mount cache will only hold a single entry for the storage + // this can lead to issues as the different ways the user has access to a storage can have different permissions + // + // so instead of using the cached entries directly, we instead filter the current mounts by the rootid of the cache entry + + $mountRootIds = array_map(function ($mount) { + return $mount->getRootId(); + }, $mountsContainingFile); + $mountRootPaths = array_map(function ($mount) { + return $mount->getRootInternalPath(); + }, $mountsContainingFile); + $mountProviders = array_unique(array_map(function ($mount) { + return $mount->getMountProvider(); + }, $mountsContainingFile)); + $mountRoots = array_combine($mountRootIds, $mountRootPaths); + + $mounts = $this->mountManager->getMountsByMountProvider($path, $mountProviders); + + $mountsContainingFile = array_filter($mounts, function ($mount) use ($mountRoots) { + return isset($mountRoots[$mount->getStorageRootId()]); + }); + + if (count($mountsContainingFile) === 0) { + if ($user === $this->getAppDataDirectoryName()) { + $folder = $this->get($path); + if ($folder instanceof Folder) { + return $folder->getByIdInRootMount($id); + } else { + throw new \Exception("getByIdInPath with non folder"); + } + } + return []; + } + + $nodes = array_map(function (IMountPoint $mount) use ($id, $mountRoots) { + $rootInternalPath = $mountRoots[$mount->getStorageRootId()]; + $cacheEntry = $mount->getStorage()->getCache()->get($id); + if (!$cacheEntry) { + return null; + } + + // cache jails will hide the "true" internal path + $internalPath = ltrim($rootInternalPath . '/' . $cacheEntry->getPath(), '/'); + $pathRelativeToMount = substr($internalPath, strlen($rootInternalPath)); + $pathRelativeToMount = ltrim($pathRelativeToMount, '/'); + $absolutePath = rtrim($mount->getMountPoint() . $pathRelativeToMount, '/'); + return $this->createNode($absolutePath, new FileInfo( + $absolutePath, $mount->getStorage(), $cacheEntry->getPath(), $cacheEntry, $mount, + \OC::$server->getUserManager()->get($mount->getStorage()->getOwner($pathRelativeToMount)) + )); + }, $mountsContainingFile); + + $nodes = array_filter($nodes); + + $folders = array_filter($nodes, function (Node $node) use ($path) { + return PathHelper::getRelativePath($path, $node->getPath()) !== null; + }); + usort($folders, function ($a, $b) { + return $b->getPath() <=> $a->getPath(); + }); + return $folders; + } } |