From 042e274d137fc711fc1456a55215ee395e630a9f Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 13 Nov 2024 18:51:02 +0100 Subject: [PATCH 1/9] fix: fix missing dot in unique name when restoring from trash Signed-off-by: Robin Appelman --- lib/Trash/TrashBackend.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Trash/TrashBackend.php b/lib/Trash/TrashBackend.php index 4fa5412fd..ee096ae91 100644 --- a/lib/Trash/TrashBackend.php +++ b/lib/Trash/TrashBackend.php @@ -144,7 +144,7 @@ public function restoreItem(ITrashItem $item): void { $target .= ' (' . $i . ')'; if (isset($info['extension'])) { - $target .= $info['extension']; + $target .= '.' . $info['extension']; } return $target; From 2989996c8fe02b5ca6789c350ad676bcba9500ee Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 13 Nov 2024 18:53:38 +0100 Subject: [PATCH 2/9] fix: remove manual un-jailing when moving to trash as the storage now handles this properly* *: expect for the mentioned bug Signed-off-by: Robin Appelman --- lib/Trash/TrashBackend.php | 50 ++++++++++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/lib/Trash/TrashBackend.php b/lib/Trash/TrashBackend.php index ee096ae91..11e1b4ae8 100644 --- a/lib/Trash/TrashBackend.php +++ b/lib/Trash/TrashBackend.php @@ -6,7 +6,7 @@ namespace OCA\GroupFolders\Trash; -use OC\Files\Storage\Wrapper\Jail; +use OC\Files\Storage\Wrapper\Encryption; use OCA\Files_Trashbin\Expiration; use OCA\Files_Trashbin\Trash\ITrashBackend; use OCA\Files_Trashbin\Trash\ITrashItem; @@ -214,12 +214,17 @@ public function moveToTrash(IStorage $storage, string $internalPath): bool { $trashStorage = $trashFolder->getStorage(); $time = time(); $trashName = $name . '.d' . $time; - [$unJailedStorage, $unJailedInternalPath] = $this->unwrapJails($storage, $internalPath); $targetInternalPath = $trashFolder->getInternalPath() . '/' . $trashName; - if ($trashStorage->moveFromStorage($unJailedStorage, $unJailedInternalPath, $targetInternalPath)) { + // until the fix from https://github.com/nextcloud/server/pull/49262 is in all versions we support we need to manually disable the optimization + if ($storage->instanceOfStorage(Encryption::class)) { + $result = $this->moveFromEncryptedStorage($storage, $trashStorage, $internalPath, $targetInternalPath); + } else { + $result = $trashStorage->moveFromStorage($storage, $internalPath, $targetInternalPath); + } + if ($result) { $this->trashManager->addTrashItem($folderId, $name, $time, $internalPath, $fileEntry->getId(), $this->userSession->getUser()->getUID()); if ($trashStorage->getCache()->getId($targetInternalPath) !== $fileEntry->getId()) { - $trashStorage->getCache()->moveFromCache($unJailedStorage->getCache(), $unJailedInternalPath, $targetInternalPath); + $trashStorage->getCache()->moveFromCache($storage->getCache(), $internalPath, $targetInternalPath); } } else { throw new \Exception('Failed to move groupfolder item to trash'); @@ -231,17 +236,36 @@ public function moveToTrash(IStorage $storage, string $internalPath): bool { } } - private function unwrapJails(IStorage $storage, string $internalPath): array { - $unJailedInternalPath = $internalPath; - $unJailedStorage = $storage; - while ($unJailedStorage->instanceOfStorage(Jail::class)) { - $unJailedStorage = $unJailedStorage->getWrapperStorage(); - if ($unJailedStorage instanceof Jail) { - $unJailedInternalPath = $unJailedStorage->getUnjailedPath($unJailedInternalPath); - } + /** + * move from storage when we can't just move within the storage + * + * This is copied from the fallback implementation from Common::moveFromStorage + */ + private function moveFromEncryptedStorage(IStorage $sourceStorage, IStorage $targetStorage, string $sourceInternalPath, string $targetInternalPath): bool { + if (!$sourceStorage->isDeletable($sourceInternalPath)) { + return false; } - return [$unJailedStorage, $unJailedInternalPath]; + $result = $targetStorage->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath, true); + if ($result) { + if ($sourceStorage->instanceOfStorage(ObjectStoreStorage::class)) { + /** @var ObjectStoreStorage $sourceStorage */ + $sourceStorage->setPreserveCacheOnDelete(true); + } + try { + if ($sourceStorage->is_dir($sourceInternalPath)) { + $result = $sourceStorage->rmdir($sourceInternalPath); + } else { + $result = $sourceStorage->unlink($sourceInternalPath); + } + } finally { + if ($sourceStorage->instanceOfStorage(ObjectStoreStorage::class)) { + /** @var ObjectStoreStorage $sourceStorage */ + $sourceStorage->setPreserveCacheOnDelete(false); + } + } + } + return $result; } private function userHasAccessToFolder(IUser $user, int $folderId): bool { From 227097607d81b29631a5795263601521dbc9e311 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 13 Nov 2024 19:01:57 +0100 Subject: [PATCH 3/9] fix: use "full" target folder from user when restoring trash items Signed-off-by: Robin Appelman --- lib/Trash/TrashBackend.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/Trash/TrashBackend.php b/lib/Trash/TrashBackend.php index 11e1b4ae8..2fd1d8706 100644 --- a/lib/Trash/TrashBackend.php +++ b/lib/Trash/TrashBackend.php @@ -102,6 +102,7 @@ public function restoreItem(ITrashItem $item): void { } $user = $item->getUser(); + $userFolder = $this->rootFolder->getUserFolder($user->getUID()); [, $folderId] = explode('/', $item->getTrashPath()); $node = $this->getNodeForTrashItem($user, $item); if ($node === null) { @@ -119,7 +120,7 @@ public function restoreItem(ITrashItem $item): void { $trashStorage = $node->getStorage(); /** @var Folder $targetFolder */ - $targetFolder = $this->mountProvider->getFolder((int)$folderId); + $targetFolder = $userFolder->get($item->getGroupFolderMountPoint()); $originalLocation = $item->getInternalOriginalLocation(); $parent = dirname($originalLocation); if ($parent === '.') { From 09284947ecb74ff5a850825eeff5594e9a5dd7a1 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Mon, 18 Nov 2024 14:42:57 +0100 Subject: [PATCH 4/9] fix: make root cache entry optional for groupfolder storage Signed-off-by: Robin Appelman --- lib/Mount/GroupFolderStorage.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/Mount/GroupFolderStorage.php b/lib/Mount/GroupFolderStorage.php index 1a812ec76..83a8b7cb5 100644 --- a/lib/Mount/GroupFolderStorage.php +++ b/lib/Mount/GroupFolderStorage.php @@ -20,7 +20,7 @@ class GroupFolderStorage extends Quota implements IConstructableStorage { private int $folderId; - private ICacheEntry $rootEntry; + private ?ICacheEntry $rootEntry; private IUserSession $userSession; private ?IUser $mountOwner; /** @var RootEntryCache|null */ @@ -59,7 +59,11 @@ public function getCache(string $path = '', ?IStorage $storage = null): ICache { $storage = $this; } - $this->cache = new RootEntryCache(parent::getCache($path, $storage), $this->rootEntry); + $cache = parent::getCache($path, $storage); + if ($this->rootEntry !== null) { + $cache = new RootEntryCache($cache, $this->rootEntry); + } + $this->cache = $cache; return $this->cache; } From 617eb295eaef845cec01a9da97afdc4db218e2ec Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Mon, 18 Nov 2024 14:43:56 +0100 Subject: [PATCH 5/9] fix: create a separate mount for trashbin to make encryption work Signed-off-by: Robin Appelman --- lib/Mount/MountProvider.php | 144 ++++++++++++++++++++++++----------- lib/Trash/GroupTrashItem.php | 12 --- lib/Trash/TrashBackend.php | 28 +++++-- 3 files changed, 121 insertions(+), 63 deletions(-) diff --git a/lib/Mount/MountProvider.php b/lib/Mount/MountProvider.php index c22eae6a2..d310df79a 100644 --- a/lib/Mount/MountProvider.php +++ b/lib/Mount/MountProvider.php @@ -37,16 +37,16 @@ class MountProvider implements IMountProvider { private ?int $rootStorageId = null; public function __construct( - private FolderManager $folderManager, - private \Closure $rootProvider, - private ACLManagerFactory $aclManagerFactory, - private IUserSession $userSession, - private IRequest $request, + private FolderManager $folderManager, + private \Closure $rootProvider, + private ACLManagerFactory $aclManagerFactory, + private IUserSession $userSession, + private IRequest $request, private IMountProviderCollection $mountProviderCollection, - private IDBConnection $connection, - private ICache $cache, - private bool $allowRootShare, - private bool $enableEncryption, + private IDBConnection $connection, + private ICache $cache, + private bool $allowRootShare, + private bool $enableEncryption, ) { } @@ -83,7 +83,7 @@ public function getMountsForUser(IUser $user, IStorageFactory $loader): array { $aclManager = $this->aclManagerFactory->getACLManager($user, $this->getRootStorageId()); $rootRules = $aclManager->getRelevantRulesForPath($aclRootPaths); - return array_values(array_filter(array_map(function (array $folder) use ($user, $loader, $conflicts, $aclManager, $rootRules): ?IMountPoint { + return array_merge(...array_filter(array_map(function (array $folder) use ($user, $loader, $conflicts, $aclManager, $rootRules): ?array { // check for existing files in the user home and rename them if needed $originalFolderName = $folder['mount_point']; if (in_array($originalFolderName, $conflicts)) { @@ -102,7 +102,7 @@ public function getMountsForUser(IUser $user, IStorageFactory $loader): array { $userStorage->getPropagator()->propagateChange("files/$folderName", time()); } - return $this->getMount( + $mount = $this->getMount( $folder['folder_id'], '/' . $user->getUID() . '/files/' . $folder['mount_point'], $folder['permissions'], @@ -114,6 +114,22 @@ public function getMountsForUser(IUser $user, IStorageFactory $loader): array { $aclManager, $rootRules ); + if (!$mount) { + return null; + } + $trashMount = $this->getTrashMount( + $folder['folder_id'], + '/' . $user->getUID() . '/files_trashbin/groupfolders/' . $folder['folder_id'], + $folder['quota'], + $loader, + $user + ); + + return [ + $mount, + $trashMount, + ]; + }, $folders))); } @@ -137,16 +153,16 @@ private function getCurrentUID(): ?string { } public function getMount( - int $id, - string $mountPoint, - int $permissions, - int $quota, - ?ICacheEntry $cacheEntry = null, + int $id, + string $mountPoint, + int $permissions, + int $quota, + ?ICacheEntry $cacheEntry = null, ?IStorageFactory $loader = null, - bool $acl = false, - ?IUser $user = null, - ?ACLManager $aclManager = null, - array $rootRules = [], + bool $acl = false, + ?IUser $user = null, + ?ACLManager $aclManager = null, + array $rootRules = [], ): ?IMountPoint { if (!$cacheEntry) { // trigger folder creation @@ -180,53 +196,91 @@ public function getMount( $cacheEntry['permissions'] &= $aclRootPermissions; } + $quotaStorage = $this->getGroupFolderStorage($id, $storage, $user, $rootPath, $quota, $cacheEntry); + + $maskedStore = new PermissionsMask([ + 'storage' => $quotaStorage, + 'mask' => $permissions, + ]); + + if (!$this->allowRootShare) { + $maskedStore = new RootPermissionsMask([ + 'storage' => $maskedStore, + 'mask' => Constants::PERMISSION_ALL - Constants::PERMISSION_SHARE, + ]); + } + + return new GroupMountPoint( + $id, + $maskedStore, + $mountPoint, + null, + $loader + ); + } + + public function getTrashMount( + int $id, + string $mountPoint, + int $quota, + IStorageFactory $loader, + IUser $user, + ): IMountPoint { + + $storage = $this->getRootFolder()->getStorage(); + + $storage->setOwner($user?->getUID()); + + $trashPath = $this->getRootFolder()->getInternalPath() . '/trash/' . $id; + + $trashStorage = $this->getGroupFolderStorage($id, $storage, $user, $trashPath, $quota, null); + + return new GroupMountPoint( + $id, + $trashStorage, + $mountPoint, + null, + $loader + ); + } + + public function getGroupFolderStorage( + int $id, + IStorage $rootStorage, + ?IUser $user, + string $rootPath, + int $quota, + ?ICacheEntry $rootCacheEntry, + ): IStorage { if ($this->enableEncryption) { $baseStorage = new GroupFolderEncryptionJail([ - 'storage' => $storage, - 'root' => $rootPath + 'storage' => $rootStorage, + 'root' => $rootPath, ]); $quotaStorage = new GroupFolderStorage([ 'storage' => $baseStorage, 'quota' => $quota, 'folder_id' => $id, - 'rootCacheEntry' => $cacheEntry, + 'rootCacheEntry' => $rootCacheEntry, 'userSession' => $this->userSession, 'mountOwner' => $user, ]); } else { $baseStorage = new Jail([ - 'storage' => $storage, - 'root' => $rootPath + 'storage' => $rootStorage, + 'root' => $rootPath, ]); $quotaStorage = new GroupFolderNoEncryptionStorage([ 'storage' => $baseStorage, 'quota' => $quota, 'folder_id' => $id, - 'rootCacheEntry' => $cacheEntry, + 'rootCacheEntry' => $rootCacheEntry, 'userSession' => $this->userSession, 'mountOwner' => $user, ]); } - $maskedStore = new PermissionsMask([ - 'storage' => $quotaStorage, - 'mask' => $permissions - ]); - - if (!$this->allowRootShare) { - $maskedStore = new RootPermissionsMask([ - 'storage' => $maskedStore, - 'mask' => Constants::PERMISSION_ALL - Constants::PERMISSION_SHARE, - ]); - } - - return new GroupMountPoint( - $id, - $maskedStore, - $mountPoint, - null, - $loader - ); + return $quotaStorage; } public function getJailPath(int $folderId): string { diff --git a/lib/Trash/GroupTrashItem.php b/lib/Trash/GroupTrashItem.php index 5930e451c..b23dd70ff 100644 --- a/lib/Trash/GroupTrashItem.php +++ b/lib/Trash/GroupTrashItem.php @@ -43,18 +43,6 @@ public function getTitle(): string { return $this->getGroupFolderMountPoint() . '/' . $this->getOriginalLocation(); } - public function getStorage(): IStorage { - // get the unjailed storage, since the trash item is outside the jail - // (the internal path is also unjailed) - $groupFolderStorage = parent::getStorage(); - if ($groupFolderStorage->instanceOfStorage(Jail::class)) { - /** @var Jail $groupFolderStorage */ - return $groupFolderStorage->getUnjailedStorage(); - } - - return $groupFolderStorage; - } - public function getMtime(): int { // trashbin is currently (incorrectly) assuming these to be the same return $this->getDeletedTime(); diff --git a/lib/Trash/TrashBackend.php b/lib/Trash/TrashBackend.php index 2fd1d8706..477b39eda 100644 --- a/lib/Trash/TrashBackend.php +++ b/lib/Trash/TrashBackend.php @@ -76,7 +76,7 @@ public function listTrashFolder(ITrashItem $folder): array { $this->aclManagerFactory->getACLManager($user)->preloadRulesForFolder($folder->getPath()); return array_values(array_filter(array_map(function (Node $node) use ($folder, $user): ?GroupTrashItem { - if (!$this->userHasAccessToPath($user, $folder->getPath() . '/' . $node->getName())) { + if (!$this->userHasAccessToPath($user, $this->getUnJailedPath($node))) { return null; } @@ -289,10 +289,11 @@ private function userHasAccessToPath( private function getNodeForTrashItem(IUser $user, ITrashItem $trashItem): ?Node { [, $folderId, $path] = explode('/', $trashItem->getTrashPath(), 3); + $folderId = (int)$folderId; $folders = $this->folderManager->getFoldersForUser($user); foreach ($folders as $groupFolder) { - if ($groupFolder['folder_id'] === (int)$folderId) { - $trashRoot = $this->getTrashFolder((int)$folderId); + if ($groupFolder['folder_id'] === $folderId) { + $trashRoot = $this->rootFolder->get('/' . $user->getUID() . '/files_trashbin/groupfolders/' . $folderId); try { $node = $trashRoot->get($path); if (!$this->userHasAccessToPath($user, $trashItem->getPath())) { @@ -334,6 +335,17 @@ private function getTrashFolder(int $folderId): Folder { } } + private function getUnJailedPath(Node $node): string { + $storage = $node->getStorage(); + $path = $node->getInternalPath(); + while ($storage->instanceOfStorage(Jail::class)) { + /** @var Jail $storage */ + $path = $storage->getUnjailedPath($path); + $storage = $storage->getUnjailedStorage(); + } + return $path; + } + /** * @param list $folders * @return list @@ -354,10 +366,14 @@ private function getTrashForFolders(IUser $user, array $folders): array { $folderId = $folder['folder_id']; $folderHasAcl = $folder['acl']; $mountPoint = $folder['mount_point']; - $trashFolder = $this->getTrashFolder($folderId); + + // ensure the trash folder exists + $this->getTrashFolder($folderId); + + $trashFolder = $this->rootFolder->get('/' . $user->getUID() . '/files_trashbin/groupfolders/' . $folderId); $content = $trashFolder->getDirectoryListing(); $userCanManageAcl = $this->folderManager->canManageACL($folderId, $user); - $this->aclManagerFactory->getACLManager($user)->preloadRulesForFolder($trashFolder->getPath()); + $this->aclManagerFactory->getACLManager($user)->preloadRulesForFolder($this->getUnJailedPath($trashFolder)); foreach ($content as $item) { /** @var \OC\Files\Node\Node $item */ $pathParts = pathinfo($item->getName()); @@ -374,7 +390,7 @@ private function getTrashForFolders(IUser $user, array $folders): array { continue; } - if (!$this->userHasAccessToPath($user, $item->getPath())) { + if (!$this->userHasAccessToPath($user, $this->getUnJailedPath($item))) { continue; } From cca334aa6ce5acb01856bc9485116de1b3c74067 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Mon, 18 Nov 2024 14:44:07 +0100 Subject: [PATCH 6/9] fix: fix moving files to trash Signed-off-by: Robin Appelman --- lib/Trash/TrashBackend.php | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/lib/Trash/TrashBackend.php b/lib/Trash/TrashBackend.php index 477b39eda..03ef04c43 100644 --- a/lib/Trash/TrashBackend.php +++ b/lib/Trash/TrashBackend.php @@ -8,6 +8,7 @@ use OC\Files\Storage\Wrapper\Encryption; use OCA\Files_Trashbin\Expiration; +use OCA\Files_Trashbin\Storage; use OCA\Files_Trashbin\Trash\ITrashBackend; use OCA\Files_Trashbin\Trash\ITrashItem; use OCA\GroupFolders\ACL\ACLManagerFactory; @@ -211,7 +212,14 @@ public function moveToTrash(IStorage $storage, string $internalPath): bool { $name = basename($internalPath); $fileEntry = $storage->getCache()->get($internalPath); $folderId = $storage->getFolderId(); - $trashFolder = $this->getTrashFolder($folderId); + $user = $this->userSession->getUser(); + if (!$user) { + throw new \Exception("file moved to trash with no user in context"); + } + // ensure the folder exists + $this->getTrashFolder($folderId); + + $trashFolder = $this->rootFolder->get('/' . $user->getUID() . '/files_trashbin/groupfolders/' . $folderId); $trashStorage = $trashFolder->getStorage(); $time = time(); $trashName = $name . '.d' . $time; @@ -223,9 +231,16 @@ public function moveToTrash(IStorage $storage, string $internalPath): bool { $result = $trashStorage->moveFromStorage($storage, $internalPath, $targetInternalPath); } if ($result) { - $this->trashManager->addTrashItem($folderId, $name, $time, $internalPath, $fileEntry->getId(), $this->userSession->getUser()->getUID()); - if ($trashStorage->getCache()->getId($targetInternalPath) !== $fileEntry->getId()) { + $this->trashManager->addTrashItem($folderId, $name, $time, $internalPath, $fileEntry->getId(), $user->getUID()); + + // some storage backends (object/encryption) can either already move the cache item or cause the target to be scanned + // so we only conditionally do the cache move here + if (!$trashStorage->getCache()->inCache($targetInternalPath)) { + // doesn't exist in target yet, do the move $trashStorage->getCache()->moveFromCache($storage->getCache(), $internalPath, $targetInternalPath); + } elseif ($storage->getCache()->inCache($internalPath)) { + // exists in both source and target, cleanup source + $storage->getCache()->remove($internalPath); } } else { throw new \Exception('Failed to move groupfolder item to trash'); @@ -247,6 +262,11 @@ private function moveFromEncryptedStorage(IStorage $sourceStorage, IStorage $tar return false; } + // the trash should be the top wrapper, remove it to prevent recursive attempts to move to trash + if ($sourceStorage instanceof Storage) { + $sourceStorage = $sourceStorage->getWrapperStorage(); + } + $result = $targetStorage->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath, true); if ($result) { if ($sourceStorage->instanceOfStorage(ObjectStoreStorage::class)) { From 6b15dd453aac1904d5902f1afc3d21329a553150 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 27 Nov 2024 18:59:39 +0100 Subject: [PATCH 7/9] fix: add fallback behavior for pre-fix trashbin restore Signed-off-by: Robin Appelman --- lib/Trash/TrashBackend.php | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/lib/Trash/TrashBackend.php b/lib/Trash/TrashBackend.php index 03ef04c43..41e234186 100644 --- a/lib/Trash/TrashBackend.php +++ b/lib/Trash/TrashBackend.php @@ -6,7 +6,9 @@ namespace OCA\GroupFolders\Trash; +use OC\Encryption\Exceptions\DecryptionFailedException; use OC\Files\Storage\Wrapper\Encryption; +use OC\Files\Storage\Wrapper\Jail; use OCA\Files_Trashbin\Expiration; use OCA\Files_Trashbin\Storage; use OCA\Files_Trashbin\Trash\ITrashBackend; @@ -159,8 +161,19 @@ public function restoreItem(ITrashItem $item): void { } $targetLocation = $targetFolder->getInternalPath() . '/' . $originalLocation; - $targetFolder->getStorage()->moveFromStorage($trashStorage, $node->getInternalPath(), $targetLocation); - $targetFolder->getStorage()->getUpdater()->renameFromStorage($trashStorage, $node->getInternalPath(), $targetLocation); + $targetStorage = $targetFolder->getStorage(); + $trashLocation = $node->getInternalPath(); + try { + $targetStorage->moveFromStorage($trashStorage, $trashLocation, $targetLocation); + $targetStorage->getUpdater()->renameFromStorage($trashStorage, $trashLocation, $targetLocation); + } catch (DecryptionFailedException $e) { + // Before https://github.com/nextcloud/groupfolders/pull/3425 the key would be in the wrong place, leading to the decryption failure. + // for those we fall back to the old restore behavior + [$unwrappedTargetStorage, $unwrappedTargetLocation] = $this->unwrapJails($targetStorage, $targetLocation); + [$unwrappedTrashStorage, $unwrappedTrashLocation] = $this->unwrapJails($trashStorage, $trashLocation); + $unwrappedTargetStorage->moveFromStorage($unwrappedTrashStorage, $unwrappedTrashLocation, $unwrappedTargetLocation); + $unwrappedTargetStorage->getUpdater()->renameFromStorage($unwrappedTrashStorage, $unwrappedTrashLocation, $unwrappedTargetLocation); + } $this->trashManager->removeItem((int)$folderId, $item->getName(), $item->getDeletedTime()); \OCP\Util::emitHook( '\OCA\Files_Trashbin\Trashbin', @@ -172,6 +185,18 @@ public function restoreItem(ITrashItem $item): void { ); } + private function unwrapJails(IStorage $storage, string $internalPath): array { + $unJailedInternalPath = $internalPath; + $unJailedStorage = $storage; + while ($unJailedStorage->instanceOfStorage(Jail::class)) { + $unJailedStorage = $unJailedStorage->getWrapperStorage(); + if ($unJailedStorage instanceof Jail) { + $unJailedInternalPath = $unJailedStorage->getUnjailedPath($unJailedInternalPath); + } + } + return [$unJailedStorage, $unJailedInternalPath]; + } + /** * @throws \LogicException * @throws \Exception From 98c45aa9a4429ff5280bc996bd47853475a816d4 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Thu, 28 Nov 2024 14:59:26 +0100 Subject: [PATCH 8/9] chore: formatting Signed-off-by: Robin Appelman --- lib/Mount/MountProvider.php | 54 ++++++++++++++++++------------------ lib/Trash/GroupTrashItem.php | 2 -- lib/Trash/TrashBackend.php | 2 +- 3 files changed, 28 insertions(+), 30 deletions(-) diff --git a/lib/Mount/MountProvider.php b/lib/Mount/MountProvider.php index d310df79a..66e6ef7f3 100644 --- a/lib/Mount/MountProvider.php +++ b/lib/Mount/MountProvider.php @@ -37,16 +37,16 @@ class MountProvider implements IMountProvider { private ?int $rootStorageId = null; public function __construct( - private FolderManager $folderManager, - private \Closure $rootProvider, - private ACLManagerFactory $aclManagerFactory, - private IUserSession $userSession, - private IRequest $request, + private FolderManager $folderManager, + private \Closure $rootProvider, + private ACLManagerFactory $aclManagerFactory, + private IUserSession $userSession, + private IRequest $request, private IMountProviderCollection $mountProviderCollection, - private IDBConnection $connection, - private ICache $cache, - private bool $allowRootShare, - private bool $enableEncryption, + private IDBConnection $connection, + private ICache $cache, + private bool $allowRootShare, + private bool $enableEncryption, ) { } @@ -153,16 +153,16 @@ private function getCurrentUID(): ?string { } public function getMount( - int $id, - string $mountPoint, - int $permissions, - int $quota, - ?ICacheEntry $cacheEntry = null, + int $id, + string $mountPoint, + int $permissions, + int $quota, + ?ICacheEntry $cacheEntry = null, ?IStorageFactory $loader = null, - bool $acl = false, - ?IUser $user = null, - ?ACLManager $aclManager = null, - array $rootRules = [], + bool $acl = false, + ?IUser $user = null, + ?ACLManager $aclManager = null, + array $rootRules = [], ): ?IMountPoint { if (!$cacheEntry) { // trigger folder creation @@ -220,11 +220,11 @@ public function getMount( } public function getTrashMount( - int $id, - string $mountPoint, - int $quota, + int $id, + string $mountPoint, + int $quota, IStorageFactory $loader, - IUser $user, + IUser $user, ): IMountPoint { $storage = $this->getRootFolder()->getStorage(); @@ -245,11 +245,11 @@ public function getTrashMount( } public function getGroupFolderStorage( - int $id, - IStorage $rootStorage, - ?IUser $user, - string $rootPath, - int $quota, + int $id, + IStorage $rootStorage, + ?IUser $user, + string $rootPath, + int $quota, ?ICacheEntry $rootCacheEntry, ): IStorage { if ($this->enableEncryption) { diff --git a/lib/Trash/GroupTrashItem.php b/lib/Trash/GroupTrashItem.php index b23dd70ff..c3f8f9911 100644 --- a/lib/Trash/GroupTrashItem.php +++ b/lib/Trash/GroupTrashItem.php @@ -6,11 +6,9 @@ namespace OCA\GroupFolders\Trash; -use OC\Files\Storage\Wrapper\Jail; use OCA\Files_Trashbin\Trash\ITrashBackend; use OCA\Files_Trashbin\Trash\TrashItem; use OCP\Files\FileInfo; -use OCP\Files\Storage\IStorage; use OCP\IUser; class GroupTrashItem extends TrashItem { diff --git a/lib/Trash/TrashBackend.php b/lib/Trash/TrashBackend.php index 41e234186..9063f7c83 100644 --- a/lib/Trash/TrashBackend.php +++ b/lib/Trash/TrashBackend.php @@ -239,7 +239,7 @@ public function moveToTrash(IStorage $storage, string $internalPath): bool { $folderId = $storage->getFolderId(); $user = $this->userSession->getUser(); if (!$user) { - throw new \Exception("file moved to trash with no user in context"); + throw new \Exception('file moved to trash with no user in context'); } // ensure the folder exists $this->getTrashFolder($folderId); From 630caec0fb666374b8d7f55905634954f14b2f16 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Thu, 28 Nov 2024 15:05:06 +0100 Subject: [PATCH 9/9] chore: psalm fixes Signed-off-by: Robin Appelman --- lib/Mount/GroupFolderStorage.php | 2 +- lib/Mount/MountProvider.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Mount/GroupFolderStorage.php b/lib/Mount/GroupFolderStorage.php index 83a8b7cb5..b9923138e 100644 --- a/lib/Mount/GroupFolderStorage.php +++ b/lib/Mount/GroupFolderStorage.php @@ -23,7 +23,7 @@ class GroupFolderStorage extends Quota implements IConstructableStorage { private ?ICacheEntry $rootEntry; private IUserSession $userSession; private ?IUser $mountOwner; - /** @var RootEntryCache|null */ + /** @var ICache|null */ public $cache; public function __construct($parameters) { diff --git a/lib/Mount/MountProvider.php b/lib/Mount/MountProvider.php index 66e6ef7f3..f5bc74acb 100644 --- a/lib/Mount/MountProvider.php +++ b/lib/Mount/MountProvider.php @@ -229,7 +229,7 @@ public function getTrashMount( $storage = $this->getRootFolder()->getStorage(); - $storage->setOwner($user?->getUID()); + $storage->setOwner($user->getUID()); $trashPath = $this->getRootFolder()->getInternalPath() . '/trash/' . $id;