diff --git a/apps/files_trashbin/lib/Sabre/TrashbinPlugin.php b/apps/files_trashbin/lib/Sabre/TrashbinPlugin.php
index 9afa5092e0914..1c6f258fca42e 100644
--- a/apps/files_trashbin/lib/Sabre/TrashbinPlugin.php
+++ b/apps/files_trashbin/lib/Sabre/TrashbinPlugin.php
@@ -12,6 +12,8 @@
use OC\Files\View;
use OCA\DAV\Connector\Sabre\FilesPlugin;
use OCA\Files_Trashbin\Trash\ITrashItem;
+use OCP\Files\IRootFolder;
+use OCP\Files\Mount\IMountManager;
use OCP\IPreview;
use Psr\Log\LoggerInterface;
use Sabre\DAV\INode;
@@ -42,7 +44,8 @@ class TrashbinPlugin extends ServerPlugin {
public function __construct(
private readonly IPreview $previewManager,
- private readonly View $view,
+ private readonly IRootFolder $rootFolder,
+ private readonly IMountManager $mountManager,
) {
}
@@ -174,7 +177,16 @@ public function beforeMove(string $sourcePath, string $destinationPath): bool {
return true;
}
- $freeSpace = $this->view->free_space($destinationParentPath);
+ $userFolder = $this->rootFolder->getUserFolder($fileInfo->getUser()->getUID());
+ $originalPath = $userFolder->getFullPath(dirname($fileInfo->getOriginalLocation()));
+
+ // Since the parent folder might no longer exist, we don't try to get the parent node to check the free space
+ // instead we resolve the mount where the restore would go to, and check that for the free space
+ $originalMount = $this->mountManager->find($originalPath);
+ if (!$originalMount) {
+ throw new \Exception('no mount found when looking for restore path');
+ }
+ $freeSpace = $originalMount->getStorage()->free_space($originalMount->getInternalPath($originalPath));
if (
$freeSpace === FileInfo::SPACE_NOT_COMPUTED
diff --git a/apps/files_trashbin/lib/Trashbin.php b/apps/files_trashbin/lib/Trashbin.php
index 5402cc7045b12..533da2dcbf53a 100644
--- a/apps/files_trashbin/lib/Trashbin.php
+++ b/apps/files_trashbin/lib/Trashbin.php
@@ -34,6 +34,7 @@
use OCP\Files\IMimeTypeLoader;
use OCP\Files\IRootFolder;
use OCP\Files\Node;
+use OCP\Files\NotEnoughSpaceException;
use OCP\Files\NotFoundException;
use OCP\Files\NotPermittedException;
use OCP\Files\Storage\ILockingStorage;
@@ -564,6 +565,14 @@ public static function restore($file, $filename, $timestamp) {
$sourceNode = self::getNodeForPath($user, $sourcePath);
$targetNode = self::getNodeForPath($user, $targetPath, 'files');
+
+ $targetParent = $targetNode->getParent();
+
+ $free = $targetParent->getFreeSpace();
+ if ($free >= 0 && $free < $sourceNode->getSize(false)) {
+ throw new NotEnoughSpaceException('Not enough free space in ' . $targetParent->getPath() . ' to restore ' . $sourceNode->getPath());
+ }
+
$run = true;
$event = new BeforeNodeRestoredEvent($sourceNode, $targetNode, $run);
$dispatcher = Server::get(IEventDispatcher::class);
diff --git a/apps/files_trashbin/tests/Sabre/TrashbinPluginTest.php b/apps/files_trashbin/tests/Sabre/TrashbinPluginTest.php
index 5feda386350d0..001e3bcb5ba1d 100644
--- a/apps/files_trashbin/tests/Sabre/TrashbinPluginTest.php
+++ b/apps/files_trashbin/tests/Sabre/TrashbinPluginTest.php
@@ -9,12 +9,17 @@
namespace OCA\Files_Trashbin\Tests\Sabre;
use OC\Files\FileInfo;
-use OC\Files\View;
use OCA\Files_Trashbin\Sabre\ITrash;
use OCA\Files_Trashbin\Sabre\RestoreFolder;
use OCA\Files_Trashbin\Sabre\TrashbinPlugin;
use OCA\Files_Trashbin\Trash\ITrashItem;
+use OCP\Files\Folder;
+use OCP\Files\IRootFolder;
+use OCP\Files\Mount\IMountManager;
+use OCP\Files\Mount\IMountPoint;
+use OCP\Files\Storage\IStorage;
use OCP\IPreview;
+use OCP\IUser;
use Sabre\DAV\Server;
use Sabre\DAV\Tree;
use Test\TestCase;
@@ -34,6 +39,13 @@ public function testQuota(int $quota, int $fileSize, bool $expectedResult): void
$fileInfo = $this->createMock(ITrashItem::class);
$fileInfo->method('getSize')
->willReturn($fileSize);
+ $user = $this->createMock(IUser::class);
+ $user->method('getUID')
+ ->willReturn('test');
+ $fileInfo->method('getUser')
+ ->willReturn($user);
+ $fileInfo->method('getOriginalLocation')
+ ->willReturn('relative/original/location');
$trashNode = $this->createMock(ITrash::class);
$trashNode->method('getFileInfo')
@@ -46,11 +58,30 @@ public function testQuota(int $quota, int $fileSize, bool $expectedResult): void
$previewManager = $this->createMock(IPreview::class);
- $view = $this->createMock(View::class);
- $view->method('free_space')
+ $userFolder = $this->createMock(Folder::class);
+ $userFolder->method('getFullPath')
+ ->with('relative/original') // the parent path
+ ->willReturn('/full/path/to/original');
+ $rootFolder = $this->createMock(IRootFolder::class);
+ $rootFolder->method('getUserFolder')
+ ->willReturn($userFolder);
+
+ $storage = $this->createMock(IStorage::class);
+ $storage->method('free_space')
+ ->with('path/to/original')
->willReturn($quota);
+ $mount = $this->createMock(IMountPoint::class);
+ $mount->method('getStorage')
+ ->willReturn($storage);
+ $mount->method('getInternalPath')
+ ->with('/full/path/to/original')
+ ->willReturn('path/to/original');
+ $mountManager = $this->createMock(IMountManager::class);
+ $mountManager->method('find')
+ ->with('/full/path/to/original')
+ ->willReturn($mount);
- $plugin = new TrashbinPlugin($previewManager, $view);
+ $plugin = new TrashbinPlugin($previewManager, $rootFolder, $mountManager);
$plugin->initialize($this->server);
$sourcePath = 'trashbin/test/trash/file1';
@@ -60,11 +91,11 @@ public function testQuota(int $quota, int $fileSize, bool $expectedResult): void
public static function quotaProvider(): array {
return [
- [ 1024 * 1024, 512 * 1024, true ],
- [ 512 * 1024, 513 * 1024, false ],
- [ FileInfo::SPACE_NOT_COMPUTED, 1024 * 1024, true ],
- [ FileInfo::SPACE_UNKNOWN, 1024 * 1024, true ],
- [ FileInfo::SPACE_UNLIMITED, 1024 * 1024, true ]
+ [1024 * 1024, 512 * 1024, true],
+ [512 * 1024, 513 * 1024, false],
+ [FileInfo::SPACE_NOT_COMPUTED, 1024 * 1024, true],
+ [FileInfo::SPACE_UNKNOWN, 1024 * 1024, true],
+ [FileInfo::SPACE_UNLIMITED, 1024 * 1024, true]
];
}
}
diff --git a/build/psalm-baseline.xml b/build/psalm-baseline.xml
index 4663e682ff9ad..f1a87cb845b8f 100644
--- a/build/psalm-baseline.xml
+++ b/build/psalm-baseline.xml
@@ -1829,11 +1829,6 @@
-
-
-
-
-