Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/server.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorRobin Appelman <robin@icewind.nl>2022-03-28 19:47:17 +0300
committerRobin Appelman <robin@icewind.nl>2022-04-04 16:40:16 +0300
commit44a8ebdc1fa796d4f7dc453c58561b64902ca12f (patch)
treeb2dc883aa3c8d8ff36c89cda9be16f0aad242bfc /lib
parent700444e21801002cc24093229d8ac7714d2e1486 (diff)
optimize getById on LazyUserFolder to not require a full fs setup
Signed-off-by: Robin Appelman <robin@icewind.nl>
Diffstat (limited to 'lib')
-rw-r--r--lib/private/Files/Node/Folder.php65
-rw-r--r--lib/private/Files/Node/LazyFolder.php12
-rw-r--r--lib/private/Files/Node/LazyRoot.php4
-rw-r--r--lib/private/Files/Node/LazyUserFolder.php26
-rw-r--r--lib/private/Files/Node/Root.php83
-rw-r--r--lib/public/Files/IRootFolder.php13
6 files changed, 121 insertions, 82 deletions
diff --git a/lib/private/Files/Node/Folder.php b/lib/private/Files/Node/Folder.php
index 3c40ee455fa..d058805b20e 100644
--- a/lib/private/Files/Node/Folder.php
+++ b/lib/private/Files/Node/Folder.php
@@ -333,70 +333,7 @@ class Folder extends Node implements \OCP\Files\Folder {
* @return \OC\Files\Node\Node[]
*/
public function getById($id) {
- $mountCache = $this->root->getUserMountCache();
- if (strpos($this->getPath(), '/', 1) > 0) {
- [, $user] = explode('/', $this->getPath());
- } else {
- $user = null;
- }
- $mountsContainingFile = $mountCache->getMountsForFileId((int)$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);
- $mountRoots = array_combine($mountRootIds, $mountRootPaths);
-
- $mounts = $this->root->getMountsIn($this->path);
- $mounts[] = $this->root->getMount($this->path);
-
- $mountsContainingFile = array_filter($mounts, function ($mount) use ($mountRoots) {
- return isset($mountRoots[$mount->getStorageRootId()]);
- });
-
- if (count($mountsContainingFile) === 0) {
- if ($user === $this->getAppDataDirectoryName()) {
- return $this->getByIdInRootMount((int)$id);
- }
- return [];
- }
-
- $nodes = array_map(function (IMountPoint $mount) use ($id, $mountRoots) {
- $rootInternalPath = $mountRoots[$mount->getStorageRootId()];
- $cacheEntry = $mount->getStorage()->getCache()->get((int)$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->root->createNode($absolutePath, new \OC\Files\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) {
- return $this->getRelativePath($node->getPath());
- });
- usort($folders, function ($a, $b) {
- return $b->getPath() <=> $a->getPath();
- });
- return $folders;
+ return $this->root->getByIdInPath((int)$id, $this->getPath());
}
protected function getAppDataDirectoryName(): string {
diff --git a/lib/private/Files/Node/LazyFolder.php b/lib/private/Files/Node/LazyFolder.php
index 45451e5c53c..7d5038e85a2 100644
--- a/lib/private/Files/Node/LazyFolder.php
+++ b/lib/private/Files/Node/LazyFolder.php
@@ -25,6 +25,7 @@ declare(strict_types=1);
*/
namespace OC\Files\Node;
+use OC\Files\Utils\PathHelper;
use OCP\Constants;
/**
@@ -382,13 +383,6 @@ class LazyFolder implements \OCP\Files\Folder {
/**
* @inheritDoc
*/
- public function getRelativePath($path) {
- return $this->__call(__FUNCTION__, func_get_args());
- }
-
- /**
- * @inheritDoc
- */
public function isSubNode($node) {
return $this->__call(__FUNCTION__, func_get_args());
}
@@ -518,4 +512,8 @@ class LazyFolder implements \OCP\Files\Folder {
public function getUploadTime(): int {
return $this->__call(__FUNCTION__, func_get_args());
}
+
+ public function getRelativePath($path) {
+ return PathHelper::getRelativePath($this->getPath(), $path);
+ }
}
diff --git a/lib/private/Files/Node/LazyRoot.php b/lib/private/Files/Node/LazyRoot.php
index c4d61f653e4..c01b9fdbb83 100644
--- a/lib/private/Files/Node/LazyRoot.php
+++ b/lib/private/Files/Node/LazyRoot.php
@@ -39,4 +39,8 @@ class LazyRoot extends LazyFolder implements IRootFolder {
public function getUserFolder($userId) {
return $this->__call(__FUNCTION__, func_get_args());
}
+
+ public function getByIdInPath(int $id, string $path) {
+ return $this->__call(__FUNCTION__, func_get_args());
+ }
}
diff --git a/lib/private/Files/Node/LazyUserFolder.php b/lib/private/Files/Node/LazyUserFolder.php
index 4c9e89ce233..d91759117c1 100644
--- a/lib/private/Files/Node/LazyUserFolder.php
+++ b/lib/private/Files/Node/LazyUserFolder.php
@@ -29,28 +29,38 @@ use OCP\Files\NotFoundException;
use OCP\IUser;
class LazyUserFolder extends LazyFolder {
- private IRootFolder $rootFolder;
+ private IRootFolder $root;
private IUser $user;
+ private string $path;
public function __construct(IRootFolder $rootFolder, IUser $user) {
- $this->rootFolder = $rootFolder;
+ $this->root = $rootFolder;
$this->user = $user;
+ $this->path = '/' . $user->getUID() . '/files';
parent::__construct(function () use ($user) {
try {
- return $this->rootFolder->get('/' . $user->getUID() . '/files');
+ return $this->root->get('/' . $user->getUID() . '/files');
} catch (NotFoundException $e) {
- if (!$this->rootFolder->nodeExists('/' . $user->getUID())) {
- $this->rootFolder->newFolder('/' . $user->getUID());
+ if (!$this->root->nodeExists('/' . $user->getUID())) {
+ $this->root->newFolder('/' . $user->getUID());
}
- return $this->rootFolder->newFolder('/' . $user->getUID() . '/files');
+ return $this->root->newFolder('/' . $user->getUID() . '/files');
}
}, [
- 'path' => '/' . $user->getUID() . '/files',
+ 'path' => $this->path,
'permissions' => Constants::PERMISSION_ALL,
]);
}
public function get($path) {
- return $this->rootFolder->get('/' . $this->user->getUID() . '/files/' . rtrim($path, '/'));
+ return $this->root->get('/' . $this->user->getUID() . '/files/' . ltrim($path, '/'));
+ }
+
+ /**
+ * @param int $id
+ * @return \OC\Files\Node\Node[]
+ */
+ public function getById($id) {
+ return $this->root->getByIdInPath((int)$id, $this->getPath());
}
}
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;
+ }
}
diff --git a/lib/public/Files/IRootFolder.php b/lib/public/Files/IRootFolder.php
index f89a0041146..7d007cb690c 100644
--- a/lib/public/Files/IRootFolder.php
+++ b/lib/public/Files/IRootFolder.php
@@ -38,11 +38,22 @@ interface IRootFolder extends Folder, Emitter {
* Returns a view to user's files folder
*
* @param string $userId user ID
- * @return \OCP\Files\Folder
+ * @return Folder
* @throws NoUserException
* @throws NotPermittedException
*
* @since 8.2.0
*/
public function getUserFolder($userId);
+
+ /**
+ * Get a file or folder by fileid, inside a parent path
+ *
+ * @param int $id
+ * @param string $path
+ * @return Node[]
+ *
+ * @since 24.0.0
+ */
+ public function getByIdInPath(int $id, string $path);
}